Skip to content

Commit

Permalink
refactor: move CrosswordPlayingView to its own file (#507)
Browse files Browse the repository at this point in the history
* refactor: move CrosswordPlayingView to its own file

* test: update test name

* Update lib/crossword/view/crossword_playing_view.dart

---------

Co-authored-by: Jaime <52668514+jsgalarraga@users.noreply.github.com>
  • Loading branch information
alestiago and jsgalarraga authored May 21, 2024
1 parent b62cbd4 commit 5f85383
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 66 deletions.
30 changes: 1 addition & 29 deletions lib/crossword/view/crossword_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:game_domain/game_domain.dart';
import 'package:io_crossword/audio/audio.dart';
import 'package:io_crossword/board_status/board_status.dart';
import 'package:io_crossword/bottom_bar/bottom_bar.dart';
import 'package:io_crossword/crossword/crossword.dart';
import 'package:io_crossword/drawer/drawer.dart';
import 'package:io_crossword/l10n/l10n.dart';
Expand Down Expand Up @@ -179,7 +178,7 @@ class _CrosswordViewState extends State<CrosswordView>
} else if (status == CrosswordStatus.ready) {
return FadeInAnimation(
onComplete: _controller.playNext,
child: const LoadedBoardView(),
child: const CrosswordPlayingView(),
);
} else {
return const SizedBox.shrink();
Expand Down Expand Up @@ -229,33 +228,6 @@ class _CrosswordViewState extends State<CrosswordView>
}
}

@visibleForTesting
class LoadedBoardView extends StatelessWidget {
@visibleForTesting
const LoadedBoardView({super.key});

@override
Widget build(BuildContext context) {
return DefaultWordInputController(
child: Stack(
children: [
BlocSelector<CrosswordBloc, CrosswordState, bool>(
selector: (state) => state.mascotVisible,
builder: (context, mascotVisible) {
return IgnorePointer(
ignoring: mascotVisible,
child: const CrosswordBoardView(),
);
},
),
const BottomBar(),
const WordSelectionPage(),
],
),
);
}
}

