Files
English/kouyu_english/test/material_step_test.dart

108 lines
3.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:kouyu_english/core/app_state.dart';
import 'package:kouyu_english/core/models.dart';
import 'package:kouyu_english/core/courses/courses.dart';
import 'package:kouyu_english/core/courses/course_pack.dart';
import 'package:kouyu_english/core/courses/course_repository.dart';
import 'package:kouyu_english/features/lesson/lesson_flow.dart';
/// Widget smoke test for the JSON units' 听读材料 (listening/reading
/// comprehension) step: it must be reached only on the last segment of a unit
/// that has materials, render from the real loaded content, and let the learner
/// continue to writing once every question is answered.
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() async {
await CourseRepository.instance.load();
});
tearDownAll(() => CourseRepository.instance.resetForTest());
/// The first loaded unit whose materials contain at least one question.
CoursePack unitWithQuestions() => CourseRepository.instance.units.firstWhere(
(u) => u.materials.any((m) => m.questions.isNotEmpty),
);
AppState stateOn(String unitId, int segmentIndex) {
final state = AppState();
state.activeLessonId = unitId;
state.activeSegmentIndexes[unitId] = segmentIndex;
return state;
}
testWidgets(
'material step is reached only on the last segment with materials',
(tester) async {
final unit = unitWithQuestions();
final lesson = lessonById(unit.id);
expect(
lesson.segments.length,
greaterThan(1),
reason: 'need a multi-segment unit to prove the gate',
);
// Finishing reading on an earlier segment skips straight to writing.
final early = stateOn(unit.id, 0);
early.lessonStep = LessonStep.reading;
early.completeReading();
expect(early.lessonStep, LessonStep.writing);
// Finishing reading on the final segment opens the comprehension step.
final last = stateOn(unit.id, lesson.segments.length - 1);
last.lessonStep = LessonStep.reading;
last.completeReading();
expect(last.lessonStep, LessonStep.material);
},
);
testWidgets(
'renders the unit materials and continues once every question is answered',
(tester) async {
final unit = unitWithQuestions();
final lesson = lessonById(unit.id);
final state = stateOn(unit.id, lesson.segments.length - 1);
state.lessonStep = LessonStep.material;
await tester.pumpWidget(
MaterialApp(
home: LessonFlow(
state: state,
onOpenDialogue: () {},
onFinish: () {},
),
),
);
await tester.pumpAndSettle();
// The step rendered from the real loaded content.
expect(find.text('读一段真实的小材料,做完理解题。'), findsOneWidget);
// Continue is gated until every question is answered.
expect(find.text('答对所有理解题后继续'), findsOneWidget);
expect(find.text('继续写一写'), findsNothing);
// Answer every question by tapping its correct option (answer == the
// parsed contract's first option; the widget shuffles their display order).
for (final material in unit.materials) {
for (final question in material.questions) {
final option = find.text(question.answer).first;
await tester.ensureVisible(option);
await tester.pumpAndSettle();
await tester.tap(option);
await tester.pumpAndSettle();
}
}
// Now the button is enabled and advances the lesson to writing.
final go = find.text('继续写一写');
expect(go, findsOneWidget);
await tester.ensureVisible(go);
await tester.tap(go);
await tester.pumpAndSettle();
expect(state.lessonStep, LessonStep.writing);
},
);
}