### Mocktail Setup and Basic Mocking in Flutter Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mocktail/packages/mocktail/test/mockito_compat/generated_mocks_test.md Provides a foundational example of setting up Mocktail in Flutter, including creating mock classes, initializing them in setUp, and performing basic stubbing for methods and getters. ```dart import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; class Foo { String positionalParameter(int x) => 'Real'; String get getter => 'Real'; set setter(int value) {} } class MockFoo extends Mock implements Foo {} void main() { group('for a generated mock,', () { late MockFoo foo; setUp(() { foo = MockFoo(); }); test('a method with a positional parameter can be stubbed', () { when(() => foo.positionalParameter(42)).thenReturn('Stubbed'); expect(foo.positionalParameter(42), equals('Stubbed')); }); test('a getter can be stubbed', () { when(() => foo.getter).thenReturn('Stubbed'); expect(foo.getter, equals('Stubbed')); }); test('a setter can be called without stubbing', () { expect(() => foo.setter = 7, returnsNormally); }); }); } ``` -------------------------------- ### Flutter Test Setup and Mocking Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/test/how_to_play/view/how_to_play_page_test.md This snippet demonstrates the initial setup for Flutter widget tests, including initializing Flame's image cache and registering fallback values for mocks. It also shows how to mock Cubits and Blocs using the mockingjay package for dependency injection during tests. ```dart // ignore_for_file: prefer_const_constructors import 'package:authentication_repository/authentication_repository.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flame/cache.dart'; import 'package:flame/flame.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:game_domain/game_domain.dart'; import 'package:io_crossword/crossword/crossword.dart'; import 'package:io_crossword/how_to_play/how_to_play.dart'; import 'package:io_crossword/l10n/l10n.dart'; import 'package:io_crossword/player/player.dart'; import 'package:io_crossword/team_selection/team_selection.dart' hide AssetsLoadingStatus; import 'package:io_crossword_ui/io_crossword_ui.dart'; import 'package:mockingjay/mockingjay.dart'; import '../../helpers/helpers.dart'; class _MockHowToPlayCubit extends MockCubit implements HowToPlayCubit {} class _MockPlayerBloc extends MockBloc implements PlayerBloc {} class _MockRoute extends Mock implements Route {} void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() async { Flame.images = Images(prefix: ''); await Flame.images.loadAll([ ...Mascot.dash.teamMascot.loadableHowToPlayDesktopAssets(), ...Mascot.dash.teamMascot.loadableHowToPlayMobileAssets(), ]); registerFallbackValue(Mascot.dash); }); group('$HowToPlayPage', () { late PlayerBloc playerBloc; setUp(() { playerBloc = _MockPlayerBloc(); }); testWidgets('route builds a $HowToPlayPage', (tester) async { when(() => playerBloc.state).thenReturn(PlayerState()); await tester.pumpRoute( playerBloc: playerBloc, HowToPlayPage.route(), ); await tester.pump(); expect(find.byType(HowToPlayPage), findsOneWidget); }); group('canPop', () { for (final status in PlayerStatus.values.toSet() ..removeAll({PlayerStatus.loading, PlayerStatus.playing})) { testWidgets('is true when status is $status', (tester) async { when(() => playerBloc.state).thenReturn(PlayerState(status: status)); await tester.pumpApp( playerBloc: playerBloc, HowToPlayPage(), ); final popScope = tester.widget(find.byType(PopScope)); final canPop = popScope.canPop; expect(canPop, isTrue); }); } for (final status in {PlayerStatus.loading, PlayerStatus.playing}) { testWidgets('is false when status is $status', (tester) async { when(() => playerBloc.state).thenReturn(PlayerState(status: status)); await tester.pumpApp( playerBloc: playerBloc, HowToPlayPage(), ); final popScope = tester.widget(find.byType(PopScope)); final canPop = popScope.canPop; expect(canPop, isFalse); }); } }); testWidgets('displays a $HowToPlayView', (tester) async { when(() => playerBloc.state).thenReturn(PlayerState()); await tester.pumpApp( MultiBlocProvider( providers: [ BlocProvider.value( value: playerBloc, ), ], child: HowToPlayPage(), ), layout: IoLayoutData.small, ); expect(find.byType(HowToPlayView), findsOneWidget); }); }); group('$HowToPlayView', () { late HowToPlayCubit howToPlayCubit; late PlayerBloc playerBloc; late Widget widget; late AppLocalizations l10n; setUpAll(() async { l10n = await AppLocalizations.delegate.load(Locale('en')); }); setUp(() { howToPlayCubit = _MockHowToPlayCubit(); playerBloc = _MockPlayerBloc(); when(() => howToPlayCubit.loadAssets(any())).thenAnswer((_) async {}); when(() => howToPlayCubit.state).thenReturn( HowToPlayState(assetsStatus: AssetsLoadingStatus.success), ); when(() => playerBloc.state).thenReturn(PlayerState()); widget = MultiBlocProvider( providers: [ BlocProvider.value(value: howToPlayCubit), BlocProvider.value(value: playerBloc), ], child: HowToPlayView(), ); }); group('displays', () { for (final layout in IoLayoutData.values) { testWidgets('$IoAppBar with $layout', (tester) async { await tester.pumpApp(widget, layout: layout); expect(find.byType(IoAppBar), findsOneWidget); }); testWidgets('$HowToPlayPageContent with $layout', (tester) async { await tester.pumpApp(widget, layout: layout); expect(find.byType(HowToPlayPageContent), findsOneWidget); }); testWidgets('a $PlayNowButton with $layout', (tester) async { await tester.pumpApp(widget, layout: layout); ``` -------------------------------- ### Mock SpaceX API Client and Repository Setup Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_spacex_demo/packages/crew_member_repository/test/crew_member_repository_test.md This snippet demonstrates setting up a mock SpaceX API client using Mocktail and initializing the CrewMemberRepository. It includes the definition of mock objects and the setup for tests, ensuring dependencies are correctly mocked. ```dart // ignore_for_file: prefer_const_constructors import 'package:crew_member_repository/crew_member_repository.dart'; import 'package:mocktail/mocktail.dart'; import 'package:spacex_api/spacex_api.dart'; import 'package:test/test.dart'; class MockSpaceXApiClient extends Mock implements SpaceXApiClient {} void main() { group('CrewMemberRepository', () { late SpaceXApiClient spaceXApiClient; late CrewMemberRepository subject; final crewMembers = List.generate( 3, (i) => CrewMember( id: '$i', name: 'Alejandro Ferrero', status: 'active', agency: 'Very Good Aliens', image: 'https://media-exp1.licdn.com/dms/image/C4D03AQHVNIVOMkwQaA/profile-displayphoto-shrink_200_200/0/1631637257882?e=1637193600&v=beta&t=jFm-Ckb0KS0Z5hJDbo3ZBSEZSYLHfllUf4N-IV2NDTc', wikipedia: 'https://www.wikipedia.org/', launches: ['Launch $i'], ), ); setUp(() { spaceXApiClient = MockSpaceXApiClient(); when(() => spaceXApiClient.fetchAllCrewMembers()) .thenAnswer((_) async => crewMembers); subject = CrewMemberRepository(spaceXApiClient: spaceXApiClient); }); test('constructor returns normally', () { expect( () => CrewMemberRepository(), returnsNormally, ); }); group('.fetchAllCrewMembers', () { test( 'throws CrewMembersException when api throws an exception', () async { when(() => spaceXApiClient.fetchAllCrewMembers()) .thenThrow(Exception()); expect( () => subject.fetchAllCrewMembers(), throwsA(isA()), ); verify(() => spaceXApiClient.fetchAllCrewMembers()).called(1); }, ); test('makes correct request', () async { await subject.fetchAllCrewMembers(); verify(() => spaceXApiClient.fetchAllCrewMembers()).called(1); }); test('returns correct crew members', () async { expect(await spaceXApiClient.fetchAllCrewMembers(), crewMembers); }); }); }); } ``` -------------------------------- ### Flutter Widget Testing Setup Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_bloc/examples/flutter_complex_list/test/complex_list/view/complex_list_page_test.md Sets up mock repository and cubit for widget testing. Includes extension methods for pumping the widget tree with necessary providers. ```dart import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_complex_list/complex_list/complex_list.dart'; import 'package:flutter_complex_list/repository.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; class _MockRepository extends Mock implements Repository {} class _MockComplexListCubit extends MockCubit implements ComplexListCubit {} extension on WidgetTester { Future pumpListPage(Repository repository) { return pumpWidget( MaterialApp( home: RepositoryProvider.value( value: repository, child: const ComplexListPage(), ), ), ); } Future pumpListView(ComplexListCubit listCubit) { return pumpWidget( MaterialApp( home: BlocProvider.value( value: listCubit, child: const ComplexListView(), ), ), ); } } ``` -------------------------------- ### JWT Validation Setup and Mocking Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/api/packages/jwt_middleware/test/src/jwt_middleware_test.md This snippet details the setup for testing JWT middleware functionality. It includes mocking dependencies like `JWT`, `RequestContext`, and `JsonWebSignature`, and registering fallback values for types used in testing. The `setUp` function initializes mocks and defines their behavior, such as returning a specific user ID or validating tokens. ```dart late GetCall get; late JWT jwt; late JwtMiddleware subject; late JwtParser parseJwt; late JsonWebSignature jws; late JwsParser parseJws; late bool isEmulator; setUp(() { get = _MockGet().call; when(() => get(any())). thenAnswer((_) async => http.Response( _successfulKeyResponse, 200, headers: { 'cache-control': 'public, max-age=3600, must-revalidate', }, )); jwt = _MockJWT(); when(() => jwt.userId).thenReturn('USER_ID'); when(() => jwt.validate(any())).thenReturn(true); when(() => jwt.keyId).thenReturn(keyId); when(() => jwt.verifyWith(any())).thenReturn(true); jws = _MockJsonWebSignature(); when(() => jws.verify(any())).thenAnswer((_) async => true); parseJwt = (_) => jwt; }); setUpAll(() { registerFallbackValue(Uri()); registerFallbackValue(_FakeVerifier()); registerFallbackValue(_FakeJsonWebKeyStore()); }); group('JwtMiddleware', () { final uri = Uri.parse('https://example.com/api/endpoint'); const projectId = 'PROJECT_ID'; const keyId = '1e973ee0e16f7eef4f921d50dc61d70b2efefc19'; const user = AuthenticatedUser('USER_ID', 'myToken'); final returnsUser = isA<_UserGetter>().having( (f) => f(), 'returns', user, ); }); ``` -------------------------------- ### Test GET Route Handler with Mockito Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/api/test/routes/game/hint_test.md Demonstrates how to test a GET route handler by mocking dependencies like hintRepository and request contexts. It covers successful retrieval of hints, error handling for exceptions, and validation of request parameters. ```dart group('GET', () { late Uri uri; setUp(() { uri = _MockUri(); when(() => request.method).thenReturn(HttpMethod.get); when(() => request.uri).thenReturn(uri); }); test('returns Response with a list of hints', () async { final hintList = [ Hint(question: 'question1', response: HintResponse.yes, readableResponse: 'yes'), Hint(question: 'question2', response: HintResponse.notApplicable, readableResponse: 'nah'), ]; when(() => uri.queryParameters).thenReturn({'wordId': 'wordId'}); when(() => hintRepository.isHintsEnabled()).thenAnswer((_) async => true); when(() => hintRepository.getPreviousHints(userId: 'userId', wordId: 'wordId')).thenAnswer((_) async => hintList); final response = await route.onRequest(requestContext); expect(response.statusCode, HttpStatus.ok); }); }); ``` -------------------------------- ### Mock BLoC Setup for Testing Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/test/leaderboard/view/leaderboard_success_test.md Demonstrates how to create mock classes for BLoC components using the mock_bloc package. These mocks are essential for isolating the widget under test from actual business logic implementations. ```dart class _MockLeaderboardBloc extends MockBloc implements LeaderboardBloc {} class _MockPlayerBloc extends MockBloc implements PlayerBloc {} ``` -------------------------------- ### Mock WebSocket Server Setup Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_web_socket_client/test/src/web_socket_test.md A utility function to create a local WebSocket server for testing purposes. It uses 'io.HttpServer' and 'WebSocketTransformer' to handle incoming connections and provide a channel for communication. ```dart Future createWebSocketServer({ void Function(WebSocketChannel channel)? onConnection, int port = 0, }) async { final server = await io.HttpServer.bind('localhost', port); server .transform( io.WebSocketTransformer( protocolSelector: (protocols) => protocols.firstOrNull, ), ) .listen((webSocket) { if (onConnection != null) onConnection(IOWebSocketChannel(webSocket)); }); return server; } ``` -------------------------------- ### Mocking and Verifying Methods with Mocktail Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mocktail/packages/mocktail/test/mocktail_test.md Demonstrates how to use 'when' to stub methods and 'verify' to ensure they were called. Includes examples for positional arguments, named arguments, and generic type handling. ```dart test('when voidWithDefaultNamedArg (override)', () { when(() => foo.voidWithDefaultNamedArg(x: 10)).thenReturn(null); expect(() => foo.voidWithDefaultNamedArg(x: 10), returnsNormally); verify(() => foo.voidWithDefaultNamedArg(x: 10)).called(1); }); test('when voidWithGenericTypeArg (specific verify type)', () { when(() => foo.voidWithGenericTypeArg(any())).thenReturn(null); expect(() => foo.voidWithGenericTypeArg(1), returnsNormally); verify(() => foo.voidWithGenericTypeArg(1)).called(1); }); ``` -------------------------------- ### Flutter Test Setup for DashatarPuzzleLayoutDelegate Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_slide_puzzle/test/dashatar/layout/dashatar_puzzle_layout_delegate_test.md Sets up mock objects and initial states for DashatarPuzzleBloc, DashatarThemeBloc, ThemeBloc, PuzzleBloc, TimerBloc, and AudioControlBloc. This is crucial for widget testing to isolate components and control their behavior. ```dart // ignore_for_file: prefer_const_constructors import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:very_good_slide_puzzle/audio_control/audio_control.dart'; import 'package:very_good_slide_puzzle/dashatar/dashatar.dart'; import 'package:very_good_slide_puzzle/models/models.dart'; import 'package:very_good_slide_puzzle/puzzle/puzzle.dart'; import 'package:very_good_slide_puzzle/theme/theme.dart'; import 'package:very_good_slide_puzzle/timer/timer.dart'; import '../../helpers/helpers.dart'; void main() { group('DashatarPuzzleLayoutDelegate', () { late DashatarPuzzleLayoutDelegate layoutDelegate; late DashatarPuzzleBloc dashatarPuzzleBloc; late DashatarThemeBloc dashatarThemeBloc; late ThemeBloc themeBloc; late PuzzleBloc puzzleBloc; late PuzzleState state; late TimerBloc timerBloc; late AudioControlBloc audioControlBloc; setUp(() { layoutDelegate = DashatarPuzzleLayoutDelegate(); dashatarPuzzleBloc = MockDashatarPuzzleBloc(); final dashatarPuzzleState = DashatarPuzzleState(secondsToBegin: 3); whenListen( dashatarPuzzleBloc, Stream.value(dashatarPuzzleState), initialState: dashatarPuzzleState, ); dashatarThemeBloc = MockDashatarThemeBloc(); final themes = [GreenDashatarTheme()]; final dashatarThemeState = DashatarThemeState(themes: themes); whenListen( dashatarThemeBloc, Stream.value(dashatarThemeState), initialState: dashatarThemeState, ); themeBloc = MockThemeBloc(); final theme = GreenDashatarTheme(); final themeState = ThemeState(themes: [theme], theme: theme); when(() => themeBloc.state).thenReturn(themeState); puzzleBloc = MockPuzzleBloc(); state = PuzzleState(); when(() => puzzleBloc.state).thenReturn(state); timerBloc = MockTimerBloc(); when(() => timerBloc.state).thenReturn(TimerState()); audioControlBloc = MockAudioControlBloc(); when(() => audioControlBloc.state).thenReturn(AudioControlState()); }); group('startSectionBuilder', () { testWidgets( 'renders DashatarStartSection ' 'on a large display', (tester) async { tester.setLargeDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.startSectionBuilder(state), ), dashatarPuzzleBloc: dashatarPuzzleBloc, dashatarThemeBloc: dashatarThemeBloc, puzzleBloc: puzzleBloc, themeBloc: themeBloc, timerBloc: timerBloc, audioControlBloc: audioControlBloc, ); expect( find.byWidgetPredicate( (widget) => widget is DashatarStartSection && widget.state == state, ), findsOneWidget, ); }); testWidgets( 'renders DashatarStartSection ' 'on a medium display', (tester) async { tester.setMediumDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.startSectionBuilder(state), ), dashatarPuzzleBloc: dashatarPuzzleBloc, dashatarThemeBloc: dashatarThemeBloc, puzzleBloc: puzzleBloc, themeBloc: themeBloc, timerBloc: timerBloc, audioControlBloc: audioControlBloc, ); expect( find.byWidgetPredicate( (widget) => widget is DashatarStartSection && widget.state == state, ), findsOneWidget, ); }); testWidgets( 'renders DashatarStartSection ' 'on a small display', (tester) async { tester.setSmallDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.startSectionBuilder(state), ), dashatarPuzzleBloc: dashatarPuzzleBloc, dashatarThemeBloc: dashatarThemeBloc, puzzleBloc: puzzleBloc, themeBloc: themeBloc, timerBloc: timerBloc, audioControlBloc: audioControlBloc, ); expect( find.byWidgetPredicate( (widget) => widget is DashatarStartSection && widget.state == state, ), findsOneWidget, ); }); }); group('endSectionBuilder', () { group('on a large display', () { testWidgets( 'does not render DashatarPuzzleActionButton and ' 'DashatarThemePicker', (tester) async { tester.setLargeDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.endSectionBuilder(state), ), dashatarPuzzleBloc: dashatarPuzzleBloc, dashatarThemeBloc: dashatarThemeBloc, puzzleBloc: puzzleBloc, ``` -------------------------------- ### Flutter Test Setup for Registration Bloc Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_bloc_concurrency_demos/test/registration/view/registration_view_test.md Sets up fallback values for RegistrationState and RegistrationEvent using `setUpAll` for use with `registerFallbackValue` in Flutter tests. This is crucial for mocking dependencies. ```dart void main() { setUpAll(() { registerFallbackValue(const RegistrationState.initial()); registerFallbackValue(const RegistrationSubmitted()); }); group('Registration', () { testWidgets('instantiates', (tester) async { const files = Registration(isOld: false); await tester.pumpApp(files); await tester.pumpAndSettle(); expect(find.byType(RegistrationView), findsOneWidget); }); }); group('RegistrationView', () { const username = 'unicorn'; const usernameTooShortState = RegistrationState( username: UsernameInput.dirty(value: 'uni'), isCheckingUsername: false, status: RegistrationStatus.editing, ); const usernameEmptyState = RegistrationState( username: UsernameInput.dirty(), isCheckingUsername: false, status: RegistrationStatus.editing, ); const initialUsernameState = RegistrationState( username: UsernameInput.dirty(value: username), isCheckingUsername: false, status: RegistrationStatus.editing, ); const usernameTakenState = RegistrationState( username: UsernameInput.dirty( value: username, serverError: UsernameInputError.taken, ), isCheckingUsername: false, status: RegistrationStatus.editing, ); const checkingUsernameState = RegistrationState( username: UsernameInput.dirty(value: username), isCheckingUsername: true, status: RegistrationStatus.editing, ); group('body', () { Stream registrationStates({required bool success}) { return Stream.fromIterable( [ const RegistrationState( username: UsernameInput.dirty(value: username), isCheckingUsername: false, status: RegistrationStatus.submitting, ), RegistrationState( username: const UsernameInput.dirty(value: username), isCheckingUsername: false, status: success ? RegistrationStatus.succeeded : RegistrationStatus.failed, ), ], ); } testWidgets('shows form inputs', (tester) async { final bloc = MockRegistrationBloc(); when(() => bloc.state).thenReturn(initialUsernameState); await tester.pumpRegistrationView(bloc); await tester.pumpAndSettle(); final form = find.byType(Form); expect(form, findsOneWidget); final usernameField = find.byType(UsernameField); expect(usernameField, findsOneWidget); final submitButton = find.byType(SubmitButton); expect(submitButton, findsOneWidget); }); testWidgets('shows snackbar for registration failure', (tester) async { final bloc = MockRegistrationBloc(); whenListen( bloc, registrationStates(success: false), initialState: initialUsernameState, ); await tester.pumpRegistrationView(bloc); await tester.pumpAndSettle(); final snackbar = find.byType(SnackBar); expect(snackbar, findsOneWidget); final context = tester.element(snackbar); final text = find.descendant( of: snackbar, matching: find.text(context.l10n.registrationViewError), ); expect(text, findsOneWidget); }); testWidgets('shows snackbar for registration success', (tester) async { final bloc = MockRegistrationBloc(); whenListen( bloc, registrationStates(success: true), initialState: initialUsernameState, ); await tester.pumpRegistrationView(bloc); await tester.pumpAndSettle(); final snackbar = find.byType(SnackBar); expect(snackbar, findsOneWidget); }); }); }); } ``` -------------------------------- ### Handling Exceptions in blocTest for Dart Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_bloc/packages/bloc_test/test/bloc_bloc_test_test.md This example shows how to test for exceptions thrown during BLoC operations. It uses the `setUp` to mock a repository method that throws an exception and verifies that the BLoC emits an empty list of states and captures the error. ```dart blocTest( 'setUp is executed before build/act', setUp: () { when(() => repository.sideEffect()).thenThrow(Exception()); }, build: () => SideEffectCounterBloc(repository), act: (bloc) => bloc.add(CounterEvent.increment), expect: () => const [], errors: () => [isException], ); ``` -------------------------------- ### ApiClient Initialization and Setup in Tests Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/packages/api_client/test/src/api_client_test.md This code sets up the ApiClient for testing, including mocking the HTTP client, creating stream controllers for authentication and app check tokens, and defining default and expected responses. It ensures the ApiClient is ready to be tested. ```dart late ApiClient subject; late _MockHttpClient httpClient; late StreamController idTokenStreamController; late StreamController appCheckTokenStreamController; Future Function() refreshIdToken = () async => null; setUp(() { httpClient = _MockHttpClient(); when( () => httpClient.get( any(), headers: any(named: 'headers'), ), ).thenAnswer((_) async => defaultResponse); // ... other http method mock setups ... idTokenStreamController = StreamController.broadcast(); appCheckTokenStreamController = StreamController.broadcast(); subject = ApiClient( baseUrl: baseUrl, getCall: httpClient.get, postCall: httpClient.post, patchCall: httpClient.patch, putCall: httpClient.put, idTokenStream: idTokenStreamController.stream, refreshIdToken: () => refreshIdToken(), appCheckTokenStream: appCheckTokenStreamController.stream, ); }); ``` -------------------------------- ### WidgetTester extensions for StreakAtRiskView Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/test/streak/view/streak_at_risk_test.md Custom extensions for WidgetTester to simplify the setup of StreakAtRiskView within a Bloc-provided environment. These helpers facilitate testing complex widget trees by abstracting the MultiBlocProvider setup. ```dart extension on WidgetTester { Future pumpStreakDialogCheck({ required PlayerBloc playerBloc, required WordSelectionBloc wordSelectionBloc, required VoidCallback onLeave, }) async { return pumpApp( MultiBlocProvider( providers: [ BlocProvider.value(value: playerBloc), BlocProvider.value(value: wordSelectionBloc), ], child: Builder(builder: (context) { return ElevatedButton( onPressed: () { StreakAtRiskView.check(context, onLeave: onLeave); }, child: Text('button'), ); }), ), ); } Future tapStreakRisk() async { await tap(find.text('button')); } } ``` -------------------------------- ### Configure and List Global Bricks Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mason/packages/mason_cli/test/commands/list_test.md Shows how to programmatically create a mason.yaml file, add a global brick, and verify that the list command correctly identifies the global brick. ```dart File(p.join(Directory.current.path, 'mason.yaml')).writeAsStringSync('bricks:\n documentation:\n path: ../../../../../bricks/documentation\n todos:\n path: ../../../../../bricks/todos\n widget:\n git:\n url: https://github.com/felangel/mason\n path: bricks/widget'); await expectLater(MasonCommandRunner(logger: logger, pubUpdater: pubUpdater).run(['add', '-g', 'greeting', '--path', greetingPath]), completion(ExitCode.success.code)); await expectLater(MasonCommandRunner(logger: logger, pubUpdater: pubUpdater).run(['list', '-g']), completion(ExitCode.success.code)); verify(() => logger.info('└── ${styleBold.wrap('greeting')} 0.1.0+1 -> $greetingPath')).called(1); ``` -------------------------------- ### Test SimplePuzzleLayoutDelegate Start Section Rendering Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_slide_puzzle/test/simple/simple_puzzle_layout_delegate_test.md Tests the rendering of the start section of the SimplePuzzleLayoutDelegate across different display sizes (large, medium, small). It verifies that the SimpleStartSection widget is correctly displayed with the provided puzzle state. ```Dart // ignore_for_file: prefer_const_constructors import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:very_good_slide_puzzle/colors/colors.dart'; import 'package:very_good_slide_puzzle/models/models.dart'; import 'package:very_good_slide_puzzle/puzzle/puzzle.dart'; import 'package:very_good_slide_puzzle/simple/simple_puzzle_layout_delegate.dart'; import 'package:very_good_slide_puzzle/theme/theme.dart'; import '../helpers/helpers.dart'; void main() { group('SimplePuzzleLayoutDelegate', () { late SimplePuzzleLayoutDelegate layoutDelegate; late ThemeBloc themeBloc; late PuzzleTheme theme; late PuzzleState state; const themeName = 'Name'; setUpAll(() { final oldComparator = goldenFileComparator as LocalFileComparator; final newComparator = TolerantComparator(Uri.parse('${oldComparator.basedir}test')); expect(oldComparator.basedir, newComparator.basedir); goldenFileComparator = newComparator; }); setUp(() { layoutDelegate = SimplePuzzleLayoutDelegate(); themeBloc = MockThemeBloc(); theme = MockPuzzleTheme(); state = MockPuzzleState(); final themeState = ThemeState(themes: [theme], theme: theme); when(() => state.puzzleStatus).thenReturn(PuzzleStatus.incomplete); when(() => state.numberOfMoves).thenReturn(5); when(() => state.numberOfTilesLeft).thenReturn(15); when(() => theme.name).thenReturn(themeName); when(() => theme.nameColor).thenReturn(Colors.black); when(() => theme.titleColor).thenReturn(Colors.black); when(() => theme.defaultColor).thenReturn(Colors.black); when(() => theme.buttonColor).thenReturn(Colors.black); when(() => themeBloc.state).thenReturn(themeState); }); group('startSectionBuilder', () { testWidgets( 'renders SimpleStartSection ' 'on a large display', (tester) async { tester.setLargeDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.startSectionBuilder(state), ), themeBloc: themeBloc, ); expect( find.byWidgetPredicate( (widget) => widget is SimpleStartSection && widget.state == state, ), findsOneWidget, ); }); testWidgets( 'renders SimpleStartSection ' 'on a medium display', (tester) async { tester.setMediumDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.startSectionBuilder(state), ), themeBloc: themeBloc, ); expect( find.byWidgetPredicate( (widget) => widget is SimpleStartSection && widget.state == state, ), findsOneWidget, ); }); testWidgets( 'renders SimpleStartSection ' 'on a small display', (tester) async { tester.setSmallDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.startSectionBuilder(state), ), themeBloc: themeBloc, ); expect( find.byWidgetPredicate( (widget) => widget is SimpleStartSection && widget.state == state, ), findsOneWidget, ); }); }); group('endSectionBuilder', () { testWidgets( 'renders an empty widget ' 'on a large display', (tester) async { tester.setLargeDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.endSectionBuilder(state), ), themeBloc: themeBloc, ); expect(find.byType(SizedBox), findsOneWidget); expect(find.byType(SimplePuzzleShuffleButton), findsNothing); }); testWidgets( 'renders SimplePuzzleShuffleButton ' 'on a medium display', (tester) async { tester.setMediumDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.endSectionBuilder(state), ), themeBloc: themeBloc, ); expect(find.byType(SimplePuzzleShuffleButton), findsOneWidget); }); testWidgets( 'renders SimplePuzzleShuffleButton ' 'on a small display', (tester) async { tester.setSmallDisplaySize(); await tester.pumpApp( SingleChildScrollView( child: layoutDelegate.endSectionBuilder(state), ), themeBloc: themeBloc, ); expect(find.byType(SimplePuzzleShuffleButton), findsOneWidget); }); }); group('backgroundBuilder', () { testWidgets( 'renders a large dash Image ' 'on a large display', (tester) async { ``` -------------------------------- ### Instantiate and Manage BricksJson Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mason/packages/mason/test/src/bricks_json_test.md Demonstrates how to initialize BricksJson using different directory sources and how to add bricks to the registry. It also shows how to handle malformed JSON files and clear the brick cache. ```dart final directory = Directory.systemTemp.createTempSync(); final bricksJson = BricksJson(directory: directory); // Adding a brick from a path final brick = Brick.path(path.join('..', '..', 'bricks', 'simple')); await bricksJson.add(brick); await bricksJson.flush(); // Clearing the cache bricksJson.clear(); ``` -------------------------------- ### Test GET /game/leaderboard/initials_blacklist Route Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/api/test/routes/game/leaderboard/initials_blacklist/index_test.md Tests the GET request for the /game/leaderboard/initials_blacklist route. It mocks the LeaderboardRepository to return a predefined blacklist and asserts that the response status code is 200 OK and the response body contains the expected blacklist. ```Dart import 'dart:io'; import 'package:dart_frog/dart_frog.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; import '../../../../../routes/game/leaderboard/initials_blacklist/index.dart' as route; class _MockLeaderboardRepository extends Mock implements LeaderboardRepository {} class _MockRequest extends Mock implements Request {} class _MockRequestContext extends Mock implements RequestContext {} void main() { group('GET /', () { late LeaderboardRepository leaderboardRepository; late Request request; late RequestContext context; const blacklist = ['AAA', 'BBB', 'CCC']; setUp(() { leaderboardRepository = _MockLeaderboardRepository(); request = _MockRequest(); context = _MockRequestContext(); when(() => context.request).thenReturn(request); when(() => context.read()) .thenReturn(leaderboardRepository); }); test('responds with a 200', () async { when(() => request.method).thenReturn(HttpMethod.get); when(() => leaderboardRepository.getInitialsBlocklist()) .thenAnswer((_) async => blacklist); final response = await route.onRequest(context); expect(response.statusCode, equals(HttpStatus.ok)); }); for (final httpMethod in HttpMethod.values.toList() ..remove(HttpMethod.get)) { test('does not allow $httpMethod', () async { when(() => request.method).thenReturn(httpMethod); final response = await route.onRequest(context); expect(response.statusCode, equals(HttpStatus.methodNotAllowed)); }); } test('responds with the blacklist', () async { when(() => request.method).thenReturn(HttpMethod.get); when(() => leaderboardRepository.getInitialsBlocklist()) .thenAnswer((_) async => blacklist); final response = await route.onRequest(context); final json = await response.json(); expect( json, equals({ 'list': ['AAA', 'BBB', 'CCC'], }), ); }); }); } ``` -------------------------------- ### Create Universal Bundle from Hosted Source Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mason/packages/mason_cli/test/commands/bundle_test.md Tests the creation of a universal bundle from a hosted brick source. It verifies that the command succeeds, generates the expected bundle file, and logs progress appropriately. ```dart test('creates a new universal bundle from hosted', () async { final testDir = Directory( path.join(Directory.current.path, 'hosted'), )..createSync(recursive: true); Directory.current = testDir.path; final result = await commandRunner.run([ 'bundle', 'greeting', '--source', 'hosted', ]); expect(result, equals(ExitCode.success.code)); final file = File( path.join( testFixturesPath(cwd, suffix: '.bundle'), 'hosted', 'greeting.bundle', ), ); final actual = json.encode( (await MasonBundle.fromUniversalBundle(file.readAsBytesSync())) .toJson(), ); expect(actual, contains('"readme":{"path":"README.md","data":"')); expect( actual, contains('"changelog":{"path":"CHANGELOG.md","data":"'), ); expect(actual, contains('"license":{"path":"LICENSE","data":"')); verify(() => logger.progress('Bundling greeting')).called(1); verify(() => progress.complete('Generated 1 file.')).called(1); verify( () => logger.info(darkGray.wrap(' ${canonicalize(file.path)}')), ).called(1); }); ``` -------------------------------- ### Test HTTP GET Request with Authentication Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/packages/api_client/test/src/api_client_test.md Verifies that the API client correctly includes Authorization and Firebase AppCheck headers in GET requests. It also demonstrates how to mock token streams and verify the request structure using mockito. ```dart test('sends the authentication and app check token', () async { idTokenStreamController.add(mockIdToken); appCheckTokenStreamController.add(mockAppCheckToken); await Future.microtask(() {}); await subject.get('/path/to/endpoint'); verify( () => httpClient.get( Uri.parse('$baseUrl/path/to/endpoint'), headers: { 'Authorization': 'Bearer $mockIdToken', 'X-Firebase-AppCheck': mockAppCheckToken, }, ), ).called(1); }); ``` -------------------------------- ### Watch Local Brick for Changes (Dart) Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mason/packages/mason_cli/test/commands/make_test.md Demonstrates setting up a local brick template and watching it for changes. This involves creating temporary directories, defining a brick's YAML content, and preparing for subsequent file modifications. ```dart const watchBrick = 'watch_brick'; final tempDirectory = Directory.systemTemp.createTempSync(); Directory.current = tempDirectory.path; addTearDown(() { Directory.current = cwd; if (tempDirectory.existsSync()) { tempDirectory.deleteSync(recursive: true); } }); final outputDirectory = Directory( path.join(tempDirectory.path, 'watch_output'), )..createSync(recursive: true); final watchBrickDirectory = Directory( path.join(tempDirectory.path, watchBrick), )..createSync(recursive: true); final localBrickTemplateDirectory = Directory( path.join(watchBrickDirectory.path, BrickYaml.dir), )..createSync(recursive: true); File(path.join(watchBrickDirectory.path, BrickYaml.file)) ..createSync(recursive: true) ..writeAsStringSync(''' name: $watchBrick description: A local brick that will be watched. version: 0.1.0+1 vars: name: type: string description: Your name default: Dash prompt: What is your name? '''); final helloTemplate = ``` -------------------------------- ### Initialize Mason Project (Dart) Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/felangel_mason/packages/mason_cli/test/commands/init_test.md Tests the 'mason init' command to initialize a new Mason project. It checks for existing 'mason.yaml' files and verifies the successful creation of project files when none exist. Dependencies include 'mason', 'mason_cli', 'mocktail', and 'pub_updater'. ```dart import 'dart:io'; import 'package:mason/mason.dart' hide packageVersion; import 'package:mason_cli/src/command_runner.dart'; import 'package:mason_cli/src/version.dart'; import 'package:mocktail/mocktail.dart'; import 'package:path/path.dart' as path; import 'package:pub_updater/pub_updater.dart'; import 'package:test/test.dart'; import '../helpers/helpers.dart'; class _MockLogger extends Mock implements Logger {} class _MockPubUpdater extends Mock implements PubUpdater {} class _MockProgress extends Mock implements Progress {} void main() { final cwd = Directory.current; group('mason init', () { late Logger logger; late Progress progress; late PubUpdater pubUpdater; late MasonCommandRunner commandRunner; setUp(() { logger = _MockLogger(); progress = _MockProgress(); pubUpdater = _MockPubUpdater(); when(() => logger.progress(any())).thenReturn(progress); when( () => pubUpdater.getLatestVersion(any()), ).thenAnswer((_) async => packageVersion); commandRunner = MasonCommandRunner( logger: logger, pubUpdater: pubUpdater, ); setUpTestingEnvironment(cwd, suffix: '.init'); }); tearDown(() { Directory.current = cwd; }); test('exits with code 64 when mason.yaml already exists', () async { final masonYaml = File(path.join(Directory.current.path, 'mason.yaml')); await masonYaml.create(recursive: true); final result = await commandRunner.run(['init']); expect(result, equals(ExitCode.usage.code)); verify( () => logger.err('Existing mason.yaml at ${masonYaml.path}') ).called(1); }); test('initializes mason when a mason.yaml does not exist', () async { final result = await commandRunner.run(['init']); expect(result, equals(ExitCode.success.code)); final actual = Directory( path.join(testFixturesPath(cwd, suffix: '.init')) ); final expected = Directory( path.join(testFixturesPath(cwd, suffix: 'init')) ); expect(directoriesDeepEqual(actual, expected), isTrue); expect( File(path.join(actual.path, '.mason', 'bricks.json')).existsSync(), isFalse, ); verify(() => logger.progress('Initializing')).called(1); verify(() => progress.complete('Generated 1 file.')).called(1); }); }); } ``` -------------------------------- ### Test GET /board/sections Route Source: https://github.com/nana-kwame-bot/flutter_tests/blob/main/VGVentures_io_crossword/api/test/routes/board/sections/index_test.md Tests the functionality of the GET /board/sections route. It verifies that all board sections are correctly retrieved and returned with an HTTP 200 OK status. This involves mocking the CrosswordRepository to return predefined board sections. ```dart import 'dart:io'; import 'package:crossword_repository/crossword_repository.dart'; import 'package:dart_frog/dart_frog.dart'; import 'package:game_domain/game_domain.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; import '../../../../routes/board/sections/index.dart' as route; class _MockRequestContext extends Mock implements RequestContext {} class _MockRequest extends Mock implements Request {} class _MockCrosswordRepository extends Mock implements CrosswordRepository {} void main() { group('GET /board/sections', () { late RequestContext requestContext; late Request request; late CrosswordRepository crosswordRepository; setUp(() { requestContext = _MockRequestContext(); request = _MockRequest(); when(() => request.method).thenReturn(HttpMethod.get); crosswordRepository = _MockCrosswordRepository(); when(() => requestContext.request).thenReturn(request); when(() => requestContext.read()) .thenReturn(crosswordRepository); }); test('return all sections', () async { const boardSections = [ BoardSection( id: '1', position: Point(1, 1), words: [], ), BoardSection( id: '2', position: Point(2, 1), words: [], ), ]; when(() => crosswordRepository.listAllSections()) .thenAnswer((_) async => boardSections); final response = await route.onRequest(requestContext); expect(response.statusCode, HttpStatus.ok); expect( await response.json(), boardSections.map((section) => section.toJson()).toList(), ); }); test('returns method not allowed when is not a get', () async { when(() => request.method).thenReturn(HttpMethod.post); final response = await route.onRequest(requestContext); expect(response.statusCode, HttpStatus.methodNotAllowed); }); }); } ```