halkyon/halkyon_learn_flutter/test/app/instance_gate_test.dart
Tizian 「ティツィアーン」 9b0f28d7c1
feat(instance): the first start offers instances as tiles
Under the wordmark on a cobalt wash, two tiles as Proton's account page
shows its services: the build's instance, chosen in one tap, and
another, which unfolds the address to type. A ring from cobalt to
copper, a glow and a tagline come in under the pointer, on the
keyboard's focus, while pressed or open; without a mouse the taglines
always show. The launch screen's "Halkyon" over "Learn" becomes
BrandWordmark, which both show.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-18 21:06:28 +02:00

158 lines
5.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/app/instance_gate.dart';
import 'package:halkyon_learn_flutter/src/app/person_app.dart';
import 'package:halkyon_learn_flutter/src/core/instance/instance.dart';
import 'package:halkyon_learn_flutter/src/core/instance/instance_choice.dart';
import 'package:halkyon_learn_flutter/src/feature/auth/widget/session_gate.dart';
import 'package:halkyon_learn_flutter/src/feature/settings/widget/settings_screen.dart';
import 'package:material_ui/material_ui.dart';
import '../support/fake_instance_checker.dart';
import '../support/memory_device_settings_store.dart';
import '../support/memory_instance_store.dart';
import '../support/pump_app.dart';
import '../support/test_dependencies.dart';
void main() {
final builtIn = Instance.parse('learn.halkyon.eu')!;
final other = Instance.parse('learn.example.org')!;
late MemoryInstanceStore store;
late List<Instance> opened;
late List<Instance> forgotten;
setUp(() {
store = MemoryInstanceStore();
opened = [];
forgotten = [];
});
/// Starts the app on a device that [usedBefore] the choice existed, with
/// [answering] instances answering a check.
Future<InstanceChoice> start(
WidgetTester tester, {
bool usedBefore = false,
Set<Instance> answering = const {},
}) async {
tester.view.physicalSize = const Size(412, 900);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final choice = InstanceChoice(
store,
builtIn: builtIn,
forget: (instance) async => forgotten.add(instance),
);
await choice.load(usedBefore: usedBefore);
await tester.pumpWidget(
InstanceGate(
choice: choice,
checker: FakeInstanceChecker(answering),
deviceSettings: MemoryDeviceSettingsStore(),
open: (instance) async {
opened.add(instance);
return testDependencies();
},
app: SessionGate(app: (person) => PersonApp(person: person)),
),
);
await tester.pumpAndSettle();
return choice;
}
/// Opens Settings › Switch account, further down Settings.
Future<void> openSwitcher(WidgetTester tester) async {
await openTab(tester, 'Profile');
await tester.tap(find.byTooltip('Settings'));
await tester.pumpAndSettle();
await tester.scrollUntilVisible(
find.text('Switch account'),
200,
// Settings' list; its citation preview is a scroll view of its own.
scrollable: find
.descendant(
of: find.byType(SettingsScreen),
matching: find.byType(Scrollable),
)
.first,
);
// Built, but perhaps still below the window's edge.
await tester.ensureVisible(find.text('Switch account'));
await tester.pumpAndSettle();
await tester.tap(find.text('Switch account'));
await tester.pumpAndSettle();
}
testWidgets('a new install asks for the instance first, and opens the '
"build's in one tap", (tester) async {
await start(tester);
// The wordmark says it to screen readers.
expect(find.bySemanticsLabel('Welcome to Halkyon Learn'), findsOneWidget);
expect(opened, isEmpty, reason: 'nothing made anywhere yet');
expect(find.byType(TextField), findsNothing, reason: 'no address asked');
await tester.tap(find.text('learn.halkyon.eu'));
await tester.pumpAndSettle();
expect(opened, [builtIn]);
expect(tab('Home'), findsOneWidget);
});
testWidgets('another instance is checked before the app moves there', (
tester,
) async {
await start(tester, answering: {other});
await tester.tap(find.text('Another instance'));
await tester.pumpAndSettle();
expect(
FocusManager.instance.primaryFocus?.context
?.findAncestorWidgetOfExactType<TextField>(),
isNotNull,
reason: 'the address is typed at once',
);
await tester.enterText(find.byType(TextField), 'nowhere.example.org');
await tester.tap(find.text('Continue'));
await tester.pumpAndSettle();
expect(
find.text(
'No instance of Halkyon Learn answers at nowhere.example.org.',
),
findsOneWidget,
);
expect(opened, isEmpty);
await tester.enterText(find.byType(TextField), 'learn.example.org');
await tester.tap(find.text('Continue'));
await tester.pumpAndSettle();
expect(opened, [other]);
});
testWidgets('an install from before goes on without asking', (tester) async {
await start(tester, usedBefore: true);
expect(opened, [builtIn]);
expect(tab('Home'), findsOneWidget);
});
testWidgets('Settings switches between the accounts on the device, and '
'removes one not in use', (tester) async {
store = MemoryInstanceStore((current: builtIn, known: [builtIn, other]));
await start(tester);
await openSwitcher(tester);
expect(find.text('learn.halkyon.eu'), findsWidgets);
await tester.tap(find.text('learn.example.org'));
await tester.pumpAndSettle();
expect(opened, [builtIn, other]);
expect(tab('Home'), findsOneWidget, reason: 'a new app, on Home');
await openSwitcher(tester);
await tester.tap(find.byTooltip('Remove account'));
await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(FilledButton, 'Remove'));
await tester.pumpAndSettle();
expect(forgotten, [builtIn]);
expect(store.kept?.known, [other]);
});
}