Files
TPSchedule/mobile/test/school/undergraduate_session_test.dart
T

221 lines
7.9 KiB
Dart

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('live URL cannot cross origin or change again during capture', () async {
await session.openTimetable();
final content = File('test/fixtures/school/undergraduate-timetable.html')
.readAsStringSync();
platform.web.javascript = (_) async => underEvidence(
'https://eams.uestc.edu.cn/eams/courseTableForStd.action?semester.id=523',
html: content,
);
for (final address in [
'https://other.test/eams/courseTableForStd.action',
'https://idas.uestc.edu.cn/authserver/login',
'http://eams.uestc.edu.cn/eams/courseTableForStd.action',
'https://eams.uestc.edu.cn/eams/courseTableForStd.action?semester.id=503',
]) {
platform.web.documentUrl = address;
await session.readCurrentTimetable();
expect(session.pendingDraft, isNull);
expect(session.message, contains('未完成'));
}
});
test('visible timetable imports after same-document history changes native URL does not follow', () async {
await session.openTimetable();
platform.web.documentUrl = 'https://eams.uestc.edu.cn/eams/courseTableForStd.action?semester.id=523';
final content = File('test/fixtures/school/undergraduate-timetable.html')
.readAsStringSync();
platform.web.javascript = (_) async => underEvidence(
'https://eams.uestc.edu.cn/eams/courseTableForStd.action?semester.id=523',
html: content,
);
platform.delegate.finished(platform.web.url!);
await flushSchoolEvents();
expect(session.statusLabel, '已连接');
await session.readCurrentTimetable();
expect(session.pendingDraft!.courses, hasLength(18));
});
test(
'duplicate login continuation upgrades exact school HTTP to HTTPS',
() async {
await session.openTimetable();
final decision = await platform.delegate.navigation(
NavigationRequest(
url: 'http://eams.uestc.edu.cn/eams/home.action?login=1',
isMainFrame: true,
),
);
expect(decision, NavigationDecision.prevent);
expect(
platform.web.loads.last,
'https://eams.uestc.edu.cn/eams/home.action?login=1',
);
expect(session.message, isNot(contains('未完成')));
},
);
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 {
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<Object>();
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<bool>();
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/');
});
}