diff --git a/lib/game/bloc/game_bloc.dart b/lib/game/bloc/game_bloc.dart index 795d04e2..a21a9e6f 100644 --- a/lib/game/bloc/game_bloc.dart +++ b/lib/game/bloc/game_bloc.dart @@ -48,6 +48,7 @@ class GameBloc extends Bloc { } void _onIncreasedMultiplier(MultiplierIncreased event, Emitter emit) { + print("_onIncreasedMultiplier"); if (state.status.isPlaying) { emit( state.copyWith( diff --git a/lib/game/components/android_acres/behaviors/ramp_multiplier_behavior.dart b/lib/game/components/android_acres/behaviors/ramp_multiplier_behavior.dart index f3d537c4..f5f85663 100644 --- a/lib/game/components/android_acres/behaviors/ramp_multiplier_behavior.dart +++ b/lib/game/components/android_acres/behaviors/ramp_multiplier_behavior.dart @@ -35,6 +35,8 @@ class RampMultiplierBehavior extends Component with ParentIsA { return hasChanged && achievedFiveShots && canIncrease; }, onNewState: (state) { + print("onNewState $state"); + readBloc().add(const MultiplierIncreased()); }, ), diff --git a/packages/pinball_components/test/src/components/spaceship_ramp/behavior/ramp_arrow_blinking_behavior_test.dart b/packages/pinball_components/test/src/components/spaceship_ramp/behavior/ramp_arrow_blinking_behavior_test.dart index d259a170..cd225212 100644 --- a/packages/pinball_components/test/src/components/spaceship_ramp/behavior/ramp_arrow_blinking_behavior_test.dart +++ b/packages/pinball_components/test/src/components/spaceship_ramp/behavior/ramp_arrow_blinking_behavior_test.dart @@ -11,7 +11,6 @@ import 'package:mocktail/mocktail.dart'; import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/src/components/spaceship_ramp/behavior/ramp_arrow_blinking_behavior.dart'; import 'package:pinball_flame/pinball_flame.dart'; -import 'package:pinball_components/src/components/multiball/behaviors/behaviors.dart'; class _TestGame extends Forge2DGame { @override @@ -133,6 +132,9 @@ void main() { ); await streamController.close(); + + await game.ready(); + verify(bloc.onStop).called(1); }, ); @@ -168,6 +170,8 @@ void main() { behavior.onTick(); + await game.ready(); + expect(behavior.timer.isRunning(), false); }, ); @@ -205,6 +209,8 @@ void main() { behavior.onTick(); } + await game.ready(); + expect(behavior.timer.isRunning(), false); }, ); diff --git a/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_isolatedDiff.png b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_isolatedDiff.png new file mode 100644 index 00000000..9336b99e Binary files /dev/null and b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_isolatedDiff.png differ diff --git a/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_maskedDiff.png b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_maskedDiff.png new file mode 100644 index 00000000..cab2c9ba Binary files /dev/null and b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_maskedDiff.png differ diff --git a/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_masterImage.png b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_masterImage.png new file mode 100644 index 00000000..597b1b66 Binary files /dev/null and b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_masterImage.png differ diff --git a/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_testImage.png b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_testImage.png new file mode 100644 index 00000000..e403c805 Binary files /dev/null and b/packages/pinball_components/test/src/components/spaceship_ramp/failures/active5_testImage.png differ diff --git a/packages/pinball_components/test/src/components/spaceship_ramp/spaceship_ramp_test.dart b/packages/pinball_components/test/src/components/spaceship_ramp/spaceship_ramp_test.dart index 614ad718..779e243f 100644 --- a/packages/pinball_components/test/src/components/spaceship_ramp/spaceship_ramp_test.dart +++ b/packages/pinball_components/test/src/components/spaceship_ramp/spaceship_ramp_test.dart @@ -1,7 +1,10 @@ -// ignore_for_file: cascade_invocations +// ignore_for_file: cascade_invocations, prefer_const_constructors + +import 'dart:async'; import 'package:bloc_test/bloc_test.dart'; import 'package:flame/components.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'; @@ -10,7 +13,38 @@ import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/src/components/spaceship_ramp/behavior/behavior.dart'; import 'package:pinball_flame/pinball_flame.dart'; -import '../../../helpers/helpers.dart'; +class _TestGame extends Forge2DGame { + @override + Future onLoad() async { + images.prefix = ''; + await images.loadAll([ + Assets.images.android.ramp.boardOpening.keyName, + Assets.images.android.ramp.railingForeground.keyName, + Assets.images.android.ramp.railingBackground.keyName, + Assets.images.android.ramp.main.keyName, + Assets.images.android.ramp.arrow.inactive.keyName, + Assets.images.android.ramp.arrow.active1.keyName, + Assets.images.android.ramp.arrow.active2.keyName, + Assets.images.android.ramp.arrow.active3.keyName, + Assets.images.android.ramp.arrow.active4.keyName, + Assets.images.android.ramp.arrow.active5.keyName, + ]); + } + + Future pump( + SpaceshipRamp child, { + required SpaceshipRampCubit spaceshipRampCubit, + }) async { + await ensureAdd( + FlameBlocProvider.value( + value: spaceshipRampCubit, + children: [ + ZCanvasComponent(children: [child]), + ], + ), + ); + } +} class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {} @@ -34,18 +68,100 @@ void main() { Assets.images.android.ramp.arrow.active4.keyName, Assets.images.android.ramp.arrow.active5.keyName, ]; - final flameTester = FlameTester(() => TestGame(assets)); + + final flameTester = FlameTester(_TestGame.new); group('SpaceshipRamp', () { flameTester.test( 'loads correctly', (game) async { - final spaceshipRamp = SpaceshipRamp(); - await game.ensureAdd(spaceshipRamp); - expect(game.children, contains(spaceshipRamp)); + final bloc = _MockSpaceshipRampCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: SpaceshipRampState.initial(), + ); + final ramp = SpaceshipRamp(); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); + expect(game.descendants(), contains(ramp)); }, ); + group('loads', () { + flameTester.test( + 'a SpaceshipRampBoardOpening', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: SpaceshipRampState.initial(), + ); + final ramp = SpaceshipRamp(); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); + expect( + game.descendants().whereType().length, + equals(1), + ); + }, + ); + + flameTester.test( + 'a SpaceshipRampArrowSpriteComponent', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: SpaceshipRampState.initial(), + ); + final ramp = SpaceshipRamp(); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); + expect( + game + .descendants() + .whereType() + .length, + equals(1), + ); + }, + ); + + flameTester.test( + 'a RampArrowBlinkingBehavior', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: SpaceshipRampState.initial(), + ); + final ramp = SpaceshipRamp(); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); + expect( + game.descendants().whereType().length, + equals(1), + ); + }, + ); + }); + group('renders correctly', () { const goldenFilePath = '../golden/spaceship_ramp/'; final centerForSpaceshipRamp = Vector2(-13, -55); @@ -54,26 +170,35 @@ void main() { 'inactive sprite', setUp: (game, tester) async { await game.images.loadAll(assets); + final bloc = _MockSpaceshipRampCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: SpaceshipRampState.initial(), + ); final ramp = SpaceshipRamp(); - final canvas = ZCanvasComponent(children: [ramp]); - await game.ensureAdd(canvas); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); await tester.pump(); - final index = ramp.children + final current = ramp.children .whereType() .first .current; expect( - SpaceshipRampArrowSpriteState.values[index!], - SpaceshipRampArrowSpriteState.inactive, + current, + ArrowLightState.inactive, ); game.camera.followVector2(centerForSpaceshipRamp); }, verify: (game, tester) async { await expectLater( - find.byGame(), + find.byGame<_TestGame>(), matchesGoldenFile('${goldenFilePath}inactive.png'), ); }, @@ -83,29 +208,41 @@ void main() { 'active1 sprite', setUp: (game, tester) async { await game.images.loadAll(assets); + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); final ramp = SpaceshipRamp(); - final canvas = ZCanvasComponent(children: [ramp]); - await game.ensureAdd(canvas); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); - ramp.bloc.onAscendingBallEntered(); + streamController.add( + state.copyWith(lightState: ArrowLightState.active1), + ); await game.ready(); await tester.pump(); - final index = ramp.children + final current = ramp.children .whereType() .first .current; expect( - SpaceshipRampArrowSpriteState.values[index!], - SpaceshipRampArrowSpriteState.active1, + current, + ArrowLightState.active1, ); game.camera.followVector2(centerForSpaceshipRamp); }, verify: (game, tester) async { await expectLater( - find.byGame(), + find.byGame<_TestGame>(), matchesGoldenFile('${goldenFilePath}active1.png'), ); }, @@ -115,31 +252,41 @@ void main() { 'active2 sprite', setUp: (game, tester) async { await game.images.loadAll(assets); + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); final ramp = SpaceshipRamp(); - final canvas = ZCanvasComponent(children: [ramp]); - await game.ensureAdd(canvas); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); - ramp.bloc - ..onAscendingBallEntered() - ..onAscendingBallEntered(); + streamController.add( + state.copyWith(lightState: ArrowLightState.active2), + ); await game.ready(); await tester.pump(); - final index = ramp.children + final current = ramp.children .whereType() .first .current; expect( - SpaceshipRampArrowSpriteState.values[index!], - SpaceshipRampArrowSpriteState.active2, + current, + ArrowLightState.active2, ); game.camera.followVector2(centerForSpaceshipRamp); }, verify: (game, tester) async { await expectLater( - find.byGame(), + find.byGame<_TestGame>(), matchesGoldenFile('${goldenFilePath}active2.png'), ); }, @@ -149,32 +296,41 @@ void main() { 'active3 sprite', setUp: (game, tester) async { await game.images.loadAll(assets); + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); final ramp = SpaceshipRamp(); - final canvas = ZCanvasComponent(children: [ramp]); - await game.ensureAdd(canvas); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); - ramp.bloc - ..onAscendingBallEntered() - ..onAscendingBallEntered() - ..onAscendingBallEntered(); + streamController.add( + state.copyWith(lightState: ArrowLightState.active3), + ); await game.ready(); await tester.pump(); - final index = ramp.children + final current = ramp.children .whereType() .first .current; expect( - SpaceshipRampArrowSpriteState.values[index!], - SpaceshipRampArrowSpriteState.active3, + current, + ArrowLightState.active3, ); game.camera.followVector2(centerForSpaceshipRamp); }, verify: (game, tester) async { await expectLater( - find.byGame(), + find.byGame<_TestGame>(), matchesGoldenFile('${goldenFilePath}active3.png'), ); }, @@ -184,33 +340,41 @@ void main() { 'active4 sprite', setUp: (game, tester) async { await game.images.loadAll(assets); + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); final ramp = SpaceshipRamp(); - final canvas = ZCanvasComponent(children: [ramp]); - await game.ensureAdd(canvas); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); - ramp.bloc - ..onAscendingBallEntered() - ..onAscendingBallEntered() - ..onAscendingBallEntered() - ..onAscendingBallEntered(); + streamController.add( + state.copyWith(lightState: ArrowLightState.active4), + ); await game.ready(); await tester.pump(); - final index = ramp.children + final current = ramp.children .whereType() .first .current; expect( - SpaceshipRampArrowSpriteState.values[index!], - SpaceshipRampArrowSpriteState.active4, + current, + ArrowLightState.active4, ); game.camera.followVector2(centerForSpaceshipRamp); }, verify: (game, tester) async { await expectLater( - find.byGame(), + find.byGame<_TestGame>(), matchesGoldenFile('${goldenFilePath}active4.png'), ); }, @@ -220,63 +384,62 @@ void main() { 'active5 sprite', setUp: (game, tester) async { await game.images.loadAll(assets); + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); final ramp = SpaceshipRamp(); - final canvas = ZCanvasComponent(children: [ramp]); - await game.ensureAdd(canvas); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); - ramp.bloc - ..onAscendingBallEntered() - ..onAscendingBallEntered() - ..onAscendingBallEntered() - ..onAscendingBallEntered() - ..onAscendingBallEntered(); + streamController.add( + state.copyWith(lightState: ArrowLightState.active5), + ); await game.ready(); await tester.pump(); - final index = ramp.children + final current = ramp.children .whereType() .first .current; expect( - SpaceshipRampArrowSpriteState.values[index!], - SpaceshipRampArrowSpriteState.active5, + current, + ArrowLightState.active5, ); game.camera.followVector2(centerForSpaceshipRamp); }, verify: (game, tester) async { await expectLater( - find.byGame(), + find.byGame<_TestGame>(), matchesGoldenFile('${goldenFilePath}active5.png'), ); }, ); }); - flameTester.test('closes bloc when removed', (game) async { - final bloc = _MockSpaceshipRampCubit(); - whenListen( - bloc, - const Stream.empty(), - initialState: const SpaceshipRampState.initial(), - ); - when(bloc.close).thenAnswer((_) async {}); - - final ramp = SpaceshipRamp.test(); - - await game.ensureAdd(ramp); - game.remove(ramp); - await game.ready(); - - verify(bloc.close).called(1); - }); - group('adds', () { flameTester.test('new children', (game) async { + final bloc = _MockSpaceshipRampCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: SpaceshipRampState.initial(), + ); final component = Component(); final ramp = SpaceshipRamp(children: [component]); - await game.ensureAdd(ramp); + await game.pump( + ramp, + spaceshipRampCubit: bloc, + ); expect(ramp.children, contains(component)); }); }); @@ -330,18 +493,24 @@ void main() { }); flameTester.test('can be loaded', (game) async { - final parent = SpaceshipRamp.test(); final component = SpaceshipRampBoardOpening(); - await game.ensureAdd(parent); + final parent = SpaceshipRamp.test(); + await game.pump( + parent, + spaceshipRampCubit: _MockSpaceshipRampCubit(), + ); await parent.ensureAdd(component); expect(parent.children, contains(component)); }); flameTester.test('adds a RampBallAscendingContactBehavior', (game) async { - final parent = SpaceshipRamp.test(); final component = SpaceshipRampBoardOpening(); - await game.ensureAdd(parent); - await parent.ensureAdd(component); + final ramp = SpaceshipRamp.test(); + await game.pump( + ramp, + spaceshipRampCubit: _MockSpaceshipRampCubit(), + ); + await ramp.ensureAdd(component); expect( component.children.whereType().length, equals(1), diff --git a/test/game/components/android_acres/behaviors/ramp_multiplier_behavior_test.dart b/test/game/components/android_acres/behaviors/ramp_multiplier_behavior_test.dart index 507ece72..7430841a 100644 --- a/test/game/components/android_acres/behaviors/ramp_multiplier_behavior_test.dart +++ b/test/game/components/android_acres/behaviors/ramp_multiplier_behavior_test.dart @@ -59,8 +59,6 @@ class _MockGameBloc extends Mock implements GameBloc {} class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {} -class _FakeGameState extends Fake implements GameState {} - class _FakeGameEvent extends Fake implements GameEvent {} void main() { @@ -70,7 +68,6 @@ void main() { late GameBloc gameBloc; setUp(() { - registerFallbackValue(_FakeGameState()); registerFallbackValue(_FakeGameEvent()); gameBloc = _MockGameBloc(); }); @@ -82,7 +79,6 @@ void main() { 'when hits are multiples of 5 times and multiplier is less than 6', (game) async { final bloc = _MockSpaceshipRampCubit(); - final event = MultiplierIncreased(); final state = SpaceshipRampState.initial(); final streamController = StreamController(); whenListen( @@ -95,7 +91,7 @@ void main() { multiplier: 5, ), ); - when(() => gameBloc.add(event)).thenAnswer((_) async {}); + when(() => gameBloc.add(any())).thenAnswer((_) async {}); final behavior = RampMultiplierBehavior(); final parent = SpaceshipRamp.test(); @@ -109,7 +105,9 @@ void main() { streamController.add(state.copyWith(hits: 5)); - verify(() => gameBloc.add(event)).called(1); + await game.ready(); + + verify(() => gameBloc.add(const MultiplierIncreased())).called(1); }, ); @@ -143,6 +141,8 @@ void main() { streamController.add(state.copyWith(hits: 5)); + await game.ready(); + verifyNever(() => gameBloc.add(const MultiplierIncreased())); }, ); @@ -177,6 +177,8 @@ void main() { streamController.add(state.copyWith(hits: 1)); + await game.ready(); + verifyNever(() => gameBloc.add(const MultiplierIncreased())); }, ); diff --git a/test/game/components/android_acres/behaviors/ramp_progress_behavior_test.dart b/test/game/components/android_acres/behaviors/ramp_progress_behavior_test.dart new file mode 100644 index 00000000..bdd5414b --- /dev/null +++ b/test/game/components/android_acres/behaviors/ramp_progress_behavior_test.dart @@ -0,0 +1,310 @@ +// ignore_for_file: cascade_invocations, prefer_const_constructors + +import 'dart:async'; + +import 'package:bloc_test/bloc_test.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/components/android_acres/behaviors/behaviors.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +class _TestGame extends Forge2DGame { + @override + Future onLoad() async { + images.prefix = ''; + await images.loadAll([ + Assets.images.android.ramp.boardOpening.keyName, + Assets.images.android.ramp.railingForeground.keyName, + Assets.images.android.ramp.railingBackground.keyName, + Assets.images.android.ramp.main.keyName, + Assets.images.android.ramp.arrow.inactive.keyName, + Assets.images.android.ramp.arrow.active1.keyName, + Assets.images.android.ramp.arrow.active2.keyName, + Assets.images.android.ramp.arrow.active3.keyName, + Assets.images.android.ramp.arrow.active4.keyName, + Assets.images.android.ramp.arrow.active5.keyName, + Assets.images.android.rail.main.keyName, + Assets.images.android.rail.exit.keyName, + Assets.images.score.fiveThousand.keyName, + ]); + } + + Future pump( + SpaceshipRamp child, { + required SpaceshipRampCubit spaceshipRampCubit, + required GameBloc gameBloc, + }) async { + await ensureAdd( + FlameBlocProvider.value( + value: gameBloc, + children: [ + FlameBlocProvider.value( + value: spaceshipRampCubit, + children: [ + ZCanvasComponent(children: [child]), + ], + ), + ], + ), + ); + } +} + +class _MockGameBloc extends Mock implements GameBloc {} + +class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {} + +class _FakeGameEvent extends Fake implements GameEvent {} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('RampProgressBehavior', () { + late GameBloc gameBloc; + + setUp(() { + registerFallbackValue(_FakeGameEvent()); + gameBloc = _MockGameBloc(); + }); + + final flameTester = FlameTester(_TestGame.new); + + flameTester.test( + 'adds onProgressed ' + 'when hits and multiplier is less than 6', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); + when(() => gameBloc.state).thenReturn( + GameState.initial().copyWith( + multiplier: 1, + ), + ); + + final behavior = RampProgressBehavior(); + final parent = SpaceshipRamp.test(); + + await game.pump( + parent, + gameBloc: gameBloc, + spaceshipRampCubit: bloc, + ); + await parent.ensureAdd(behavior); + + streamController.add(state.copyWith(hits: 5)); + + await game.ready(); + + verify(bloc.onProgressed).called(1); + }, + ); + + flameTester.test( + 'adds onProgressed ' + 'when hits and multiplier is 6 but arrow is not full lit', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); + when(() => gameBloc.state).thenReturn( + GameState.initial().copyWith( + multiplier: 6, + ), + ); + + final behavior = RampProgressBehavior(); + final parent = SpaceshipRamp.test(); + + await game.pump( + parent, + gameBloc: gameBloc, + spaceshipRampCubit: bloc, + ); + await parent.ensureAdd(behavior); + + streamController.add(state.copyWith(hits: 5)); + + await game.ready(); + + verify(bloc.onProgressed).called(1); + }, + ); + + flameTester.test( + "doesn't add onProgressed " + 'when hits and multiplier is 6 and arrow is full lit', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); + when(() => gameBloc.state).thenReturn( + GameState.initial().copyWith( + multiplier: 6, + ), + ); + + final behavior = RampProgressBehavior(); + final parent = SpaceshipRamp.test(); + + await game.pump( + parent, + gameBloc: gameBloc, + spaceshipRampCubit: bloc, + ); + await parent.ensureAdd(behavior); + + streamController.add( + state.copyWith( + hits: 5, + lightState: ArrowLightState.active5, + ), + ); + + await game.ready(); + + verifyNever(bloc.onProgressed); + }, + ); + + flameTester.test( + 'adds onAnimate ' + 'when arrow is full lit after hit and multiplier is less than 6', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); + when(() => gameBloc.state).thenReturn( + GameState.initial().copyWith( + multiplier: 5, + ), + ); + + final behavior = RampProgressBehavior(); + final parent = SpaceshipRamp.test(); + + await game.pump( + parent, + gameBloc: gameBloc, + spaceshipRampCubit: bloc, + ); + await parent.ensureAdd(behavior); + + streamController.add( + state.copyWith( + hits: 5, + lightState: ArrowLightState.active5, + ), + ); + + await game.ready(); + + verify(bloc.onAnimate).called(1); + }, + ); + + flameTester.test( + "doesn't add onAnimate " + 'when arrow is not full lit after hit', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); + when(() => gameBloc.state).thenReturn( + GameState.initial().copyWith( + multiplier: 5, + ), + ); + + final behavior = RampProgressBehavior(); + final parent = SpaceshipRamp.test(); + + await game.pump( + parent, + gameBloc: gameBloc, + spaceshipRampCubit: bloc, + ); + await parent.ensureAdd(behavior); + + streamController.add( + state.copyWith( + hits: 4, + lightState: ArrowLightState.active4, + ), + ); + + await game.ready(); + + verifyNever(bloc.onAnimate); + }, + ); + + flameTester.test( + "doesn't add onAnimate " + 'when multiplier is 6 after hit', + (game) async { + final bloc = _MockSpaceshipRampCubit(); + final state = SpaceshipRampState.initial(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: state, + ); + when(() => gameBloc.state).thenReturn( + GameState.initial().copyWith( + multiplier: 6, + ), + ); + + final behavior = RampProgressBehavior(); + final parent = SpaceshipRamp.test(); + + await game.pump( + parent, + gameBloc: gameBloc, + spaceshipRampCubit: bloc, + ); + await parent.ensureAdd(behavior); + + streamController.add( + state.copyWith(hits: 4), + ); + + await game.ready(); + + verifyNever(bloc.onAnimate); + }, + ); + }); +}