feat: 增加AI配置文件与TTS自动朗读,修复二级页面返回按钮与音频播放
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
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/generated_content.dart';
|
||||
import 'package:kouyu_english/core/models.dart';
|
||||
import 'package:kouyu_english/features/dialogue/dialogue_flow.dart';
|
||||
import 'package:kouyu_english/features/review/review_page.dart';
|
||||
import 'package:kouyu_english/features/shell/learning_shell.dart';
|
||||
import 'package:kouyu_english/main.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
});
|
||||
|
||||
testWidgets('Onboarding PlacementPage back button returns to WelcomePage', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(const KouyuEnglishApp());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('每天 20 分钟,\n说出能用的英语。'), findsOneWidget);
|
||||
await tester.tap(find.text('继续'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('从哪里开始?'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('每天 20 分钟,\n说出能用的英语。'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('SettingsPage back button returns to ProgressPage', (
|
||||
tester,
|
||||
) async {
|
||||
final state = AppState()..finishOnboarding();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: LearningShell(state: state)),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Navigate to "我的" (progress tab)
|
||||
await tester.tap(find.text('我的'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final settingsButton = find.text('调整学习与 AI 设置');
|
||||
await tester.ensureVisible(settingsButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(settingsButton, findsOneWidget);
|
||||
await tester.tap(settingsButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// In SettingsPage
|
||||
expect(find.text('学习设置'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
// Tap back button
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('调整学习与 AI 设置'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('LessonFlow back button returns to tab', (tester) async {
|
||||
final state = AppState()..finishOnboarding();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: LearningShell(state: state)),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('开始今天的学习'), findsOneWidget);
|
||||
await tester.tap(find.text('开始今天的学习'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// In LessonFlow
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
// Tap back button
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('开始今天的学习'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('DialogueScenePage from Home has back button and returns to Home', (
|
||||
tester,
|
||||
) async {
|
||||
final state = AppState()..finishOnboarding();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: LearningShell(state: state)),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('开始情境对话'), findsOneWidget);
|
||||
await tester.tap(find.text('开始情境对话'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// In DialogueScenePage as secondary route
|
||||
expect(find.text('AI 情境对话'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('开始情境对话'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('DialogueSummaryPage has back button', (tester) async {
|
||||
var backCalled = false;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: DialogueSummaryPage(
|
||||
summary: const DialogueSummaryData(
|
||||
completedTasks: ['介绍姓名'],
|
||||
personalSentence: 'My name is Shen.',
|
||||
usedHelp: false,
|
||||
),
|
||||
onHome: () {},
|
||||
onLesson: () {},
|
||||
onRetry: () {},
|
||||
onBack: () => backCalled = true,
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('对话完成'), findsNWidgets(2)); // AppBar title and Eyebrow
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(backCalled, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('AdaptiveLessonPage has back button in all states', (tester) async {
|
||||
final state = AppState()..finishOnboarding();
|
||||
|
||||
// 1. Empty state
|
||||
var finished = false;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: AdaptiveLessonPage(
|
||||
state: state,
|
||||
onFinished: () => finished = true,
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('AI 四技能补练'), findsNWidgets(2));
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
expect(finished, isTrue);
|
||||
|
||||
// 2. Active lesson state
|
||||
state.cacheApprovedAdaptiveLesson(
|
||||
const GeneratedLesson(
|
||||
lessonId: 'adapt-1',
|
||||
revision: 1,
|
||||
stageVersion: 'A0',
|
||||
abilityIds: ['greeting'],
|
||||
prerequisiteIds: [],
|
||||
targetItemIds: ['name'],
|
||||
receptiveChunks: ['My name is Mia.'],
|
||||
previewItemIds: ['name'],
|
||||
estimatedMinutes: 5,
|
||||
tasks: [
|
||||
GeneratedLessonTask(
|
||||
taskId: 't1',
|
||||
skill: 'listening',
|
||||
type: 'listen',
|
||||
prompt: '听并写出名字',
|
||||
stimulus: 'My name is Mia.',
|
||||
answer: 'Mia',
|
||||
targetItemIds: ['name'],
|
||||
),
|
||||
],
|
||||
),
|
||||
auditor: 'test',
|
||||
);
|
||||
|
||||
finished = false;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: AdaptiveLessonPage(
|
||||
state: state,
|
||||
onFinished: () => finished = true,
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
expect(finished, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('AssessmentPreparationPage and AssessmentPage have back buttons', (
|
||||
tester,
|
||||
) async {
|
||||
final state = AppState()..finishOnboarding();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: LearningShell(state: state)),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Navigate to "我的"
|
||||
await tester.tap(find.text('我的'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Open assessment pack A0-E1
|
||||
final packAButton = find.text('开始 A0-E1');
|
||||
await tester.ensureVisible(packAButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(packAButton, findsOneWidget);
|
||||
await tester.tap(packAButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// In AssessmentPreparationPage
|
||||
expect(find.text('评估准备'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
// Start assessment
|
||||
await tester.tap(find.text('开始评估'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// In AssessmentPage
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
// Tap back button in AssessmentPage
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Returns to Progress tab
|
||||
expect(find.text('A0 四技能评估'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user