import 'dart:io'; import 'dart:convert'; import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'package:hepan_everyday/features/school/undergraduate/session.dart'; import 'package:hepan_everyday/features/school/undergraduate/page_probe.dart'; import '../support/fake_school_web.dart'; String underEvidence( String url, { bool authenticated = true, String? html, String kind = 'timetable', }) => jsonEncode({ 'topUrl': url, 'authenticated': authenticated, 'pages': [ if (html != null) {'kind': kind, 'url': url, 'html': html}, ], }); void main() { TestWidgetsFlutterBinding.ensureInitialized(); late FakeSchoolPlatform platform; late UndergraduateSession session; setUp(() { platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; 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.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 { await session.openTimetable(); var probes = 0; platform.web.javascript = (_) async { probes++; return underEvidence('about:blank', authenticated: false); }; session.setReadingActive(true); await flushSchoolEvents(); expect(probes, 0); platform.web.javascript = (_) async => underEvidence(platform.web.url!); platform.delegate.started(platform.web.url!); platform.delegate.finished(platform.web.url!); await flushSchoolEvents(); expect(session.busy, isFalse); expect(session.message, UndergraduateSession.manualMessage); }, ); test( 'manual session is lazy and never captures until the student taps import', () async { expect(platform.controllerCreations, 0); await session.openTimetable(); expect(platform.web.loads, ['https://eams.uestc.edu.cn/eams/']); final content = File('test/fixtures/school/undergraduate-timetable.html') .readAsStringSync(); var captures = 0; platform.web.javascript = (s) async { if (s == undergraduateCaptureScript) { captures++; return underEvidence(platform.web.url!, html: content); } return underEvidence(platform.web.url!); }; platform.delegate.finished(platform.web.url!); await flushSchoolEvents(); expect(captures, 0); expect(session.pendingDraft, isNull); await session.readCurrentTimetable(); expect(captures, 1); expect(session.pendingDraft!.courses, hasLength(18)); }, ); test('closed routes reject old asynchronous capture and save', () async { await session.openTimetable(); final gate = Completer(); platform.web.javascript = (_) => gate.future; final read = session.readCurrentTimetable(); await flushSchoolEvents(); final generation = session.pageGeneration; session.setReadingActive(false); gate.complete( underEvidence( platform.web.url!, html: File('test/fixtures/school/undergraduate-timetable.html') .readAsStringSync(), ), ); await read; expect(session.pendingDraft, isNull); expect(session.saved(generation: generation), isFalse); }); test( 'unused logout stays lazy and failed cookie clearing can be retried', () async { await session.logout(); expect(platform.controllerCreations, 0); await session.openTimetable(); platform.cookies.fail = true; await session.logout(); expect(session.canLogout, isTrue); platform.cookies.fail = false; await session.logout(); expect(session.canLogout, isFalse); }, ); test('new login waits for an outstanding cookie clear', () async { await session.openTimetable(); platform.cookies.clearing = Completer(); final closing = session.logout(); await flushSchoolEvents(); final reopening = session.openTimetable(); await flushSchoolEvents(); platform.cookies.clearing!.complete(true); await closing; await reopening; expect(session.hasOpened, isTrue); expect(platform.web.loads.last, 'https://eams.uestc.edu.cn/eams/'); }); }