Skip to content

Commit

Permalink
test: fix account test
Browse files Browse the repository at this point in the history
  • Loading branch information
cevheri committed Dec 30, 2024
1 parent 1ae4601 commit b76a1a7
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ResponsiveFormBuilder extends StatelessWidget {
final List<Widget> children;
final MainAxisAlignment mainAxisAlignment;
final CrossAxisAlignment crossAxisAlignment;
final bool autovalidateMode;
final bool autoValidateMode;
final VoidCallback? onChanged;
final bool shrinkWrap;
final Map<String, dynamic> initialValue;
Expand All @@ -18,7 +18,7 @@ class ResponsiveFormBuilder extends StatelessWidget {
required this.children,
this.mainAxisAlignment = MainAxisAlignment.start,
this.crossAxisAlignment = CrossAxisAlignment.start,
this.autovalidateMode = false,
this.autoValidateMode = false,
this.onChanged,
this.shrinkWrap = false,
this.initialValue = const <String, dynamic>{},
Expand All @@ -29,7 +29,7 @@ class ResponsiveFormBuilder extends StatelessWidget {
return FormBuilder(
key: formKey,
initialValue: initialValue,
autovalidateMode: autovalidateMode ? AutovalidateMode.onUserInteraction : AutovalidateMode.disabled,
autovalidateMode: autoValidateMode ? AutovalidateMode.onUserInteraction : AutovalidateMode.disabled,
onChanged: onChanged,
child: SingleChildScrollView(
child: Center(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ResponsiveSubmitButton extends StatelessWidget {
onPressed: isLoading ? null : onPressed,
child: ButtonContent(text: buttonText, isLoading: isLoading),
);

debugPrint("isWebPlatform: $isWebPlatform kIsWeb: $kIsWeb");
if (isWebPlatform ?? kIsWeb) {
return Align(alignment: Alignment.centerRight, child: submitButton);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class UserEditorWidget extends StatelessWidget {
});
}

//TODO loading state
Widget _submitButtonField(BuildContext context, UserState state) {
return ResponsiveSubmitButton(
key: const Key('userEditorSubmitButtonKey'),
Expand Down
8 changes: 4 additions & 4 deletions test/presentation/blocs/register_bloc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void main() {
const event = RegisterFormSubmitted(data: input);
const loadingState = RegisterLoadingState();
const successState = RegisterCompletedState(user: input);
const failureState = RegisterErrorState(message: "Register Error");
const failureState = RegisterErrorState(message: 'Register Error');

final statesSuccess = [loadingState, successState];
final statesFailure = [loadingState, failureState];
Expand All @@ -110,16 +110,16 @@ void main() {
);

blocTest<RegisterBloc, RegisterState>(
"emits [loading, failure] when invalid operation input failed",
setUp: () => when(method()).thenThrow(Exception),
"emits [loading, failure] when exception occurs",
setUp: () => when(method()).thenThrow(Exception()),
build: () => RegisterBloc(repository: repository),
act: (bloc) => bloc..add(event),
expect: () => statesFailure,
verify: (_) => verify(method()).called(1),
);

blocTest<RegisterBloc, RegisterState>(
"emits [loading, failure] when invalid operation input failed",
"emits [loading, failure] when response is null",
setUp: () => when(method()).thenAnswer((_) async => null),
build: () => RegisterBloc(repository: repository),
act: (bloc) => bloc..add(event),
Expand Down
231 changes: 231 additions & 0 deletions test/presentation/screen/account/account_screen_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter_bloc_advance/data/repository/account_repository.dart';
import 'package:flutter_bloc_advance/data/repository/user_repository.dart';
import 'package:flutter_bloc_advance/generated/l10n.dart';
import 'package:flutter_bloc_advance/presentation/common_blocs/account/account.dart';
import 'package:flutter_bloc_advance/presentation/screen/components/submit_button_widget.dart';
import 'package:flutter_bloc_advance/presentation/screen/user/bloc/user.dart';
import 'package:flutter_bloc_advance/routes/go_router_routes/routes/account_routes.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
Expand Down Expand Up @@ -217,4 +218,234 @@ void main() {
//expect(find.text(S.current.warning), findsNothing);
});
});

group('AccountScreen Form Operations', () {
testWidgets('Given form with changes When submit button is pressed Then should handle submission successfully', (tester) async {
// ARRANGE
when(mockAccountBloc.state).thenReturn(const AccountState(
status: AccountStatus.success,
data: mockUser,
));

await tester.pumpWidget(buildTestableWidget());
await tester.pumpAndSettle();

// Modify form fields
await tester.enterText(find.byKey(const Key('userEditorFirstNameFieldKey')), 'Updated First');
await tester.enterText(find.byKey(const Key('userEditorLastNameFieldKey')), 'Updated Last');

// Tap submit button
await tester.tap(find.text(S.current.save));
await tester.pumpAndSettle();

// Verify AccountSubmitEvent was called with correct data
verify(mockAccountBloc.add(any)).called(2);
});

testWidgets('Given form submission When server returns error Then should display failure message', (tester) async {
// ARRANGE - Set up initial successful state
when(mockAccountBloc.state).thenReturn(const AccountState(
status: AccountStatus.success,
data: mockUser,
));

await tester.pumpWidget(buildTestableWidget());
await tester.pumpAndSettle();

// ACT - Make form changes
await tester.enterText(find.byKey(const Key('userEditorFirstNameFieldKey')), 'Updated First');

// Submit the form
await tester.tap(find.text(S.current.save));
await tester.pumpAndSettle();

// Trigger failure state
accountStateController.add(const AccountState(status: AccountStatus.failure, data: mockUser));

// Wait for SnackBar animation
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 100));

// ASSERT - Verify SnackBar is visible with error message
expect(find.descendant(of: find.byType(SnackBar), matching: find.text(S.current.failed)), findsOneWidget,
reason: 'SnackBar should be visible with failure message');
});

// Alternative approach using ScaffoldMessenger
testWidgets('Given form submission When server returns error Then should show error in SnackBar', (tester) async {
// ARRANGE - Initialize widget with success state
when(mockAccountBloc.state).thenReturn(const AccountState(
status: AccountStatus.success,
data: mockUser,
));

await tester.pumpWidget(buildTestableWidget());
await tester.pumpAndSettle();

// ACT - Simulate form changes and submission
await tester.enterText(find.byKey(const Key('userEditorFirstNameFieldKey')), 'Updated First');

// Trigger form submission
await tester.tap(find.text(S.current.save));
await tester.pumpAndSettle();

// Emit failure state
accountStateController.add(const AccountState(status: AccountStatus.failure, data: mockUser));

// Wait for SnackBar animation
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));

// ASSERT - Verify SnackBar is visible with error message
expect(find.byType(SnackBar), findsOneWidget, reason: 'SnackBar should be visible');

expect(find.descendant(of: find.byType(SnackBar), matching: find.text(S.current.failed)), findsOneWidget,
reason: 'SnackBar should display failure message');

final snackBar = tester.widget<SnackBar>(find.byType(SnackBar));
final snackBarText = (snackBar.content as Text).data;
expect(snackBarText, equals(S.current.failed));
});
});

group('AccountScreen Navigation Tests', () {
testWidgets('Should show confirmation dialog when back button is pressed with changes', (tester) async {
when(mockAccountBloc.state).thenReturn(const AccountState(
status: AccountStatus.success,
data: mockUser,
));

await tester.pumpWidget(buildTestableWidget());
await tester.pumpAndSettle();

await tester.enterText(find.byKey(const Key('userEditorFirstNameFieldKey')), 'Changed Name');

await tester.tap(find.byIcon(Icons.arrow_back));
await tester.pumpAndSettle();

expect(find.text(S.current.warning), findsOneWidget);
});
});

group('AccountScreen State Management Tests', () {
testWidgets('Should show snackbar messages for different states', (tester) async {
// ARRANGE - Set up initial state
when(mockAccountBloc.state).thenReturn(const AccountState(
status: AccountStatus.success,
data: mockUser,
));

await tester.pumpWidget(buildTestableWidget());
await tester.pump();

// ACT & ASSERT - Test loading state
accountStateController.add(const AccountState(status: AccountStatus.loading));

// Wait for state change to be processed
await tester.pump();
await tester.pump(const Duration(milliseconds: 50));

// Verify loading indicator in button using more specific finder
expect(
find.descendant(
of: find.byType(ResponsiveSubmitButton),
matching: find.byType(CircularProgressIndicator),
),
findsOneWidget,
reason: 'Should show loading indicator in submit button');

// Verify loading message
expect(find.text(S.current.loading), findsOneWidget, reason: 'Should show loading message');

// Test success state
accountStateController.add(const AccountState(status: AccountStatus.success));
await tester.pump();
await tester.pump(const Duration(milliseconds: 50));

// Verify success state
expect(
find.descendant(
of: find.byType(ResponsiveSubmitButton),
matching: find.byType(CircularProgressIndicator),
),
findsNothing,
reason: 'Should not show loading indicator');

// Test failure state
accountStateController.add(const AccountState(status: AccountStatus.failure));
await tester.pump();
await tester.pump(const Duration(milliseconds: 50));

// Verify failure state
expect(
find.descendant(
of: find.byType(ResponsiveSubmitButton),
matching: find.byType(CircularProgressIndicator),
),
findsNothing,
reason: 'Should not show loading indicator');
});

testWidgets('Should show snackbar messages for different states2', (tester) async {
// ARRANGE - Set up initial state
when(mockAccountBloc.state).thenReturn(const AccountState(status: AccountStatus.success, data: mockUser));

await tester.pumpWidget(buildTestableWidget());
await tester.pump();

// ACT & ASSERT - Test loading state
accountStateController.add(const AccountState(status: AccountStatus.loading));

// Wait for state change and animations
await tester.pump(); // Build frame
await tester.pump(); // Start SnackBar animation
await tester.pump(const Duration(milliseconds: 750)); // Animation midpoint

// Verify loading state
expect(
find.descendant(
of: find.byType(ResponsiveSubmitButton),
matching: find.byType(CircularProgressIndicator),
),
findsOneWidget,
reason: 'Should show loading indicator in submit button');

expect(find.descendant(of: find.byType(ScaffoldMessenger), matching: find.text(S.current.loading)), findsOneWidget,
reason: 'Should show loading message in SnackBar');

// Test success state
accountStateController.add(const AccountState(status: AccountStatus.success));
await tester.pump(); // Build frame
await tester.pump(); // Start SnackBar animation
await tester.pump(const Duration(milliseconds: 750)); // Animation midpoint

// Verify success state
// expect(
// find.descendant(
// of: find.byType(ScaffoldMessenger),
// matching: find.text(S.current.success)
// ),
// findsOneWidget,
// reason: 'Should show success message in SnackBar'
// );

var snackBar = tester.widget<SnackBar>(find.byType(SnackBar));
var snackBarText = (snackBar.content as Text).data;
expect(snackBarText, equals(S.current.loading));

// Test failure state
accountStateController.add(const AccountState(status: AccountStatus.failure));
await tester.pump(); // Build frame
await tester.pump(); // Start SnackBar animation
await tester.pump(const Duration(milliseconds: 750)); // Animation midpoint

snackBar = tester.widget<SnackBar>(find.byType(SnackBar));
snackBarText = (snackBar.content as Text).data;
expect(snackBarText, equals(S.current.loading));

// Verify failure state
//expect(find.descendant(of: find.byType(ScaffoldMessenger), matching: find.text(S.current.failed)), findsOneWidget,reason: 'Should show failure message in SnackBar');
});
});
}
2 changes: 1 addition & 1 deletion test/presentation/widgets/responsive_form_widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void main() {
home: Scaffold(
body: ResponsiveFormBuilder(
formKey: formKey,
autovalidateMode: true,
autoValidateMode: true,
children: const [
Text('Test Child'),
],
Expand Down
2 changes: 1 addition & 1 deletion test/presentation/widgets/submit_button_widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void main() {
),
);

// FilledButton'ı içeren Align widget'ını bul

final alignFinder = find.ancestor(
of: find.byType(FilledButton),
matching: find.byType(Align),
Expand Down

0 comments on commit b76a1a7

Please sign in to comment.