From 651dab96548837818c93e4eb0c34f1a4430aacda Mon Sep 17 00:00:00 2001 From: Allison Ryan Date: Tue, 3 May 2022 15:53:36 -0500 Subject: [PATCH] test: initials input display --- lib/game/components/backbox/backbox.dart | 4 +- lib/game/components/game_flow_controller.dart | 2 +- .../lib/src/components/z_indexes.dart | 4 +- .../game/components/backbox/backbox_test.dart | 53 +++++-- .../displays/initials_input_display_test.dart | 147 ++++++++++++++++-- .../components/game_flow_controller_test.dart | 3 +- test/helpers/test_games.dart | 23 +++ 7 files changed, 206 insertions(+), 30 deletions(-) diff --git a/lib/game/components/backbox/backbox.dart b/lib/game/components/backbox/backbox.dart index c23b56db..0ef85fba 100644 --- a/lib/game/components/backbox/backbox.dart +++ b/lib/game/components/backbox/backbox.dart @@ -18,7 +18,7 @@ class Backbox extends PositionComponent with HasGameRef, ZIndex { _BackboxSpriteComponent(), ], ) { - zIndex = ZIndexes.backboardMarquee; + zIndex = ZIndexes.backbox; } /// Puts [InitialsInputDisplay] on the [Backbox]. @@ -27,7 +27,7 @@ class Backbox extends PositionComponent with HasGameRef, ZIndex { required String characterIconPath, InitialsOnSubmit? onSubmit, }) async { - removeAll(children); + removeAll(children.where((child) => child is! _BackboxSpriteComponent)); await add( InitialsInputDisplay( score: score, diff --git a/lib/game/components/game_flow_controller.dart b/lib/game/components/game_flow_controller.dart index af4343fa..73d8be2b 100644 --- a/lib/game/components/game_flow_controller.dart +++ b/lib/game/components/game_flow_controller.dart @@ -29,7 +29,7 @@ class GameFlowController extends ComponentController void initialsInput() { // TODO(erickzanardo): implement score submission and "navigate" to the // next page - component.firstChild()?.initialsInput( + component.descendants().whereType().first.initialsInput( score: state?.score ?? 0, characterIconPath: component.characterTheme.leaderboardIcon.keyName, ); diff --git a/packages/pinball_components/lib/src/components/z_indexes.dart b/packages/pinball_components/lib/src/components/z_indexes.dart index d820fb5b..be934abd 100644 --- a/packages/pinball_components/lib/src/components/z_indexes.dart +++ b/packages/pinball_components/lib/src/components/z_indexes.dart @@ -111,7 +111,7 @@ abstract class ZIndexes { static const debugInfo = _above + score; - // Backboard + // Backbox - static const backboardMarquee = _below + outerBoundary; + static const backbox = _below + outerBoundary; } diff --git a/test/game/components/backbox/backbox_test.dart b/test/game/components/backbox/backbox_test.dart index d760577b..a8e75a0f 100644 --- a/test/game/components/backbox/backbox_test.dart +++ b/test/game/components/backbox/backbox_test.dart @@ -3,24 +3,55 @@ import 'package:flame/components.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/backbox/displays/initials_input_display.dart'; import 'package:pinball/game/game.dart'; +import 'package:pinball/l10n/l10n.dart'; import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_theme/pinball_theme.dart' as theme; import '../../../helpers/helpers.dart'; +class _MockAppLocalizations extends Mock implements AppLocalizations { + @override + String get score => ''; + + @override + String get name => ''; + + @override + String get enterInitials => ''; + + @override + String get arrows => ''; + + @override + String get andPress => ''; + + @override + String get enterReturn => ''; + + @override + String get toSubmit => ''; +} + void main() { - group('Backbox', () { - final characterIconPath = theme.Assets.images.dash.leaderboardIcon.keyName; - final assets = [ - characterIconPath, - Assets.images.backbox.marquee.keyName, - Assets.images.backbox.displayDivider.keyName, - ]; - final tester = FlameTester(() => EmptyPinballTestGame(assets: assets)); + TestWidgetsFlutterBinding.ensureInitialized(); + final characterIconPath = theme.Assets.images.dash.leaderboardIcon.keyName; + final assets = [ + characterIconPath, + Assets.images.backbox.marquee.keyName, + Assets.images.backbox.displayDivider.keyName, + ]; + final flameTester = FlameTester( + () => EmptyPinballTestGame( + assets: assets, + l10n: _MockAppLocalizations(), + ), + ); - tester.test( + group('Backbox', () { + flameTester.test( 'loads correctly', (game) async { final backbox = Backbox(); @@ -31,7 +62,7 @@ void main() { ); group('renders correctly', () { - tester.testGameWidget( + flameTester.testGameWidget( 'empty', setUp: (game, tester) async { await game.images.loadAll(assets); @@ -50,7 +81,7 @@ void main() { ); }); - tester.test( + flameTester.test( 'initialsInput adds InitialsInputDisplay', (game) async { final backbox = Backbox(); diff --git a/test/game/components/backbox/displays/initials_input_display_test.dart b/test/game/components/backbox/displays/initials_input_display_test.dart index c4596376..353b1d19 100644 --- a/test/game/components/backbox/displays/initials_input_display_test.dart +++ b/test/game/components/backbox/displays/initials_input_display_test.dart @@ -1,6 +1,9 @@ // ignore_for_file: cascade_invocations +import 'package:flame/components.dart'; import 'package:flame_test/flame_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:pinball/game/components/backbox/displays/initials_input_display.dart'; @@ -34,22 +37,24 @@ class _MockAppLocalizations extends Mock implements AppLocalizations { } void main() { - group('InitialsInputDisplay', () { - final characterIconPath = theme.Assets.images.dash.leaderboardIcon.keyName; - final assets = [ - characterIconPath, - Assets.images.backbox.displayDivider.keyName, - ]; - final tester = FlameTester( - () => EmptyPinballTestGame( - assets: assets, - l10n: _MockAppLocalizations(), - ), - ); + TestWidgetsFlutterBinding.ensureInitialized(); + final characterIconPath = theme.Assets.images.dash.leaderboardIcon.keyName; + final assets = [ + characterIconPath, + Assets.images.backbox.displayDivider.keyName, + ]; + final flameTester = FlameTester( + () => EmptyKeyboardPinballTestGame( + assets: assets, + l10n: _MockAppLocalizations(), + ), + ); - tester.test( + group('InitialsInputDisplay', () { + flameTester.test( 'loads correctly', (game) async { + await game.images.loadAll(assets); final initialsInputDisplay = InitialsInputDisplay( score: 0, characterIconPath: characterIconPath, @@ -60,5 +65,121 @@ void main() { expect(game.children, contains(initialsInputDisplay)); }, ); + + flameTester.testGameWidget( + 'can change the initials', + setUp: (game, tester) async { + final initialsInputDisplay = InitialsInputDisplay( + score: 1000, + characterIconPath: characterIconPath, + onSubmit: (_) {}, + ); + await game.ensureAdd(initialsInputDisplay); + + // Focus is already on the first letter + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + + // Move to the next an press up again + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + + // One more time + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + + // Back to the previous and increase one more + await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + }, + verify: (game, tester) async { + final initialsInputDisplay = + game.descendants().whereType().single; + + expect(initialsInputDisplay.initials, equals('BCB')); + }, + ); + + String? submitedInitials; + flameTester.testGameWidget( + 'submits the initials', + setUp: (game, tester) async { + final initialsInputDisplay = InitialsInputDisplay( + score: 1000, + characterIconPath: characterIconPath, + onSubmit: (value) { + submitedInitials = value; + }, + ); + await game.ensureAdd(initialsInputDisplay); + + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + await tester.pump(); + }, + verify: (game, tester) async { + expect(submitedInitials, equals('AAA')); + }, + ); + + group('BackboardLetterPrompt', () { + flameTester.testGameWidget( + 'cycles the char up and down when it has focus', + setUp: (game, tester) async { + await game.ensureAdd( + InitialsLetterPrompt(hasFocus: true, position: Vector2.zero()), + ); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); + await tester.pump(); + }, + verify: (game, tester) async { + final prompt = game.firstChild(); + expect(prompt?.char, equals('C')); + }, + ); + + flameTester.testGameWidget( + "does nothing when it doesn't have focus", + setUp: (game, tester) async { + await game.ensureAdd( + InitialsLetterPrompt(position: Vector2.zero()), + ); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pump(); + }, + verify: (game, tester) async { + final prompt = game.firstChild(); + expect(prompt?.char, equals('A')); + }, + ); + + flameTester.testGameWidget( + 'blinks the prompt when it has the focus', + setUp: (game, tester) async { + await game.ensureAdd( + InitialsLetterPrompt(position: Vector2.zero(), hasFocus: true), + ); + }, + verify: (game, tester) async { + final underscore = + game.descendants().whereType().first; + expect(underscore.paint.color, Colors.white); + + game.update(2); + expect(underscore.paint.color, Colors.transparent); + }, + ); + }); }); } diff --git a/test/game/components/game_flow_controller_test.dart b/test/game/components/game_flow_controller_test.dart index 7feeb021..c7196057 100644 --- a/test/game/components/game_flow_controller_test.dart +++ b/test/game/components/game_flow_controller_test.dart @@ -65,7 +65,8 @@ void main() { when(() => overlays.remove(any())).thenAnswer((_) => true); - when(game.firstChild).thenReturn(backbox); + when(() => game.descendants().whereType()) + .thenReturn([backbox]); when(game.firstChild).thenReturn(cameraController); when(() => game.overlays).thenReturn(overlays); when(() => game.characterTheme).thenReturn(DashTheme()); diff --git a/test/helpers/test_games.dart b/test/helpers/test_games.dart index 7041a2e7..aa1ef777 100644 --- a/test/helpers/test_games.dart +++ b/test/helpers/test_games.dart @@ -2,6 +2,7 @@ import 'dart:async'; +import 'package:flame/input.dart'; import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:mocktail/mocktail.dart'; @@ -87,3 +88,25 @@ class EmptyPinballTestGame extends PinballTestGame { } } } + +class EmptyKeyboardPinballTestGame extends PinballTestGame + with HasKeyboardHandlerComponents { + EmptyKeyboardPinballTestGame({ + List? assets, + PinballAudio? audio, + CharacterTheme? theme, + AppLocalizations? l10n, + }) : super( + assets: assets, + audio: audio, + theme: theme, + l10n: l10n ?? _MockAppLocalizations(), + ); + + @override + Future onLoad() async { + if (_assets != null) { + await images.loadAll(_assets!); + } + } +}