fix: harden school imports and add optional feedback diagnostics

This commit is contained in:
Codex
2026-10-15 10:37:32 +08:00
parent 674df1ceb3
commit 7299f4d8b6
25 changed files with 722 additions and 42 deletions
@@ -1,4 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'package:hepan_everyday/services/diagnostic_log.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
@@ -26,6 +29,30 @@ void main() {
platform.delegate.finished(url);
}
test('login diagnostic breadcrumbs distinguish probe and network failures without raw details', () async {
await session.openTimetable(term: SchoolTerm(73));
session.setReadingActive(true);
platform.web.javascript = (_) async => throw StateError('PRIVATE_TICKET');
navigate('https://yjsjy.uestc.edu.cn/pyxx/home/index');
await flushSchoolEvents();
var log = utf8.decode(await DiagnosticLog.instance.export());
expect(log, contains('school_probe_failed'));
expect(log, isNot(contains('PRIVATE_TICKET')));
platform.delegate.resourceError(
WebResourceError(
errorCode: -2,
description: 'PRIVATE_NETWORK_DETAIL',
isForMainFrame: true,
url: platform.web.url,
),
);
await flushSchoolEvents();
log = utf8.decode(await DiagnosticLog.instance.export());
expect(log, contains('web_resource_error'));
expect(log, contains('"status":-2'));
expect(log, isNot(contains('PRIVATE_NETWORK_DETAIL')));
});
test('graduate logout function automatically opens timetable without an exit anchor', () async {
await session.openTimetable(term: SchoolTerm(73));
platform.web.javascript = (script) async =>
@@ -82,6 +82,10 @@ void main() {
await finish();
expect(session.pendingExams!.records, hasLength(12));
expect(session.pendingExams!.requestedExamTypes, {1, 2, 3});
final completedGeneration = session.pageGeneration;
platform.delegate.started('https://eams.uestc.edu.cn/eams/');
expect(session.pendingExams, isNull);
expect(session.pageGeneration, greaterThan(completedGeneration));
},
);
test('last type failure never publishes partial results', () async {
@@ -9,6 +9,21 @@ import 'package:hepan_everyday/data/schedule_file_import.dart';
import 'package:hepan_everyday/domain/school_identity.dart';
void main() {
test('unrecognized activity writes and incomplete declarations reject the entire timetable', () {
const valid =
'activity = new TaskActivity("T", "教师", "C", "课程(C.01)", "R", "教室", "010"); '
'index = 0*unitCount+0; table0.activities[index][table0.activities[index].length]=activity;';
for (final extra in [
'table0.activities[11][table0.activities[11].length]=activity;',
'activity = new TaskActivity("T", "教师", "C", "另一课程(C.02)", "R", "教室", "010")\n'
'index = 0*unitCount+1; table0.activities[index][table0.activities[index].length]=activity;',
]) {
expect(
() => parseActivityData('$valid $extra', unitCount: 12),
throwsFormatException,
);
}
});
final uri = Uri.parse(
'https://eams.uestc.edu.cn/eams/courseTableForStd.action',
);