Files
TPSchedule/mobile/test/school/term_selection_test.dart

185 lines
7.1 KiB
Dart

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);
// A previously authenticated session has already opened its browser.
final connectedBrowser = session.web;
session.connectionState = SchoolConnectionState.connected;
await session.openTimetable(term: SchoolTerm(72), chooseTerm: true);
expect(session.needsTermSelection, isTrue);
expect(session.web, same(connectedBrowser));
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]);
});
}