194 lines
6.5 KiB
Dart
194 lines
6.5 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:hepan_everyday/app/app_controller.dart';
|
|
import 'package:hepan_everyday/domain/app_snapshot.dart';
|
|
import 'package:hepan_everyday/domain/app_settings.dart';
|
|
import 'package:hepan_everyday/features/profile/reminder_tools.dart';
|
|
|
|
import '../support/fakes.dart';
|
|
|
|
class _Notifications extends FakeNotifications {
|
|
Completer<Map<String, Object?>>? diagnosis;
|
|
int? reconciliationsAtDiagnosis;
|
|
final tests = <bool>[];
|
|
|
|
@override
|
|
Future<String> sendTestReminder({required bool scheduled}) async {
|
|
tests.add(scheduled);
|
|
return scheduled ? '已安排测试提醒' : '已发送测试提醒';
|
|
}
|
|
|
|
@override
|
|
Future<Map<String, Object?>> diagnose() async {
|
|
reconciliationsAtDiagnosis = reconciliations;
|
|
return diagnosis?.future ??
|
|
{
|
|
'notifications': true,
|
|
'exactAlarm': false,
|
|
'pendingCount': 2,
|
|
'channelImportance': 4,
|
|
'channelSound': true,
|
|
'system': {
|
|
'manufacturer': 'TestPhone',
|
|
'model': 'TestModel',
|
|
'sdk': 35,
|
|
'backgroundRestricted': true,
|
|
'standbyBucket': 45,
|
|
'startupAlarmAudit': {
|
|
'capturedAtEpochMillis': 123,
|
|
'cachedCourseCount': 3,
|
|
'existingHandleCount': 1,
|
|
'missingHandleCount': 2,
|
|
'courseName': 'Private course name',
|
|
},
|
|
'account': 'private@example.com',
|
|
},
|
|
'courseNames': ['Private course name'],
|
|
'account': 'private@example.com',
|
|
'errorCode': 'none',
|
|
};
|
|
}
|
|
|
|
@override
|
|
Future<void> openSettings({required bool background}) async {}
|
|
}
|
|
|
|
Future<void> _open(WidgetTester tester, _Notifications notifications) async {
|
|
final controller = AppController(
|
|
MemoryStore(AppSnapshot(settings: AppSettings())),
|
|
notifications,
|
|
FakeCalendar(),
|
|
() => DateTime.utc(2026, 10, 14),
|
|
);
|
|
await controller.initialize();
|
|
addTearDown(controller.dispose);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: SingleChildScrollView(
|
|
child: ReminderTools(controller: controller),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
testWidgets(
|
|
'Android 7 does not ask the user to create an unsupported category',
|
|
(tester) async {
|
|
final notifications = _Notifications()
|
|
..diagnosis = Completer<Map<String, Object?>>();
|
|
notifications.diagnosis!.complete({
|
|
'notifications': true,
|
|
'appNotificationsEnabled': true,
|
|
'channelExists': false,
|
|
'system': {'sdk': 24},
|
|
});
|
|
await _open(tester, notifications);
|
|
await tester.tap(find.text('检查提醒'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.textContaining('类别尚未建立'), findsNothing);
|
|
expect(find.text('系统通知总开关:已允许'), findsOneWidget);
|
|
},
|
|
);
|
|
testWidgets(
|
|
'diagnosis separates the application switch from the reminder category',
|
|
(tester) async {
|
|
final notifications = _Notifications()
|
|
..diagnosis = Completer<Map<String, Object?>>();
|
|
notifications.diagnosis!.complete({
|
|
'notifications': false,
|
|
'appNotificationsEnabled': false,
|
|
'channelExists': true,
|
|
'courseChannelEnabled': true,
|
|
});
|
|
await _open(tester, notifications);
|
|
await tester.tap(find.text('检查提醒'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('系统通知总开关:未允许'), findsOneWidget);
|
|
expect(find.text('课前提醒类别:已允许'), findsOneWidget);
|
|
},
|
|
);
|
|
testWidgets('test controls distinguish immediate and background reminders', (
|
|
tester,
|
|
) async {
|
|
final notifications = _Notifications();
|
|
await _open(tester, notifications);
|
|
await tester.tap(find.text('立即测试提醒'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('已发送测试提醒'), findsOneWidget);
|
|
await tester.tap(find.text('10 秒后台测试'));
|
|
await tester.pumpAndSettle();
|
|
expect(notifications.tests, [false, true]);
|
|
expect(find.textContaining('Home'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('diagnosis refreshes services and prevents overlapping actions', (
|
|
tester,
|
|
) async {
|
|
final notifications = _Notifications()
|
|
..diagnosis = Completer<Map<String, Object?>>();
|
|
await _open(tester, notifications);
|
|
final previous = notifications.reconciliations;
|
|
await tester.tap(find.text('检查提醒'));
|
|
await tester.pump();
|
|
expect(notifications.reconciliationsAtDiagnosis, previous);
|
|
for (final button in tester.widgetList<TextButton>(
|
|
find.byType(TextButton),
|
|
)) {
|
|
expect(button.onPressed, isNull);
|
|
}
|
|
notifications.diagnosis!.complete({'notifications': false});
|
|
await tester.pumpAndSettle();
|
|
expect(find.textContaining('系统通知已关闭'), findsOneWidget);
|
|
expect(find.text('复制提醒诊断'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('copied diagnostics omit unapproved fields and private values', (
|
|
tester,
|
|
) async {
|
|
String? copied;
|
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
SystemChannels.platform,
|
|
(call) async {
|
|
if (call.method == 'Clipboard.setData') {
|
|
copied = (call.arguments as Map)['text'] as String;
|
|
}
|
|
return null;
|
|
},
|
|
);
|
|
addTearDown(
|
|
() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
SystemChannels.platform,
|
|
null,
|
|
),
|
|
);
|
|
await _open(tester, _Notifications());
|
|
await tester.tap(find.text('检查提醒'));
|
|
await tester.pumpAndSettle();
|
|
await tester.ensureVisible(find.text('复制提醒诊断'));
|
|
await tester.tap(find.text('复制提醒诊断'));
|
|
await tester.pumpAndSettle();
|
|
expect(copied, isNotNull);
|
|
expect(copied, isNot(contains('private@example.com')));
|
|
expect(copied, isNot(contains('Private course name')));
|
|
final report = jsonDecode(copied!) as Map;
|
|
expect(report['pendingCount'], 2);
|
|
expect(report['courseCount'], 0);
|
|
expect(report['appVersion'], isNotEmpty);
|
|
expect((report['system'] as Map)['model'], 'TestModel');
|
|
expect(
|
|
((report['system'] as Map)['startupAlarmAudit']
|
|
as Map)['missingHandleCount'],
|
|
2,
|
|
);
|
|
expect((report['beforeCheck'] as Map)['pendingCount'], 2);
|
|
expect(find.textContaining('系统待机限制'), findsOneWidget);
|
|
});
|
|
}
|