151 lines
5.5 KiB
Dart
151 lines
5.5 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:timezone/data/latest.dart' as tzdata;
|
||
import 'package:hepan_everyday/app/hepan_app.dart';
|
||
import 'package:hepan_everyday/app/app_controller.dart';
|
||
import 'package:hepan_everyday/features/profile/settings_page.dart';
|
||
import 'package:hepan_everyday/services/calendar_service.dart';
|
||
|
||
import '../support/fakes.dart';
|
||
|
||
import 'navigation_test.dart' show uiController;
|
||
import '../services/calendar_service_test.dart' show CalendarProvider;
|
||
import '../domain/schedule_engine_test.dart' show course;
|
||
|
||
import 'package:hepan_everyday/services/android_calendar_service.dart';
|
||
import 'package:hepan_everyday/domain/app_snapshot.dart';
|
||
import 'package:hepan_everyday/domain/app_settings.dart';
|
||
import 'package:hepan_everyday/domain/semester.dart';
|
||
|
||
void main() {
|
||
setUpAll(tzdata.initializeTimeZones);
|
||
testWidgets(
|
||
'partial initial calendar sync exposes working cleanup action while switch is off',
|
||
(tester) async {
|
||
final provider = CalendarProvider()..failAfterFirst = true;
|
||
final controller = AppController(
|
||
MemoryStore(
|
||
AppSnapshot(
|
||
courses: [
|
||
course(id: 'a'),
|
||
course(id: 'b'),
|
||
],
|
||
settings: AppSettings(
|
||
semester: Semester(
|
||
startDate: DateTime(2026, 9, 9),
|
||
totalWeeks: 1,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
FakeNotifications(),
|
||
AndroidCalendarService(provider),
|
||
DateTime.now,
|
||
);
|
||
await controller.initialize();
|
||
await controller.enableCalendarFromUserAction('local');
|
||
expect(controller.snapshot.settings.calendarEnabled, isFalse);
|
||
expect(provider.records, hasLength(1));
|
||
await tester.pumpWidget(
|
||
MaterialApp(home: SettingsPage(controller: controller)),
|
||
);
|
||
await tester.pumpAndSettle();
|
||
await tester.scrollUntilVisible(
|
||
find.text('重试清理课程日程'),
|
||
250,
|
||
scrollable: find.byType(Scrollable).first,
|
||
);
|
||
await tester.ensureVisible(find.text('重试清理课程日程'));
|
||
await tester.pumpAndSettle();
|
||
await tester.tap(find.text('重试清理课程日程'));
|
||
await tester.pumpAndSettle();
|
||
expect(provider.records, isEmpty);
|
||
expect(controller.snapshot.calendarCleanupPending, isFalse);
|
||
controller.dispose();
|
||
},
|
||
);
|
||
testWidgets('calendar provider failure is explained and keeps switch off', (
|
||
tester,
|
||
) async {
|
||
final controller = AppController(
|
||
MemoryStore(),
|
||
FakeNotifications(),
|
||
UnavailableCalendar(),
|
||
DateTime.now,
|
||
);
|
||
await controller.initialize();
|
||
await tester.pumpWidget(
|
||
MaterialApp(home: SettingsPage(controller: controller)),
|
||
);
|
||
await tester.pumpAndSettle();
|
||
await tester.scrollUntilVisible(
|
||
find.text('导入手机日历'),
|
||
250,
|
||
scrollable: find.byType(Scrollable).first,
|
||
);
|
||
await tester.ensureVisible(find.text('导入手机日历'));
|
||
await tester.pumpAndSettle();
|
||
await tester.tap(find.text('导入手机日历'));
|
||
await tester.pumpAndSettle();
|
||
expect(tester.takeException(), isNull);
|
||
expect(find.text('日历暂时不可用,请检查权限后重试'), findsOneWidget);
|
||
expect(controller.snapshot.settings.calendarEnabled, isFalse);
|
||
controller.dispose();
|
||
});
|
||
testWidgets(
|
||
'invalid semester weeks are rejected without changing saved data',
|
||
(tester) async {
|
||
final controller = uiController();
|
||
await controller.initialize();
|
||
await tester.pumpWidget(HepanApp(controller: controller));
|
||
await tester.pumpAndSettle();
|
||
expect(find.bySemanticsLabel('我的'), findsOneWidget);
|
||
await tester.tap(find.bySemanticsLabel('我的'));
|
||
await tester.pumpAndSettle();
|
||
await tester.ensureVisible(find.text('课表设置'));
|
||
await tester.pumpAndSettle();
|
||
await tester.tap(find.text('课表设置'));
|
||
await tester.pumpAndSettle();
|
||
await tester.scrollUntilVisible(
|
||
find.byKey(const Key('semester-weeks')),
|
||
300,
|
||
scrollable: find.byType(Scrollable).last,
|
||
);
|
||
await tester.enterText(find.byKey(const Key('semester-weeks')), '31');
|
||
await tester.ensureVisible(find.text('保存学期设置'));
|
||
await tester.tap(find.text('保存学期设置'));
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('周数应为 1–30'), findsOneWidget);
|
||
expect(controller.snapshot.settings.semester, isNull);
|
||
controller.dispose();
|
||
},
|
||
);
|
||
testWidgets('two hundred percent font demo has no overflow', (tester) async {
|
||
tester.view.physicalSize = const Size(360, 800);
|
||
tester.view.devicePixelRatio = 1;
|
||
addTearDown(tester.view.resetPhysicalSize);
|
||
addTearDown(tester.view.resetDevicePixelRatio);
|
||
tester.platformDispatcher.textScaleFactorTestValue = 2;
|
||
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
|
||
final controller = uiController();
|
||
await controller.initialize();
|
||
await controller.showDemo();
|
||
await tester.pumpWidget(HepanApp(controller: controller));
|
||
await tester.pumpAndSettle();
|
||
await tester.scrollUntilVisible(
|
||
find.text('示例课表'),
|
||
250,
|
||
scrollable: find.byType(Scrollable).first,
|
||
);
|
||
expect(find.text('示例课表'), findsOneWidget);
|
||
expect(tester.takeException(), isNull);
|
||
controller.dispose();
|
||
});
|
||
}
|
||
|
||
class UnavailableCalendar extends FakeCalendar {
|
||
@override
|
||
Future<List<DeviceCalendar>> listWritableCalendars() async =>
|
||
throw StateError('unavailable');
|
||
}
|