Skip to content

Commit

Permalink
feat: add error state when submitting answer (#546)
Browse files Browse the repository at this point in the history
* feat: add error state when submitting answer

* feat: handle error when checking answer fails
  • Loading branch information
jsgalarraga authored May 31, 2024
1 parent f7cca22 commit 182def3
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 18 deletions.
4 changes: 4 additions & 0 deletions lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
"@submit": {
"description": "Submit label"
},
"submitError": "An error ocurred while submitting your answer.\nPlease try again.",
"@submitError": {
"description": "Error message when submitting an answer"
},
"solveIt": "Solve it",
"@solveIt": {
"description": "Solve it label"
Expand Down
43 changes: 25 additions & 18 deletions lib/word_selection/bloc/word_selection_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,27 +116,34 @@ class WordSelectionBloc extends Bloc<WordSelectionEvent, WordSelectionState> {
state.copyWith(status: WordSelectionStatus.validating),
);

final points = await _crosswordResource.answerWord(
wordId: state.word!.word.id,
answer: event.answer,
);
try {
final points = await _crosswordResource.answerWord(
wordId: state.word!.word.id,
answer: event.answer,
);

final isCorrect = points > 0;
if (isCorrect) {
emit(
state.copyWith(
status: WordSelectionStatus.solved,
word: state.word!.copyWith(
word: state.word!.word.copyWith(answer: event.answer),
final isCorrect = points > 0;
if (isCorrect) {
emit(
state.copyWith(
status: WordSelectionStatus.solved,
word: state.word!.copyWith(
word: state.word!.word.copyWith(answer: event.answer),
),
wordPoints: points,
),
wordPoints: points,
),
);
} else {
);
} else {
emit(
state.copyWith(
status: WordSelectionStatus.incorrect,
),
);
}
} catch (error, stackTrace) {
addError(error, stackTrace);
emit(
state.copyWith(
status: WordSelectionStatus.incorrect,
),
state.copyWith(status: WordSelectionStatus.failure),
);
}
}
Expand Down
32 changes: 32 additions & 0 deletions lib/word_selection/view/word_solving_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class WordSolvingLargeView extends StatelessWidget {
],
),
),
const ErrorSection(),
const SizedBox(height: 24),
if (isHintsEnabled) ...[
const HintsTitle(),
Expand Down Expand Up @@ -128,6 +129,7 @@ class WordSolvingSmallView extends StatelessWidget {
},
),
),
const ErrorSection(),
const SizedBox(height: 24),
if (isHintsEnabled) ...[
const HintsTitle(),
Expand Down Expand Up @@ -162,6 +164,36 @@ class IncorrectAnswerText extends StatelessWidget {
}
}

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

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final hasError = context.select(
(WordSelectionBloc bloc) =>
bloc.state.status == WordSelectionStatus.failure,
);

if (!hasError) return const SizedBox.shrink();

return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 16),
Text(
context.l10n.submitError,
style: IoCrosswordTextStyles.mobile.body3
.copyWith(color: theme.colorScheme.error),
textAlign: TextAlign.center,
),
],
);
}
}

@visibleForTesting
class BottomPanel extends StatelessWidget {
@visibleForTesting
Expand Down
33 changes: 33 additions & 0 deletions test/word_focused/bloc/word_selection_bloc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,39 @@ void main() {
),
],
);

blocTest<WordSelectionBloc, WordSelectionState>(
'emits a state with failure if validating an answer fails',
build: () => WordSelectionBloc(
crosswordResource: crosswordResource,
),
setUp: () {
answerWord = _MockWord();
when(() => selectedWord.word.copyWith(answer: 'correct'))
.thenReturn(answerWord);
when(
() => crosswordResource.answerWord(
wordId: selectedWord.word.id,
answer: 'correct',
),
).thenThrow(Exception('Oops'));
},
seed: () => WordSelectionState(
status: WordSelectionStatus.solving,
word: selectedWord,
),
act: (bloc) => bloc.add(WordSolveAttempted(answer: 'correct')),
expect: () => <WordSelectionState>[
WordSelectionState(
status: WordSelectionStatus.validating,
word: selectedWord,
),
WordSelectionState(
status: WordSelectionStatus.failure,
word: selectedWord,
),
],
);
});
});
}
66 changes: 66 additions & 0 deletions test/word_focused/view/word_solving_view_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ void main() {
},
);

testWidgets(
'an $ErrorSection',
(tester) async {
await tester.pumpApp(widget);

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

testWidgets(
'a $BottomPanel',
(tester) async {
Expand Down Expand Up @@ -360,6 +369,15 @@ void main() {
},
);

testWidgets(
'an $ErrorSection',
(tester) async {
await tester.pumpApp(widget);

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

testWidgets(
'a $BottomPanel',
(tester) async {
Expand Down Expand Up @@ -420,6 +438,54 @@ void main() {
);
});

group('$ErrorSection', () {
late WordSelectionBloc wordSelectionBloc;
late Widget widget;

setUp(() {
wordSelectionBloc = _MockWordSolvingBloc();

widget = BlocProvider.value(
value: wordSelectionBloc,
child: ErrorSection(),
);
});

group('renders', () {
testWidgets(
'a $SizedBox when the status is not failure',
(tester) async {
when(() => wordSelectionBloc.state).thenReturn(
WordSelectionState(
status: WordSelectionStatus.solving,
word: selectedWord,
),
);

await tester.pumpApp(widget);

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

testWidgets(
'a submitError text when the status is failure',
(tester) async {
when(() => wordSelectionBloc.state).thenReturn(
WordSelectionState(
status: WordSelectionStatus.failure,
word: selectedWord,
),
);

await tester.pumpApp(widget);

expect(find.text(l10n.submitError), findsOneWidget);
},
);
});
});

group('$BottomPanel', () {
late WordSelectionBloc wordSelectionBloc;
late HintBloc hintBloc;
Expand Down

0 comments on commit 182def3

Please sign in to comment.