feat(app)!: no anonymous accounts on the device (ADR 0020, D4, D25)
Every account has a way in, so the apps make no anonymous account any more. The start screen shows whenever nobody is signed in, a first start included, and offers SimpleLogin, a password and GitHub for those who have it, with no start without an account. An instance out of reach is said so, with Try again, and one offering no way to create an account too. An anonymous account's session left from before is deleted as the app starts (D25), falling back to signing out on the device. What only anonymous accounts needed goes: signing in anonymously, the signed-out mark, adding GitHub to an account and switching to a GitHub account from the Profile tab (with its Cancel, the only one), an anonymous device's own keys, the warning that signing out deletes the account, and the texts about keeping progress. Settings says on which instance the account is signed in. Learn's publishing, reports and suggestions and its learner count no longer ask whether the person has an identity: everyone signed in has one. The server still offers anonymous sign-in until the next commit, so older apps keep working until v0.20.0 raises the minimum build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
fad12b4411
commit
5b9df73756
1 changed files with 981 additions and 3339 deletions
|
|
@ -54,53 +54,61 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('shows the app once signed in anonymously at a first start', (
|
||||
/// Nobody signed in, as at a first start, on an instance offering every
|
||||
/// way in.
|
||||
void signedOut() {
|
||||
gateway = FakeAuthGateway(status: const SignedOut());
|
||||
dependencies = TestAppDependencies(gateway: gateway);
|
||||
dependencies.simpleLoginGateway.isOffered = true;
|
||||
}
|
||||
|
||||
testWidgets("shows the signed-in person's app", (tester) async {
|
||||
await start(tester);
|
||||
|
||||
expect(find.text('App of person-1'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('nobody signed in, it asks how to start on the instance, '
|
||||
'making no account: there is no starting without one (ADR 0020, D4)', (
|
||||
tester,
|
||||
) async {
|
||||
signedOut();
|
||||
await start(tester);
|
||||
|
||||
expect(find.text('App of anonymous-1'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('offers to try again when signing in fails', (tester) async {
|
||||
gateway.signInError = Exception('No connection');
|
||||
await start(tester);
|
||||
|
||||
expect(find.text("Couldn't reach the server."), findsOneWidget);
|
||||
|
||||
gateway.signInError = null;
|
||||
await tester.tap(find.text('Try again'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('App of anonymous-2'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('signed out, it asks how to start on the instance, making no '
|
||||
'account; starting without one makes one', (tester) async {
|
||||
await dependencies.signedOut.write(signedOut: true);
|
||||
await start(tester);
|
||||
|
||||
expect(find.text('Signed out'), findsOneWidget);
|
||||
expect(find.text('Halkyon Test'), findsOneWidget);
|
||||
expect(find.text('Start on test.example.org:'), findsOneWidget);
|
||||
expect(find.text('Sign in with GitHub'), findsOneWidget);
|
||||
expect(find.text('Continue with SimpleLogin'), findsOneWidget);
|
||||
expect(find.text('Sign in'), findsOneWidget);
|
||||
expect(find.text('Create an account'), findsOneWidget);
|
||||
expect(find.text('Sign in with GitHub'), findsOneWidget);
|
||||
expect(find.text('Start without an account'), findsNothing);
|
||||
expect(
|
||||
find.text('Use another instance'),
|
||||
findsNothing,
|
||||
reason: 'no instances to choose among here',
|
||||
);
|
||||
expect(gateway.signIns, 0);
|
||||
expect(gateway.status, const SignedOut());
|
||||
});
|
||||
|
||||
await tester.tap(find.text('Start without an account'));
|
||||
await tester.pumpAndSettle();
|
||||
testWidgets("an anonymous account's session left from before ends as the "
|
||||
'app starts, the account deleted, and the start screen asks (D25)', (
|
||||
tester,
|
||||
) async {
|
||||
gateway = FakeAuthGateway(
|
||||
status: const SignedIn(authUserId: 'anonymous-1', isIdentified: false),
|
||||
);
|
||||
dependencies = TestAppDependencies(gateway: gateway);
|
||||
await start(tester);
|
||||
|
||||
expect(find.text('App of anonymous-1'), findsOneWidget);
|
||||
expect(dependencies.signedOut.signedOut, isFalse);
|
||||
expect(find.text('App of anonymous-1'), findsNothing);
|
||||
expect(find.text('Start on test.example.org:'), findsOneWidget);
|
||||
expect(gateway.accountDeletions, 1);
|
||||
});
|
||||
|
||||
testWidgets('from there, GitHub signs in its person; a GitHub account '
|
||||
'nobody here has yet is said so, with an account to create in its '
|
||||
'place where passwords are offered (ADR 0017)', (tester) async {
|
||||
await dependencies.signedOut.write(signedOut: true);
|
||||
'nobody here has is said so, with SimpleLogin to create one in its '
|
||||
'place', (tester) async {
|
||||
signedOut();
|
||||
await start(tester);
|
||||
|
||||
gateway.gitHubError = const GitHubSignInFailed(
|
||||
|
|
@ -110,16 +118,11 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
find.text(
|
||||
'No account here signs in with this GitHub account yet. Create an '
|
||||
'account with your email address and a password instead.',
|
||||
'No account here signs in with this GitHub account. Continue with '
|
||||
'SimpleLogin to create one instead.',
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(
|
||||
find.textContaining('add GitHub'),
|
||||
findsNothing,
|
||||
reason: 'GitHub is added to nobody where passwords are offered',
|
||||
);
|
||||
|
||||
gateway.gitHubError = null;
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
|
|
@ -130,25 +133,14 @@ void main() {
|
|||
await tester.tap(find.text('Later'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('App of github-person'), findsOneWidget);
|
||||
expect(gateway.signIns, 0);
|
||||
});
|
||||
|
||||
testWidgets('after GitHub, offers no password to someone who has one, or '
|
||||
'where the instance offers none', (tester) async {
|
||||
dependencies.passwordGateway.offered = false;
|
||||
await dependencies.signedOut.write(signedOut: true);
|
||||
await start(tester);
|
||||
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Later'), findsNothing);
|
||||
expect(find.text('App of github-person'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('where no passwords are offered, a GitHub account nobody here '
|
||||
'has yet is said so with where the app adds GitHub', (tester) async {
|
||||
dependencies.passwordGateway.offered = false;
|
||||
await dependencies.signedOut.write(signedOut: true);
|
||||
testWidgets('where the instance offers passwords and no SimpleLogin, the '
|
||||
'account to create in its place has a password (ADR 0017)', (
|
||||
tester,
|
||||
) async {
|
||||
signedOut();
|
||||
dependencies.simpleLoginGateway.isOffered = false;
|
||||
await start(tester);
|
||||
|
||||
gateway.gitHubError = const GitHubSignInFailed(
|
||||
|
|
@ -158,17 +150,53 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
find.text(
|
||||
// The package's sentence, then the app's on where GitHub is added.
|
||||
'No account here signs in with this GitHub account yet. Start '
|
||||
'without an account, then add GitHub in Settings.',
|
||||
'No account here signs in with this GitHub account. Create an '
|
||||
'account with your email address and a password instead.',
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('after GitHub, offers no password to someone who has one, or '
|
||||
'where the instance offers none', (tester) async {
|
||||
signedOut();
|
||||
dependencies.passwordGateway.offered = false;
|
||||
await start(tester);
|
||||
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Later'), findsNothing);
|
||||
expect(find.text('App of github-person'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('an instance with no way to create an account says so, and '
|
||||
'GitHub signs in only those who have it', (tester) async {
|
||||
signedOut();
|
||||
dependencies.passwordGateway.offered = false;
|
||||
dependencies.simpleLoginGateway.isOffered = false;
|
||||
await start(tester);
|
||||
|
||||
expect(
|
||||
find.text('test.example.org offers no way to create an account.'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Continue with SimpleLogin'), findsNothing);
|
||||
expect(find.text('Create an account'), findsNothing);
|
||||
|
||||
gateway.gitHubError = const GitHubSignInFailed(
|
||||
GitHubSignInProblem.unknownAccount,
|
||||
);
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
find.text('No account here signs in with this GitHub account.'),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('an account that signs in with its password, and GitHub having '
|
||||
'ended, are each said so', (tester) async {
|
||||
await dependencies.signedOut.write(signedOut: true);
|
||||
signedOut();
|
||||
await start(tester);
|
||||
|
||||
gateway.gitHubError = const GitHubSignInFailed(
|
||||
|
|
@ -195,14 +223,39 @@ void main() {
|
|||
});
|
||||
|
||||
testWidgets('offers only the ways the instance has', (tester) async {
|
||||
signedOut();
|
||||
gateway.offersGitHub = false;
|
||||
dependencies.passwordGateway.offered = false;
|
||||
await dependencies.signedOut.write(signedOut: true);
|
||||
await start(tester);
|
||||
|
||||
expect(find.text('Continue with SimpleLogin'), findsOneWidget);
|
||||
expect(find.text('Sign in with GitHub'), findsNothing);
|
||||
expect(find.text('Create an account'), findsNothing);
|
||||
expect(find.text('Start without an account'), findsOneWidget);
|
||||
expect(find.textContaining('offers no way'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('an instance out of reach is said so, offering nothing, and '
|
||||
'asked again', (tester) async {
|
||||
signedOut();
|
||||
dependencies.passwordGateway.failing = const PasswordFailed(
|
||||
PasswordProblem.failed,
|
||||
);
|
||||
dependencies.simpleLoginGateway.failing = const SimpleLoginFailed(
|
||||
SimpleLoginProblem.failed,
|
||||
);
|
||||
gateway.offersGitHubError = Exception('No connection');
|
||||
await start(tester);
|
||||
|
||||
expect(find.text("Couldn't reach the server."), findsOneWidget);
|
||||
expect(find.text('Continue with SimpleLogin'), findsNothing);
|
||||
expect(find.textContaining('offers no way'), findsNothing);
|
||||
|
||||
gateway.offersGitHubError = null;
|
||||
dependencies.passwordGateway.failing = null;
|
||||
dependencies.simpleLoginGateway.failing = null;
|
||||
await tester.tap(find.text('Try again'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Continue with SimpleLogin'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('signing out, or the instance ending the session, asks how to '
|
||||
|
|
@ -216,14 +269,17 @@ void main() {
|
|||
|
||||
await tester.tap(find.text('Sign out'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Signed out'), findsOneWidget);
|
||||
expect(dependencies.signedOut.signedOut, isTrue);
|
||||
expect(find.text('Start on test.example.org:'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Start without an account'));
|
||||
gateway.gitHubError = null;
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Later'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('App of github-person'), findsOneWidget);
|
||||
gateway.revokeSession();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Signed out'), findsOneWidget);
|
||||
expect(find.text('Start on test.example.org:'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets("a sign-out under way or failed leaves the person's app as it "
|
||||
|
|
|
|||
Loading…
Reference in a new issue