Files
KiriMemo/test/widget_test.dart
pluv 1a48833914 chore: license the project under AGPL-3.0
- 添加官方 AGPL-3.0 全文
- LICENSE 作为 asset 打包,注册进 Flutter 许可清单
- 关于页「开源许可」改为打开许可页
- README 补充简介、开发命令与许可说明
2026-10-24 15:25:04 +08:00

195 lines
6.7 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mobile/main.dart';
import 'package:mobile/widgets/grouped_list_section.dart';
/// 在导航栏内按标签定位,避免和页面标题的相同文字混淆。
Finder navLabel(String label) {
return find.descendant(
of: find.byType(NavigationBar),
matching: find.text(label),
);
}
/// 手机尺寸(400 × 800 dp),避免默认 800×600 掩盖溢出问题。
void usePhoneSurface(WidgetTester tester) {
tester.view.physicalSize = const Size(400, 800);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.reset);
}
Future<void> pumpApp(WidgetTester tester) async {
usePhoneSurface(tester);
await tester.pumpWidget(const KiriMemoApp());
await tester.pumpAndSettle();
}
void main() {
testWidgets('底部导航提供学习 / 管理 / 统计 / 账户四个入口', (WidgetTester tester) async {
await pumpApp(tester);
expect(find.byType(NavigationBar), findsOneWidget);
expect(find.byType(NavigationDestination), findsNWidgets(4));
for (final String label in <String>['学习', '管理', '统计', '账户']) {
expect(navLabel(label), findsOneWidget);
}
});
testWidgets('Android 端使用水平滑入转场,而非预测式返回', (WidgetTester tester) async {
await pumpApp(tester);
final MaterialApp app = tester.widget<MaterialApp>(find.byType(MaterialApp));
final PageTransitionsTheme transitions = app.theme!.pageTransitionsTheme;
expect(
transitions.builders[TargetPlatform.android],
isA<FadeForwardsPageTransitionsBuilder>(),
);
});
testWidgets('默认停留在学习页,点击其它入口会切换', (WidgetTester tester) async {
await pumpApp(tester);
NavigationBar bar = tester.widget<NavigationBar>(find.byType(NavigationBar));
expect(bar.selectedIndex, 0);
await tester.tap(navLabel('统计'));
await tester.pumpAndSettle();
bar = tester.widget<NavigationBar>(find.byType(NavigationBar));
expect(bar.selectedIndex, 2);
await tester.tap(navLabel('账户'));
await tester.pumpAndSettle();
bar = tester.widget<NavigationBar>(find.byType(NavigationBar));
expect(bar.selectedIndex, 3);
});
testWidgets('学习首页展示今日任务与唯一主行动', (WidgetTester tester) async {
await pumpApp(tester);
expect(find.text('今日计划'), findsOneWidget);
expect(find.text('待复习'), findsOneWidget);
expect(find.text('待新识'), findsOneWidget);
expect(find.text('开始学习'), findsOneWidget);
// 顶部状态标识:接力用闪电、同步用云图标,不再用文字表达状态。
expect(find.byIcon(Icons.bolt_rounded), findsOneWidget);
expect(find.text('今日记忆'), findsOneWidget);
expect(find.text('59'), findsOneWidget);
expect(find.byIcon(Icons.cloud_done_rounded), findsOneWidget);
expect(find.byTooltip('搜索条目'), findsOneWidget);
expect(find.byTooltip('学习日志'), findsOneWidget);
// 学习域的四个快捷入口。
for (final String label in <String>['收藏夹', '自我测试', '附带资料', '计划设置']) {
expect(find.text(label), findsOneWidget);
}
});
testWidgets('未接入内核的入口点击后给出反馈', (WidgetTester tester) async {
await pumpApp(tester);
await tester.tap(find.text('开始学习'));
await tester.pump();
await tester.pump(const Duration(milliseconds: 300));
expect(find.text('学习会话 尚未接入内核'), findsOneWidget);
});
testWidgets('管理页有三个维度,各自列出卡片', (WidgetTester tester) async {
await pumpApp(tester);
await tester.tap(navLabel('管理'));
await tester.pumpAndSettle();
for (final String label in <String>['单元集', '计划', '算法']) {
expect(find.text(label), findsOneWidget);
}
expect(find.text('高考必背古诗文'), findsOneWidget);
expect(find.text('标识 cngk-t'), findsOneWidget);
await tester.tap(find.text('计划'));
await tester.pumpAndSettle();
expect(find.text('每日计划'), findsOneWidget);
expect(find.text('周末冲刺'), findsOneWidget);
expect(find.text('新识记'), findsNWidgets(2));
await tester.tap(find.text('算法'));
await tester.pumpAndSettle();
expect(find.text('NSP-0'), findsOneWidget);
expect(find.text('默认'), findsOneWidget);
});
testWidgets('账户页展示资料、学习数据与四个功能入口', (WidgetTester tester) async {
await pumpApp(tester);
await tester.tap(navLabel('账户'));
await tester.pumpAndSettle();
expect(find.text('zhiyu'), findsOneWidget);
expect(find.text('ID KM-1024 · 大一'), findsOneWidget);
expect(find.text('累计学习'), findsOneWidget);
expect(find.text('坚持'), findsOneWidget);
// 四个入口是同一张分组卡片里的四行。
expect(find.byType(GroupedListSection), findsOneWidget);
expect(find.byType(GroupedListTile), findsNWidgets(4));
for (final String label in <String>[
'设置',
'文档与帮助',
'反馈问题',
'关于 KiriMemo',
]) {
expect(find.text(label), findsOneWidget);
}
});
testWidgets('账户页可以进入设置页,设置项按分组排列', (WidgetTester tester) async {
await pumpApp(tester);
await tester.tap(navLabel('账户'));
await tester.pumpAndSettle();
await tester.tap(find.text('设置'));
await tester.pumpAndSettle();
expect(find.text('每日新识记上限'), findsOneWidget);
expect(find.text('答错后重新排队'), findsOneWidget);
// 分组在下方,需要滚动到可见。
await tester.scrollUntilVisible(find.text('版本'), 200);
expect(find.text('版本'), findsOneWidget);
expect(find.text('1.0.0'), findsOneWidget);
});
testWidgets('关于页声明 AGPL-3.0 授权', (WidgetTester tester) async {
await pumpApp(tester);
await tester.tap(navLabel('账户'));
await tester.pumpAndSettle();
await tester.tap(find.text('关于 KiriMemo'));
await tester.pumpAndSettle();
expect(find.text('GNU AGPL v3.0'), findsOneWidget);
});
testWidgets('文档与帮助页底部有可上滑的助手', (WidgetTester tester) async {
await pumpApp(tester);
await tester.tap(navLabel('账户'));
await tester.pumpAndSettle();
await tester.tap(find.text('文档与帮助'));
await tester.pumpAndSettle();
expect(find.text('文档内容将在这里显示'), findsOneWidget);
expect(find.text('问问 KiriMemo'), findsOneWidget);
// 收起时是横栏,点开后出现输入框。
expect(find.byType(TextField), findsNothing);
await tester.tap(find.text('问问 KiriMemo'));
await tester.pumpAndSettle();
expect(find.byType(TextField), findsOneWidget);
});
}