halkyon/packages/halkyon_app/test/auth/widget/account_tiles_test.dart

239 lines
7.8 KiB
Dart
Raw Normal View History

import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_app/testing.dart';
import 'package:material_ui/material_ui.dart';
/// A signed-in person's app as a test makes one: whose it is, and the
/// account's tiles in the app's own words.
class const _PersonApp(final SignedIn person) extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
localizationsDelegates: testLocalizationsDelegates,
supportedLocales: HalkyonAppLocalizations.supportedLocales,
home: Scaffold(
body: ListView(
children: [
Text('App of ${person.authUserId}'),
const AccountTiles(
anonymousNote: 'Your notes stay on this device.',
signOutAnonymousMessage:
"This account can't be signed into again, so signing out "
'deletes it with its notes.',
deleteMessage: 'Your notes are deleted everywhere.',
),
],
),
),
);
}
void main() {
late FakeAuthGateway gateway;
late TestAppDependencies dependencies;
Future<void> start(WidgetTester tester, {InstanceChoice? choice}) async {
dependencies = TestAppDependencies(gateway: gateway);
final gate = AppScope(
dependencies: dependencies,
child: SessionGate(
look: (context) => (themeMode: ThemeMode.light, locale: null),
app: _PersonApp.new,
),
);
await tester.pumpWidget(
AppFrameScope(
frame: testFrame(),
child: switch (choice) {
final choice? => InstanceScope(
notifier: choice,
checker: FakeInstanceChecker(),
countryNames: MemoryCountryNames(const {}),
subdivisionNames: const MemorySubdivisionNames({}),
child: gate,
),
null => gate,
},
),
);
await tester.pumpAndSettle();
}
setUp(() => gateway = FakeAuthGateway());
testWidgets('says whose account it is, anonymous on which instance, with '
"the app's note", (tester) async {
await start(tester);
expect(find.text('Anonymous on test.example.org'), findsOneWidget);
expect(find.text('Your notes stay on this device.'), findsOneWidget);
expect(
find.text('Switch account'),
findsNothing,
reason: 'no instances to switch among here',
);
expect(find.text('Sign out'), findsOneWidget);
expect(find.text('Delete account'), findsOneWidget);
});
testWidgets('says the account is signed in, without the note', (
tester,
) async {
gateway = FakeAuthGateway(
status: const SignedIn(authUserId: 'github-person', isIdentified: true),
);
await start(tester);
expect(find.text('Signed in on test.example.org'), findsOneWidget);
expect(find.text('Your notes stay on this device.'), findsNothing);
});
testWidgets('switching account lists the accounts on the device, the '
'instance in use named', (tester) async {
final instance = Instance.parse('learn.example.org')!;
final choice = InstanceChoice(
MemoryInstanceStore((current: instance, known: [instance])),
builtIn: instance,
forget: (instance) async {},
);
await choice.load(usedBefore: false);
await start(tester, choice: choice);
expect(find.text('Switch account'), findsOneWidget);
expect(find.text('learn.example.org'), findsWidgets);
await tester.tap(find.text('Switch account'));
await tester.pumpAndSettle();
expect(find.text('Accounts'), findsOneWidget);
});
testWidgets('signing out of an anonymous account asks first, in the '
"app's words, as it deletes it; Cancel keeps it", (tester) async {
await start(tester);
await tester.tap(find.text('Sign out'));
await tester.pumpAndSettle();
expect(find.text('Sign out?'), findsOneWidget);
expect(
find.text(
"This account can't be signed into again, so signing out deletes "
'it with its notes.',
),
findsOneWidget,
);
await tester.tap(find.text('Cancel'));
await tester.pumpAndSettle();
expect(find.text('App of anonymous-1'), findsOneWidget);
expect(gateway.signOuts, 0);
await tester.tap(find.text('Sign out'));
await tester.pumpAndSettle();
await tester.tap(find.text('Sign out').last);
await tester.pumpAndSettle();
expect(gateway.status, const SignedOut());
expect(find.text('Signed out'), findsOneWidget);
});
testWidgets('signing out of an identified account asks nothing', (
tester,
) async {
gateway = FakeAuthGateway(
status: const SignedIn(authUserId: 'github-person', isIdentified: true),
);
await start(tester);
await tester.tap(find.text('Sign out'));
await tester.pumpAndSettle();
expect(find.text('Sign out?'), findsNothing);
expect(gateway.status, const SignedOut());
});
testWidgets("deleting the account asks first, in the app's words; Cancel "
'keeps it', (tester) async {
await start(tester);
await tester.tap(find.text('Delete account'));
await tester.pumpAndSettle();
expect(find.text('Delete your account?'), findsOneWidget);
expect(find.text('Your notes are deleted everywhere.'), findsOneWidget);
await tester.tap(find.text('Cancel'));
await tester.pumpAndSettle();
expect(gateway.accountDeletions, 0);
await tester.tap(find.text('Delete account'));
await tester.pumpAndSettle();
await tester.tap(find.text('Delete account').last);
await tester.pumpAndSettle();
expect(gateway.accountDeletions, 1);
expect(find.text('Signed out'), findsOneWidget);
});
testWidgets('deleting an account with a password asks for it and a '
'code, which a wrong one fails, deleting nothing', (tester) async {
// The first person the fake password gateway makes.
const person = '00000000-0000-4000-8000-000000000001';
gateway = FakeAuthGateway(
status: const SignedIn(authUserId: person, isIdentified: true),
);
await start(tester);
dependencies.passwordGateway.addAccount(
'anna@example.org',
password: 'correct horse',
crypto: dependencies.crypto,
);
Finder field(String label) => find.widgetWithText(TextField, label);
await tester.tap(find.text('Delete account'));
await tester.pumpAndSettle();
await tester.tap(find.text('Delete account').last);
await tester.pumpAndSettle();
expect(gateway.accountDeletions, 0);
expect(field('Current password'), findsOneWidget);
await tester.enterText(field('Current password'), 'wrong horse');
await tester.enterText(
field('Code from your authenticator app'),
fakeTotpCode,
);
await tester.tap(find.text('Delete account').last);
await tester.pumpAndSettle();
expect(
find.text("The address, the password or the code isn't right."),
findsOneWidget,
);
expect(gateway.accountDeletions, 0);
expect(dependencies.passwordGateway.accounts, contains('anna@example.org'));
await tester.enterText(field('Current password'), 'correct horse');
await tester.tap(find.text('Delete account').last);
await tester.pumpAndSettle();
expect(gateway.accountDeletions, 1);
expect(
dependencies.passwordGateway.accounts,
isNot(contains('anna@example.org')),
);
expect(find.text('Signed out'), findsOneWidget);
});
testWidgets('speaks German', (tester) async {
await start(tester);
final german = lookupHalkyonAppLocalizations(const Locale('de'));
expect(
german.accountAnonymousOn('test.example.org'),
'Anonym auf test.example.org',
);
expect(german.accountSignedInOn('x'), 'Angemeldet auf x');
expect(german.accountSwitch, 'Konto wechseln');
expect(german.accountSignOut, 'Abmelden');
expect(german.accountSignOutTitle, 'Abmelden?');
expect(german.accountDelete, 'Konto löschen');
expect(german.accountDeleteTitle, 'Dein Konto löschen?');
});
}