class MascotAnimation extends StatelessWidget {
@visibleForTesting
const MascotAnimation(
Expand Down
36 changes: 36 additions & 0 deletions lib/crossword/view/crossword_playing_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:io_crossword/bottom_bar/bottom_bar.dart';
import 'package:io_crossword/crossword/crossword.dart';
import 'package:io_crossword/word_selection/word_selection.dart';

/// {@template crossword_playing_view}
/// Displays the crossword, in its playing state.
///
/// The user cannot interact with the crossword while the mascot animation is
/// playing.
/// {@endtemplate}
class CrosswordPlayingView extends StatelessWidget {
const CrosswordPlayingView({super.key});

@override
Widget build(BuildContext context) {
return DefaultWordInputController(
child: Stack(
children: [
BlocSelector<CrosswordBloc, CrosswordState, bool>(
selector: (state) => state.mascotVisible,
builder: (context, mascotVisible) {
return IgnorePointer(
ignoring: mascotVisible,
child: const CrosswordBoardView(),
);
},
),
const BottomBar(),
const WordSelectionPage(),
],
),
);
}
}
1 change: 1 addition & 0 deletions lib/crossword/view/view.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export 'crossword_board_view.dart';
export 'crossword_page.dart';
export 'crossword_playing_view.dart';
62 changes: 25 additions & 37 deletions test/crossword/view/crossword_page_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,51 +287,39 @@ void main() {
expect(find.byType(ErrorView), findsOneWidget);
});

testWidgets('renders $CrosswordBoardView with ${CrosswordStatus.ready}',
(tester) async {
when(() => crosswordBloc.state).thenReturn(
const CrosswordState(
status: CrosswordStatus.ready,
),
);

await tester.pumpSubject(
crosswordBloc: crosswordBloc,
CrosswordView(),
);

expect(find.byType(CrosswordBoardView), findsOneWidget);
});
group('$CrosswordPlayingView', () {
testWidgets('renders when ${CrosswordStatus.ready}', (tester) async {
when(() => crosswordBloc.state).thenReturn(
const CrosswordState(status: CrosswordStatus.ready),
);

testWidgets(
'does not render $WordSelectionPage when loaded',
(tester) async {
await tester.pumpSubject(
CrosswordView(),
crosswordBloc: crosswordBloc,
CrosswordView(),
);

expect(find.byType(WordSelectionPage), findsNothing);
},
);
expect(find.byType(CrosswordPlayingView), findsOneWidget);
});

testWidgets(
'renders $BottomBar',
(tester) async {
when(() => crosswordBloc.state).thenReturn(
const CrosswordState(
status: CrosswordStatus.ready,
),
);
for (final crosswordStatus in CrosswordStatus.values.toSet()
..remove(CrosswordStatus.ready)) {
testWidgets(
'''does not render $CrosswordPlayingView when status is $crosswordStatus''',
(tester) async {
when(() => crosswordBloc.state).thenReturn(
CrosswordState(status: crosswordStatus),
);

await tester.pumpSubject(
CrosswordView(),
crosswordBloc: crosswordBloc,
);
await tester.pumpSubject(
CrosswordView(),
crosswordBloc: crosswordBloc,
);

expect(find.byType(BottomBar), findsOneWidget);
},
);
expect(find.byType(CrosswordPlayingView), findsNothing);
},
);
}
});

for (final layout in IoLayoutData.values) {
testWidgets(
Expand Down
132 changes: 132 additions & 0 deletions test/crossword/view/crossword_playing_view_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter/widgets.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/board_status/board_status.dart';
import 'package:io_crossword/bottom_bar/bottom_bar.dart';
import 'package:io_crossword/crossword/crossword.dart';
import 'package:io_crossword/player/player.dart';
import 'package:io_crossword/random_word_selection/random_word_selection.dart';
import 'package:io_crossword/word_selection/word_selection.dart';
import 'package:io_crossword_ui/io_crossword_ui.dart';
import 'package:mocktail/mocktail.dart';

import '../../helpers/helpers.dart';

class _MockCrosswordBloc extends MockBloc<CrosswordEvent, CrosswordState>
implements CrosswordBloc {}

class _MockPlayerBloc extends MockBloc<PlayerEvent, PlayerState>
implements PlayerBloc {}

class _MockWordSelectionBloc
extends MockBloc<WordSelectionEvent, WordSelectionState>
implements WordSelectionBloc {}

class _MockRandomWordSelectionBloc
extends MockBloc<RandomWordSelectionEvent, RandomWordSelectionState>
implements RandomWordSelectionBloc {}

class _MockBoardStatusBloc extends MockBloc<BoardStatusEvent, BoardStatusState>
implements BoardStatusBloc {}

void main() {
group('$CrosswordPlayingView', () {
testWidgets('pumps successfully', (tester) async {
await tester.pumpSubject(const CrosswordPlayingView());

expect(find.byType(CrosswordPlayingView), findsOneWidget);
});

group('renders', () {
testWidgets('a $CrosswordBoardView', (tester) async {
await tester.pumpSubject(const CrosswordPlayingView());

expect(find.byType(CrosswordBoardView), findsOneWidget);
});

testWidgets('a $WordSelectionPage', (tester) async {
await tester.pumpSubject(const CrosswordPlayingView());

expect(find.byType(WordSelectionPage), findsOneWidget);
});

testWidgets('a $BottomBar', (tester) async {
await tester.pumpSubject(const CrosswordPlayingView());

expect(find.byType(BottomBar), findsOneWidget);
});
});
});
}

extension on WidgetTester {
Future<void> pumpSubject(
Widget child, {
CrosswordBloc? crosswordBloc,
PlayerBloc? playerBloc,
WordSelectionBloc? wordSelectionBloc,
RandomWordSelectionBloc? randomWordSelectionBloc,
BoardStatusBloc? boardStatusBloc,
IoLayoutData? layout = IoLayoutData.small,
}) {
final bloc = crosswordBloc ?? _MockCrosswordBloc();
if (crosswordBloc == null) {
when(() => bloc.state).thenReturn(const CrosswordState());
}

final playerBlocUpdate = playerBloc ?? _MockPlayerBloc();
if (playerBloc == null) {
when(() => playerBlocUpdate.state)
.thenReturn(const PlayerState(mascot: Mascots.dash));
}

final wordSelectionBlocUpdate =
wordSelectionBloc ?? _MockWordSelectionBloc();
if (wordSelectionBloc == null) {
when(() => wordSelectionBlocUpdate.state).thenReturn(
const WordSelectionState.initial(),
);
}

final randomWordSelectionBlocUpdate =
randomWordSelectionBloc ?? _MockRandomWordSelectionBloc();
if (randomWordSelectionBloc == null) {
when(() => randomWordSelectionBlocUpdate.state).thenReturn(
const RandomWordSelectionState(),
);
}

final boardStatusBlocUpdate = boardStatusBloc ?? _MockBoardStatusBloc();
if (boardStatusBloc == null) {
when(() => boardStatusBlocUpdate.state).thenReturn(
const BoardStatusInitial(),
);
}

return pumpApp(
MultiBlocProvider(
providers: [
BlocProvider<CrosswordBloc>(
create: (_) => bloc,
),
BlocProvider.value(
value: playerBlocUpdate,
),
BlocProvider<WordSelectionBloc>(
create: (_) => wordSelectionBlocUpdate,
),
BlocProvider<RandomWordSelectionBloc>(
create: (_) => randomWordSelectionBlocUpdate,
),
BlocProvider<BoardStatusBloc>(
create: (_) => boardStatusBlocUpdate,
),
],
child: child,
),
layout: layout,
);
}
}

0 comments on commit 5f85383

Please sign in to comment.