import 'package:flutter_test/flutter_test.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'package:hepan_everyday/features/school/school_session.dart'; import 'package:hepan_everyday/features/school/school_page_probe.dart'; import 'package:hepan_everyday/domain/school_term.dart'; import 'dart:convert'; import '../support/fake_school_web.dart'; import 'recognized_timetable_test.dart' show fixture; import 'exam_adapter_test.dart' show examHtml; void main() { TestWidgetsFlutterBinding.ensureInitialized(); test( 'first online import waits for an explicit term even on a ready table', () async { final platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; final session = SchoolSession(); addTearDown(session.dispose); await session.open(); const url = 'https://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/73'; platform.web.url = url; platform.web.javascript = (_) async => schoolPageEvidence(topUrl: url, authenticated: true, html: fixture()); platform.delegate.started(url); platform.delegate.finished(url); await flushSchoolEvents(); expect(session.pendingDraft, isNull); expect(session.finding, isFalse); expect(session.needsTermSelection, isTrue); }, ); test('signed out change waits for authentication then explicit choice before requesting exams', () async { final platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; final session = SchoolSession(); addTearDown(session.dispose); await session.openExams(term: SchoolTerm(73), chooseTerm: true); expect(session.needsTermSelection, isFalse); expect( platform.web.loads.single, 'https://yjsjy.uestc.edu.cn/pyxx/jzsso/login', ); const home = 'https://yjsjy.uestc.edu.cn/pyxx/home/index'; platform.web.url = home; platform.web.javascript = (_) async => schoolPageEvidence(topUrl: platform.web.url!, authenticated: true); platform.delegate.started(home); platform.delegate.finished(home); await flushSchoolEvents(); expect(session.needsTermSelection, isTrue); expect(platform.web.loads.length, 1); await session.selectTerm(SchoolTerm(72)); expect( platform.web.loads.last, 'https://yjsjy.uestc.edu.cn/pyxx/pygl/kskcxx/index?xq=72', ); expect(session.needsTermSelection, isFalse); }); test('connected change prompts immediately without replacing imported data or navigating', () async { final platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; final session = SchoolSession(); addTearDown(session.dispose); session.connectionState = SchoolConnectionState.connected; await session.openTimetable(term: SchoolTerm(72), chooseTerm: true); expect(session.needsTermSelection, isTrue); expect(platform.web.loads, isEmpty); expect(session.selectedTerm, SchoolTerm(72)); expect(session.pendingDraft, isNull); expect(session.termChoices.first.id, 73); expect(session.termChoices.last.id, 1); await session.selectTerm(SchoolTerm(71)); expect( platform.web.loads.single, 'https://yjsjy.uestc.edu.cn/pyxx/pygl/xskbcx/index/71', ); }); test('timetable selected DOM term must match request before an import can become pending', () async { final platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; final session = SchoolSession(); addTearDown(session.dispose); session.connectionState = SchoolConnectionState.connected; await session.openTimetable(term: SchoolTerm(72)); platform.web.javascript = (_) async => schoolPageEvidence(topUrl: platform.web.url!, html: fixture()); platform.delegate.started(platform.web.url!); platform.delegate.finished(platform.web.url!); await flushSchoolEvents(); expect(session.pendingDraft, isNull); platform.web.javascript = (_) async => schoolPageEvidence( topUrl: platform.web.url!, html: fixture().replaceFirst('value="73"', 'value="72"'), ); await session.readCurrentPage(); expect(session.pendingDraft?.schoolTerm, SchoolTerm(72)); }); test( 'exam selected DOM term must match requested query before saving', () async { final platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; final session = SchoolSession(); addTearDown(session.dispose); session.connectionState = SchoolConnectionState.connected; await session.openExams(term: SchoolTerm(72)); platform.web.javascript = (_) async => schoolPageEvidence( topUrl: platform.web.url!, html: examHtml(), kind: 'exams', ); platform.delegate.started(platform.web.url!); platform.delegate.finished(platform.web.url!); await flushSchoolEvents(); expect(session.pendingExams, isNull); platform.web.javascript = (_) async => schoolPageEvidence( topUrl: platform.web.url!, html: examHtml().replaceFirst('value="73"', 'value="72"'), kind: 'exams', ); await session.readCurrentPage(); expect(session.pendingExams?.termId, '72'); }, ); test( 're-authentication retains chosen term and unfinished picker intent', () async { final platform = FakeSchoolPlatform(); WebViewPlatform.instance = platform; final session = SchoolSession(); addTearDown(session.dispose); session.connectionState = SchoolConnectionState.connected; await session.openExams(term: SchoolTerm(72), chooseTerm: true); await session.openAuthentication(); expect(session.needsTermSelection, isFalse); expect(session.selectedTerm, SchoolTerm(72)); const home = 'https://yjsjy.uestc.edu.cn/pyxx/home/index'; platform.web.url = home; platform.web.javascript = (_) async => schoolPageEvidence(topUrl: home, authenticated: true); platform.delegate.started(home); platform.delegate.finished(home); await flushSchoolEvents(); expect(session.needsTermSelection, isTrue); await session.selectTerm(SchoolTerm(71)); await session.openAuthentication(); expect(session.selectedTerm, SchoolTerm(71)); expect(session.needsTermSelection, isFalse); platform.web.url = home; platform.delegate.started(home); platform.delegate.finished(home); await flushSchoolEvents(); expect( platform.web.loads.last, 'https://yjsjy.uestc.edu.cn/pyxx/pygl/kskcxx/index?xq=71', ); }, ); test('live dropdown choices are validated, deduplicated and sorted without private fields', () { final uri = Uri.parse('https://yjsjy.uestc.edu.cn/pyxx/home/index'); final evidence = SchoolPageEvidence.decode( jsonEncode({ 'topUrl': uri.toString(), 'authenticated': true, 'pages': [], 'terms': [72, 73, 72, 0, -1, 10000, 'private-value'], }), uri, ); expect(evidence.terms.map((term) => term.id), [73, 72]); }); }