diff --git a/packages/pinball_components/test/helpers/mocks.dart b/packages/pinball_components/test/helpers/mocks.dart index 33c5670d..c20a2920 100644 --- a/packages/pinball_components/test/helpers/mocks.dart +++ b/packages/pinball_components/test/helpers/mocks.dart @@ -26,3 +26,5 @@ class MockSparkyBumperCubit extends Mock implements SparkyBumperCubit {} class MockDashNestBumperCubit extends Mock implements DashNestBumperCubit {} class MockMultiplierCubit extends Mock implements MultiplierCubit {} + +class MockKickerCubit extends Mock implements KickerCubit {} diff --git a/packages/pinball_components/test/src/components/golden/kickers.png b/packages/pinball_components/test/src/components/golden/kickers.png index 23176923..1b019de9 100644 Binary files a/packages/pinball_components/test/src/components/golden/kickers.png and b/packages/pinball_components/test/src/components/golden/kickers.png differ diff --git a/packages/pinball_components/test/src/components/kicker/behaviors/kicker_ball_contact_behavior_test.dart b/packages/pinball_components/test/src/components/kicker/behaviors/kicker_ball_contact_behavior_test.dart new file mode 100644 index 00000000..f169ae80 --- /dev/null +++ b/packages/pinball_components/test/src/components/kicker/behaviors/kicker_ball_contact_behavior_test.dart @@ -0,0 +1,48 @@ +// ignore_for_file: cascade_invocations + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(TestGame.new); + + group( + 'KickerBallContactBehavior', + () { + test('can be instantiated', () { + expect( + KickerBallContactBehavior(), + isA(), + ); + }); + + flameTester.test( + 'beginContact emits onBallContacted when contacts with a ball', + (game) async { + final behavior = KickerBallContactBehavior(); + final bloc = MockKickerCubit(); + whenListen( + bloc, + const Stream.empty(), + initialState: KickerState.lit, + ); + + final kicker = Kicker.test(bloc: bloc); + await kicker.add(behavior); + await game.ensureAdd(kicker); + + behavior.beginContact(MockBall(), MockContact()); + + verify(kicker.bloc.onBallContacted).called(1); + }, + ); + }, + ); +} diff --git a/packages/pinball_components/test/src/components/kicker/behaviors/kicker_blinking_behavior_test.dart b/packages/pinball_components/test/src/components/kicker/behaviors/kicker_blinking_behavior_test.dart new file mode 100644 index 00000000..724f1b2f --- /dev/null +++ b/packages/pinball_components/test/src/components/kicker/behaviors/kicker_blinking_behavior_test.dart @@ -0,0 +1,45 @@ +import 'dart:async'; + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(TestGame.new); + + group( + 'KickerBlinkingBehavior', + () { + flameTester.testGameWidget( + 'calls onBlinked after 0.05 seconds when dimmed', + setUp: (game, tester) async { + final behavior = KickerBlinkingBehavior(); + final bloc = MockKickerCubit(); + final streamController = StreamController(); + whenListen( + bloc, + streamController.stream, + initialState: KickerState.lit, + ); + + final kicker = Kicker.test(bloc: bloc); + await kicker.add(behavior); + await game.ensureAdd(kicker); + + streamController.add(KickerState.dimmed); + await tester.pump(); + game.update(0.05); + + await streamController.close(); + verify(bloc.onBlinked).called(1); + }, + ); + }, + ); +} diff --git a/packages/pinball_components/test/src/components/kicker/cubit/kicker_cubit_test.dart b/packages/pinball_components/test/src/components/kicker/cubit/kicker_cubit_test.dart new file mode 100644 index 00000000..ed1d4a46 --- /dev/null +++ b/packages/pinball_components/test/src/components/kicker/cubit/kicker_cubit_test.dart @@ -0,0 +1,24 @@ +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_components/pinball_components.dart'; + +void main() { + group( + 'KickerCubit', + () { + blocTest( + 'onBallContacted emits dimmed', + build: KickerCubit.new, + act: (bloc) => bloc.onBallContacted(), + expect: () => [KickerState.dimmed], + ); + + blocTest( + 'onBlinked emits lit', + build: KickerCubit.new, + act: (bloc) => bloc.onBlinked(), + expect: () => [KickerState.lit], + ); + }, + ); +} diff --git a/packages/pinball_components/test/src/components/kicker_test.dart b/packages/pinball_components/test/src/components/kicker_test.dart index aebf9380..30191db3 100644 --- a/packages/pinball_components/test/src/components/kicker_test.dart +++ b/packages/pinball_components/test/src/components/kicker_test.dart @@ -1,29 +1,42 @@ // ignore_for_file: cascade_invocations +import 'package:bloc_test/bloc_test.dart'; import 'package:flame/components.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_components/pinball_components.dart'; +import 'package:pinball_components/src/components/bumping_behavior.dart'; +import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart'; import '../../helpers/helpers.dart'; void main() { group('Kicker', () { - final flameTester = FlameTester(TestGame.new); + final assets = [ + Assets.images.kicker.left.lit.keyName, + Assets.images.kicker.left.dimmed.keyName, + Assets.images.kicker.right.lit.keyName, + Assets.images.kicker.right.dimmed.keyName, + ]; + final flameTester = FlameTester(() => TestGame(assets)); flameTester.testGameWidget( 'renders correctly', setUp: (game, tester) async { + await game.images.loadAll(assets); final leftKicker = Kicker( side: BoardSide.left, + bloc: KickerCubit(), )..initialPosition = Vector2(-20, 0); final rightKicker = Kicker( side: BoardSide.right, + bloc: KickerCubit(), )..initialPosition = Vector2(20, 0); await game.ensureAddAll([leftKicker, rightKicker]); game.camera.followVector2(Vector2.zero()); + await tester.pump(); }, verify: (game, tester) async { await expectLater( @@ -38,6 +51,7 @@ void main() { (game) async { final kicker = Kicker( side: BoardSide.left, + bloc: KickerCubit(), ); await game.ensureAdd(kicker); @@ -45,58 +59,73 @@ void main() { }, ); - flameTester.test('adds new children', (game) async { - final component = Component(); - final kicker = Kicker( - side: BoardSide.left, - children: [component], + // TODO(alestiago): Consider refactoring once the following is merged: + // https://github.com/flame-engine/flame/pull/1538 + // ignore: public_member_api_docs + flameTester.test('closes bloc when removed', (game) async { + final bloc = MockKickerCubit(); + whenListen( + bloc, + const Stream.empty(), + initialState: KickerState.lit, ); + when(bloc.close).thenAnswer((_) async {}); + final kicker = Kicker.test(bloc: bloc); + await game.ensureAdd(kicker); - expect(kicker.children, contains(component)); + game.remove(kicker); + await game.ready(); + + verify(bloc.close).called(1); }); - flameTester.test( - 'body is static', - (game) async { + group('adds', () { + flameTester.test('new children', (game) async { + final component = Component(); final kicker = Kicker( side: BoardSide.left, + children: [component], + bloc: KickerCubit(), ); await game.ensureAdd(kicker); + expect(kicker.children, contains(component)); + }); - expect(kicker.body.bodyType, equals(BodyType.static)); - }, - ); - - flameTester.test( - 'has restitution', - (game) async { + flameTester.test('a BumpingBehavior', (game) async { final kicker = Kicker( side: BoardSide.left, + bloc: KickerCubit(), ); await game.ensureAdd(kicker); - - final totalRestitution = kicker.body.fixtures.fold( - 0, - (total, fixture) => total + fixture.restitution, + expect( + kicker.children.whereType().single, + isNotNull, ); - expect(totalRestitution, greaterThan(0)); - }, - ); + }); - flameTester.test( - 'has no friction', - (game) async { + flameTester.test('a KickerBallContactBehavior', (game) async { final kicker = Kicker( side: BoardSide.left, + bloc: KickerCubit(), ); await game.ensureAdd(kicker); + expect( + kicker.children.whereType().single, + isNotNull, + ); + }); - final totalFriction = kicker.body.fixtures.fold( - 0, - (total, fixture) => total + fixture.friction, + flameTester.test('a KickerBlinkingBehavior', (game) async { + final kicker = Kicker( + side: BoardSide.left, + bloc: KickerCubit(), ); - expect(totalFriction, equals(0)); - }, - ); + await game.ensureAdd(kicker); + expect( + kicker.children.whereType().single, + isNotNull, + ); + }); + }); }); } diff --git a/test/game/components/bottom_group_test.dart b/test/game/components/bottom_group_test.dart index 3254f155..1d9e58ab 100644 --- a/test/game/components/bottom_group_test.dart +++ b/test/game/components/bottom_group_test.dart @@ -10,6 +10,10 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); final assets = [ + Assets.images.kicker.left.lit.keyName, + Assets.images.kicker.left.dimmed.keyName, + Assets.images.kicker.right.lit.keyName, + Assets.images.kicker.right.dimmed.keyName, Assets.images.baseboard.left.keyName, Assets.images.baseboard.right.keyName, Assets.images.flipper.left.keyName, diff --git a/test/game/pinball_game_test.dart b/test/game/pinball_game_test.dart index 41fb1812..ff99aa15 100644 --- a/test/game/pinball_game_test.dart +++ b/test/game/pinball_game_test.dart @@ -51,8 +51,10 @@ void main() { Assets.images.googleWord.letter4.keyName, Assets.images.googleWord.letter5.keyName, Assets.images.googleWord.letter6.keyName, - Assets.images.kicker.left.keyName, - Assets.images.kicker.right.keyName, + Assets.images.kicker.left.lit.keyName, + Assets.images.kicker.left.dimmed.keyName, + Assets.images.kicker.right.lit.keyName, + Assets.images.kicker.right.dimmed.keyName, Assets.images.launchRamp.ramp.keyName, Assets.images.launchRamp.foregroundRailing.keyName, Assets.images.launchRamp.backgroundRailing.keyName,