From 79a7440dc314672dafdea7b8c4edb959662a1c81 Mon Sep 17 00:00:00 2001 From: RuiAlonso Date: Fri, 6 May 2022 13:34:12 +0200 Subject: [PATCH] test: fixed tests and coverage --- test/game/bloc/game_bloc_test.dart | 14 ++++ test/game/bloc/game_event_test.dart | 13 +++ .../game/components/backbox/backbox_test.dart | 39 +++++++-- .../backbox/bloc/backbox_bloc_test.dart | 28 ++++++- .../backbox/bloc/backbox_event_test.dart | 81 +++++++++++++++++++ .../backbox/bloc/backbox_state_test.dart | 54 ++++++++++++- .../backbox/displays/info_display_test.dart | 77 ++++++++++++++++++ .../widgets/replay_button_overlay_test.dart | 45 +++++++++++ .../start_game/bloc/start_game_bloc_test.dart | 14 +++- .../bloc/start_game_event_test.dart | 7 ++ .../bloc/start_game_state_test.dart | 40 ++++++++- .../widgets/start_game_listener_test.dart | 34 +++++++- 12 files changed, 429 insertions(+), 17 deletions(-) create mode 100644 test/game/components/backbox/displays/info_display_test.dart create mode 100644 test/game/view/widgets/replay_button_overlay_test.dart diff --git a/test/game/bloc/game_bloc_test.dart b/test/game/bloc/game_bloc_test.dart index 3e5abb74..07327b12 100644 --- a/test/game/bloc/game_bloc_test.dart +++ b/test/game/bloc/game_bloc_test.dart @@ -38,6 +38,20 @@ void main() { ], ); + blocTest( + 'GameRestarted restarts the game', + build: GameBloc.new, + act: (bloc) => bloc.add(const GameRestarted()), + expect: () => [ + isA() + ..having( + (state) => state.status, + 'status', + GameStatus.replaying, + ), + ], + ); + group('RoundLost', () { blocTest( 'decreases number of rounds ' diff --git a/test/game/bloc/game_event_test.dart b/test/game/bloc/game_event_test.dart index c4de5792..b15a14b9 100644 --- a/test/game/bloc/game_event_test.dart +++ b/test/game/bloc/game_event_test.dart @@ -98,6 +98,19 @@ void main() { }); }); + group('GameRestarted', () { + test('can be instantiated', () { + expect(const GameRestarted(), isNotNull); + }); + + test('supports value equality', () { + expect( + GameRestarted(), + equals(const GameRestarted()), + ); + }); + }); + group('SparkyTurboChargeActivated', () { test('can be instantiated', () { expect(const SparkyTurboChargeActivated(), isNotNull); diff --git a/test/game/components/backbox/backbox_test.dart b/test/game/components/backbox/backbox_test.dart index 52e2746e..4d1fb826 100644 --- a/test/game/components/backbox/backbox_test.dart +++ b/test/game/components/backbox/backbox_test.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:bloc_test/bloc_test.dart'; +import 'package:flame/game.dart'; import 'package:flame/input.dart'; import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; @@ -20,7 +21,8 @@ import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_theme/pinball_theme.dart' as theme; -class _TestGame extends Forge2DGame with HasKeyboardHandlerComponents { +class _TestGame extends Forge2DGame + with HasKeyboardHandlerComponents, HasTappables { final character = theme.DashTheme(); @override @@ -33,6 +35,7 @@ class _TestGame extends Forge2DGame with HasKeyboardHandlerComponents { character.leaderboardIcon.keyName, Assets.images.backbox.marquee.keyName, Assets.images.backbox.displayDivider.keyName, + Assets.images.backbox.button.share.keyName, ]); } @@ -93,6 +96,24 @@ class _MockAppLocalizations extends Mock implements AppLocalizations { @override String get loading => ''; + + @override + String get shareYourScore => ''; + + @override + String get andChallengeYourFriends => ''; + + @override + String get share => ''; + + @override + String get gotoIO => ''; + + @override + String get learnMore => ''; + + @override + String get firebaseOrOpenSource => ''; } void main() { @@ -193,21 +214,23 @@ void main() { ); flameTester.test( - 'adds InitialsSubmissionSuccessDisplay on InitialsSuccessState', + 'adds InfoDisplay on InitialsSuccessState', (game) async { + final state = InitialsSuccessState( + score: 100, + initials: 'AAA', + character: theme.AndroidTheme(), + ); whenListen( bloc, - Stream.value(InitialsSuccessState()), - initialState: InitialsSuccessState(), + Stream.value(state), + initialState: state, ); final backbox = Backbox.test(bloc: bloc); await game.pump(backbox); expect( - game - .descendants() - .whereType() - .length, + game.descendants().whereType().length, equals(1), ); }, diff --git a/test/game/components/backbox/bloc/backbox_bloc_test.dart b/test/game/components/backbox/bloc/backbox_bloc_test.dart index c2fbc088..bdc9233a 100644 --- a/test/game/components/backbox/bloc/backbox_bloc_test.dart +++ b/test/game/components/backbox/bloc/backbox_bloc_test.dart @@ -56,7 +56,11 @@ void main() { ), expect: () => [ LoadingState(), - InitialsSuccessState(), + InitialsSuccessState( + score: 10, + initials: 'AAA', + character: DashTheme(), + ), ], ); @@ -88,5 +92,27 @@ void main() { ], ); }); + + blocTest( + 'adds ShareState on ScoreShareRequested', + setUp: () { + leaderboardRepository = _MockLeaderboardRepository(); + }, + build: () => BackboxBloc(leaderboardRepository: leaderboardRepository), + act: (bloc) => bloc.add( + ScoreShareRequested( + score: 100, + initials: 'AAA', + character: AndroidTheme(), + ), + ), + expect: () => [ + ShareState( + score: 100, + initials: 'AAA', + character: AndroidTheme(), + ), + ], + ); }); } diff --git a/test/game/components/backbox/bloc/backbox_event_test.dart b/test/game/components/backbox/bloc/backbox_event_test.dart index 5fc766a9..42231a18 100644 --- a/test/game/components/backbox/bloc/backbox_event_test.dart +++ b/test/game/components/backbox/bloc/backbox_event_test.dart @@ -122,5 +122,86 @@ void main() { ); }); }); + + group('ScoreShareRequested', () { + test('can be instantiated', () { + expect( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + isNotNull, + ); + }); + + test('supports value comparison', () { + expect( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + equals( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + ), + ); + + expect( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + isNot( + equals( + ScoreShareRequested( + score: 1, + initials: 'AAA', + character: AndroidTheme(), + ), + ), + ), + ); + + expect( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + isNot( + equals( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: SparkyTheme(), + ), + ), + ), + ); + + expect( + ScoreShareRequested( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + isNot( + equals( + ScoreShareRequested( + score: 0, + initials: 'BBB', + character: AndroidTheme(), + ), + ), + ), + ); + }); + }); }); } diff --git a/test/game/components/backbox/bloc/backbox_state_test.dart b/test/game/components/backbox/bloc/backbox_state_test.dart index 4708c9bb..d127e5f5 100644 --- a/test/game/components/backbox/bloc/backbox_state_test.dart +++ b/test/game/components/backbox/bloc/backbox_state_test.dart @@ -95,11 +95,31 @@ void main() { group('InitialsSuccessState', () { test('can be instantiated', () { - expect(InitialsSuccessState(), isNotNull); + expect( + InitialsSuccessState( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + isNotNull, + ); }); test('supports value comparison', () { - expect(InitialsSuccessState(), equals(InitialsSuccessState())); + expect( + InitialsSuccessState( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + equals( + InitialsSuccessState( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + ), + ); }); group('InitialsFailureState', () { @@ -111,6 +131,36 @@ void main() { expect(InitialsFailureState(), equals(InitialsFailureState())); }); }); + + group('ShareState', () { + test('can be instantiated', () { + expect( + ShareState( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + isNotNull, + ); + }); + + test('supports value comparison', () { + expect( + ShareState( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + equals( + ShareState( + score: 0, + initials: 'AAA', + character: AndroidTheme(), + ), + ), + ); + }); + }); }); }); } diff --git a/test/game/components/backbox/displays/info_display_test.dart b/test/game/components/backbox/displays/info_display_test.dart new file mode 100644 index 00000000..5ae82b8e --- /dev/null +++ b/test/game/components/backbox/displays/info_display_test.dart @@ -0,0 +1,77 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame/game.dart'; +import 'package:flame_bloc/flame_bloc.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball/game/bloc/game_bloc.dart'; +import 'package:pinball/game/components/backbox/displays/info_display.dart'; +import 'package:pinball/l10n/l10n.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +class _TestGame extends Forge2DGame with HasTappables { + @override + Future onLoad() async { + await super.onLoad(); + images.prefix = ''; + await images.loadAll( + [ + Assets.images.backbox.button.share.keyName, + ], + ); + } + + Future pump(InfoDisplay component) { + return ensureAdd( + FlameBlocProvider.value( + value: GameBloc(), + children: [ + FlameProvider.value( + _MockAppLocalizations(), + children: [component], + ), + ], + ), + ); + } +} + +class _MockAppLocalizations extends Mock implements AppLocalizations { + @override + String get shareYourScore => ''; + + @override + String get andChallengeYourFriends => ''; + + @override + String get share => ''; + + @override + String get gotoIO => ''; + + @override + String get learnMore => ''; + + @override + String get firebaseOrOpenSource => ''; +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + final flameTester = FlameTester(_TestGame.new); + + group('InfoDisplay', () { + flameTester.test( + 'loads correctly', + (game) async { + final component = InfoDisplay(); + await game.pump(component); + expect(game.descendants(), contains(component)); + }, + ); + }); +} diff --git a/test/game/view/widgets/replay_button_overlay_test.dart b/test/game/view/widgets/replay_button_overlay_test.dart new file mode 100644 index 00000000..e6953d00 --- /dev/null +++ b/test/game/view/widgets/replay_button_overlay_test.dart @@ -0,0 +1,45 @@ +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball/start_game/bloc/start_game_bloc.dart'; + +import '../../../helpers/helpers.dart'; + +class _MockStartGameBloc extends Mock implements StartGameBloc {} + +void main() { + group('ReplayButtonOverlay', () { + late StartGameBloc startGameBloc; + + setUp(() async { + await mockFlameImages(); + startGameBloc = _MockStartGameBloc(); + + whenListen( + startGameBloc, + Stream.value(const StartGameState.initial()), + initialState: const StartGameState.initial(), + ); + }); + + testWidgets('renders correctly', (tester) async { + await tester.pumpApp(const ReplayButtonOverlay()); + + expect(find.text('Replay'), findsOneWidget); + }); + + testWidgets('adds ReplayTapped event to StartGameBloc when taped', + (tester) async { + await tester.pumpApp( + const ReplayButtonOverlay(), + startGameBloc: startGameBloc, + ); + + await tester.tap(find.text('Replay')); + await tester.pump(); + + verify(() => startGameBloc.add(const ReplayTapped())).called(1); + }); + }); +} diff --git a/test/start_game/bloc/start_game_bloc_test.dart b/test/start_game/bloc/start_game_bloc_test.dart index 45460fe3..55c2ccc0 100644 --- a/test/start_game/bloc/start_game_bloc_test.dart +++ b/test/start_game/bloc/start_game_bloc_test.dart @@ -5,7 +5,7 @@ import 'package:pinball/start_game/bloc/start_game_bloc.dart'; void main() { group('StartGameBloc', () { blocTest( - 'on PlayTapped changes status to selectCharacter', + 'on PlayTapped changes status to selectCharacter and restarted false', build: StartGameBloc.new, act: (bloc) => bloc.add(const PlayTapped()), expect: () => [ @@ -15,6 +15,18 @@ void main() { ], ); + blocTest( + 'on ReplayTapped changes status to selectCharacter and restarted enabled', + build: StartGameBloc.new, + act: (bloc) => bloc.add(const ReplayTapped()), + expect: () => [ + const StartGameState( + status: StartGameStatus.selectCharacter, + restarted: true, + ) + ], + ); + blocTest( 'on CharacterSelected changes status to howToPlay', build: StartGameBloc.new, diff --git a/test/start_game/bloc/start_game_event_test.dart b/test/start_game/bloc/start_game_event_test.dart index cf481d9f..26f96160 100644 --- a/test/start_game/bloc/start_game_event_test.dart +++ b/test/start_game/bloc/start_game_event_test.dart @@ -12,6 +12,13 @@ void main() { ); }); + test('ReplayTapped supports value equality', () { + expect( + ReplayTapped(), + equals(ReplayTapped()), + ); + }); + test('CharacterSelected supports value equality', () { expect( CharacterSelected(), diff --git a/test/start_game/bloc/start_game_state_test.dart b/test/start_game/bloc/start_game_state_test.dart index 7ede696d..26e1738c 100644 --- a/test/start_game/bloc/start_game_state_test.dart +++ b/test/start_game/bloc/start_game_state_test.dart @@ -25,10 +25,43 @@ void main() { expect(testState, secondState); }); - test('supports copyWith', () { - final secondState = testState.copyWith(); + group('copyWith', () { + test( + 'copies correctly ' + 'when no argument specified', + () { + const state = StartGameState( + status: StartGameStatus.initial, + ); + expect( + state.copyWith(), + equals(state), + ); + }, + ); - expect(testState, secondState); + test( + 'copies correctly ' + 'when all arguments specified', + () { + const state = StartGameState( + status: StartGameStatus.initial, + ); + final otherState = StartGameState( + status: StartGameStatus.play, + restarted: true, + ); + expect(state, isNot(equals(otherState))); + + expect( + state.copyWith( + status: otherState.status, + restarted: otherState.restarted, + ), + equals(otherState), + ); + }, + ); }); test('has correct props', () { @@ -36,6 +69,7 @@ void main() { testState.props, equals([ StartGameStatus.selectCharacter, + false, ]), ); }); diff --git a/test/start_game/widgets/start_game_listener_test.dart b/test/start_game/widgets/start_game_listener_test.dart index 4e25796b..1499687c 100644 --- a/test/start_game/widgets/start_game_listener_test.dart +++ b/test/start_game/widgets/start_game_listener_test.dart @@ -46,12 +46,14 @@ void main() { }); testWidgets( - 'calls onGameStarted event', + 'calls only GameStarted event on play', (tester) async { whenListen( startGameBloc, Stream.value( - const StartGameState(status: StartGameStatus.selectCharacter), + const StartGameState( + status: StartGameStatus.selectCharacter, + ), ), initialState: const StartGameState.initial(), ); @@ -64,10 +66,38 @@ void main() { startGameBloc: startGameBloc, ); + verifyNever(() => gameBloc.add(const GameRestarted())); verify(() => gameBloc.add(const GameStarted())).called(1); }, ); + testWidgets( + 'calls only GameRestarted event on replay', + (tester) async { + whenListen( + startGameBloc, + Stream.value( + const StartGameState( + status: StartGameStatus.selectCharacter, + restarted: true, + ), + ), + initialState: const StartGameState.initial(), + ); + + await tester.pumpApp( + const StartGameListener( + child: SizedBox.shrink(), + ), + gameBloc: gameBloc, + startGameBloc: startGameBloc, + ); + + verifyNever(() => gameBloc.add(const GameStarted())); + verify(() => gameBloc.add(const GameRestarted())).called(1); + }, + ); + testWidgets( 'shows SelectCharacter dialog', (tester) async {