Fix school browser initialization and redirect detection; improve diagnostics

This commit is contained in:
Codex
2026-10-15 12:23:35 +08:00
parent 46e26ec548
commit a4c2df838e
20 changed files with 530 additions and 17 deletions
@@ -33,6 +33,39 @@ class FakeFeedbackHttpTransport implements FeedbackHttpTransport {
}
void main() {
test(
'old feedback service gets a specific diagnostic-upgrade hint',
() async {
final transport = FakeFeedbackHttpTransport()
..response = FeedbackHttpResponse(
422,
utf8.encode(
'{"error":"validation_error","detail":"Unexpected file field."}',
),
);
await expectLater(
HttpFeedbackSender(
endpoint: 'https://example.com/v1/feedback',
transport: transport,
).send(
FeedbackSubmission.problem(
id: 'same-id',
message: '问题',
diagnosticLog: Uint8List.fromList(
utf8.encode('TPSchedule diagnostic log\n'),
),
),
),
throwsA(
isA<FeedbackException>().having(
(e) => e.message,
'upgrade hint',
allOf(contains('日志'), contains('更新')),
),
),
);
},
);
test('diagnostics use a separate UTF8 attachment field', () async {
final transport = FakeFeedbackHttpTransport();
await HttpFeedbackSender(
@@ -0,0 +1,82 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
import 'package:hepan_everyday/domain/school_term.dart';
import 'package:hepan_everyday/features/school/school_browser.dart';
import 'package:hepan_everyday/features/school/school_session.dart';
import 'package:hepan_everyday/features/school/undergraduate/session.dart';
import 'package:hepan_everyday/services/diagnostic_log.dart';
import '../support/fake_school_web.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('both school entries wait for browser compatibility settings before loading', () async {
for (final undergraduate in [false, true]) {
final platform = FakeSchoolPlatform();
WebViewPlatform.instance = platform;
final ready = Completer<SchoolBrowserInfo>();
final graduate = SchoolSession(configureBrowser: (_, _) => ready.future);
final under = UndergraduateSession(
configureBrowser: (_, _) => ready.future,
);
addTearDown(graduate.dispose);
addTearDown(under.dispose);
final opening = undergraduate
? under.openTimetable()
: graduate.openTimetable(term: SchoolTerm(73));
await flushSchoolEvents();
expect(platform.web.loads, isEmpty);
ready.complete(const SchoolBrowserInfo(chromiumVersion: '155.0.1.2'));
await opening;
expect(platform.web.loads, hasLength(1));
expect(
undergraduate ? under.browserVersion : graduate.browserVersion,
'155.0.1.2',
);
}
});
test(
'cancel while browser settings initialize never starts a late navigation',
() async {
final platform = FakeSchoolPlatform();
WebViewPlatform.instance = platform;
final ready = Completer<SchoolBrowserInfo>();
final session = UndergraduateSession(
configureBrowser: (_, _) => ready.future,
);
addTearDown(session.dispose);
final opening = session.openTimetable();
await flushSchoolEvents();
session.setReadingActive(false);
ready.complete(const SchoolBrowserInfo());
await opening;
expect(platform.web.loads, isEmpty);
},
);
test('subresource failures remain diagnostic without aborting the school session', () async {
final platform = FakeSchoolPlatform();
WebViewPlatform.instance = platform;
final session = UndergraduateSession();
addTearDown(session.dispose);
await session.openTimetable();
platform.delegate.resourceError(
WebResourceError(
errorCode: -105,
description: 'PRIVATE_COOKIE',
isForMainFrame: false,
url: 'http://eams.uestc.edu.cn/eams/scripts/component.js?ticket=PRIVATE_TICKET',
),
);
await flushSchoolEvents();
final log = utf8.decode(await DiagnosticLog.instance.export());
expect(log, contains('school_resource_failed'));
expect(log, contains('"page":"script"'));
expect(log, contains('"status":-105'));
expect(log, isNot(contains('PRIVATE_COOKIE')));
expect(log, isNot(contains('PRIVATE_TICKET')));
expect(session.message, isNot(contains('未完成')));
});
}
@@ -31,6 +31,48 @@ void main() {
session = UndergraduateSession();
});
tearDown(() => session.dispose());
test(
'page-finished during an old probe is retried on the redirected portal',
() async {
await session.openTimetable();
var first = true;
platform.web.javascript = (_) async {
if (first) {
first = false;
platform.web.url = 'https://eams.uestc.edu.cn/eams/home.action';
platform.delegate.finished(platform.web.url!);
}
return underEvidence(platform.web.url!);
};
platform.delegate.finished(platform.web.url!);
await flushSchoolEvents();
await Future<void>.delayed(const Duration(milliseconds: 600));
await flushSchoolEvents();
expect(session.statusLabel, '已连接');
expect(session.busy, isFalse);
},
);
test('a redirect between page callback and probe does not permanently stop login detection', () async {
await session.openTimetable();
var redirect = true;
platform.web.javascript = (_) async {
if (redirect) {
redirect = false;
platform.web.url = 'https://idas.uestc.edu.cn/authserver/login';
return underEvidence(platform.web.url!, authenticated: false);
}
return underEvidence(platform.web.url!);
};
platform.delegate.finished(platform.web.url!);
await flushSchoolEvents();
expect(session.message, isNot(contains('未完成')));
platform.delegate.finished(platform.web.url!);
await flushSchoolEvents();
platform.web.url = 'https://eams.uestc.edu.cn/eams/';
platform.delegate.finished(platform.web.url!);
await flushSchoolEvents();
expect(session.statusLabel, '已连接');
});
test(
'activating a loading browser never probes the previous blank document',
() async {