Files
English/kouyu_english/test/placement_and_scene_test.dart
T
shenleiandClaude Opus 5 9ab08c25ef fix: 修正学习流程中的证据、复习与进度问题
- 独立尝试按课程要求校验内容,不再任意输入即算独立成功
- 复习节点改为学后第 1/3/7/14 天,之后每 30 天抽查;复习轮换情境
- 掌握状态按作答记录推导:需认识、可回忆、跨情境使用及最近两次无帮助
- 课程证据按实际用到的目标记录;跟读与课程对话只算辅助练习
- 复习成功不再降低已有状态
- 学完课程后进入下一节未完成课程;全部学完后引导巩固与阶段评估
- 新增 3 题基础定位,按结果设置起始课程
- 新增按课程开放的对话场景,首页推荐最少练习的场景
- 切换课程时清空上一课的步骤进度
- AI 返回 JSON 格式并按 JSON 回放历史;拼写校验忽略大小写与连字符;移除学习目标选择

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 18:52:01 +09:00

93 lines
3.2 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/features/dialogue/dialogue_flow.dart';
import 'package:kouyu_english/features/onboarding/onboarding_pages.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
setUp(() {
SharedPreferences.setMockInitialValues({});
});
testWidgets('three-question placement suggests a starting lesson', (
tester,
) async {
final state = AppState();
var started = false;
await tester.pumpWidget(
MaterialApp(
home: PlacementPage(state: state, onStart: () => started = true),
),
);
await tester.tap(find.text('开始 3 分钟定位'));
await tester.pumpAndSettle();
expect(find.text('定位 · 1 / 3'), findsOneWidget);
await tester.tap(find.text('你好,我叫 Mia,很高兴认识你。'));
await tester.pump();
await tester.tap(find.text('下一题'));
await tester.pumpAndSettle();
expect(find.text('定位 · 2 / 3'), findsOneWidget);
await tester.tap(find.text('现在不方便开口,跳过'));
await tester.pumpAndSettle();
expect(find.text('定位 · 3 / 3'), findsOneWidget);
await tester.enterText(find.byType(TextField), 'My name is Mia.');
await tester.tap(find.text('查看建议'));
await tester.pumpAndSettle();
expect(find.text('建议从 A0 第 2 课开始'), findsOneWidget);
expect(find.text('从更简单内容开始'), findsOneWidget);
await tester.tap(find.text('开始今天学习'));
await tester.pump();
expect(started, isTrue);
expect(state.activeLessonId, 'a0-02');
expect(state.placementStartLessonId, 'a0-02');
expect(state.completedLessonIds, isEmpty);
});
testWidgets('an unanswered placement starts from lesson one', (tester) async {
final state = AppState();
await tester.pumpWidget(
MaterialApp(
home: PlacementPage(state: state, onStart: () {}),
),
);
await tester.tap(find.text('开始 3 分钟定位'));
await tester.pumpAndSettle();
await tester.tap(find.text('听不懂,下一题'));
await tester.pumpAndSettle();
await tester.tap(find.text('我读完了'));
await tester.pumpAndSettle();
await tester.tap(find.text('还不会说,查看建议'));
await tester.pumpAndSettle();
expect(find.text('建议从 A0 第 1 课开始'), findsOneWidget);
expect(find.text('从更简单内容开始'), findsNothing);
});
testWidgets('scene page lists open and locked scenes', (tester) async {
final state = AppState()
..completedLessonIds.addAll(['a0-01', 'a0-02', 'a0-03', 'a0-04']);
String? startedScene;
await tester.pumpWidget(
MaterialApp(
home: DialogueScenePage(
state: state,
onStart: (id) => startedScene = id,
),
),
);
expect(find.text('初次见面'), findsOneWidget);
expect(find.text('留个电话'), findsOneWidget);
expect(find.text('A0 · 学完第 7 课后开放'), findsOneWidget);
await tester.tap(find.widgetWithText(FilledButton, '开始对话').first);
expect(startedScene, isNotNull);
});
}