fix(app): GitHub's refusals say why, and no hint adds GitHub where passwords are offered

Where an instance offers password sign-in, GitHub is added to nobody (ADR
0017, D2), yet the start screen still said "then add GitHub" after a GitHub
account nobody has, and every refusal but an unknown account read
"Couldn't sign in with GitHub." (the end-to-end test of 21 Oct).

- The gateway tells from one read of the basics whether GitHub signs in and
  whether it is added to people (`gitHubOffer`, in place of
  `gitHubClientId`); the GitHub bloc keeps it (`Ready.linking`) for the
  profile, with why an attempt failed (`Ready.problem`).
- The instance's `usePassword`, `deprecated` and `ended` become problems of
  their own (`gitHubSignInProblemOf`), worded by `gitHubProblemText` and on
  the start screen; an anonymous person refused a link is told the GitHub
  account is nobody's and offered the password instead.
- Where passwords are offered, the start screen offers an account to create
  in place of the app's hint on adding GitHub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-21 19:19:28 +02:00
commit 19aabb0266
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -15,13 +15,23 @@ void main() {
/// The home tab.
final home = find.byType(HomeScreen);
Future<void> showApp(WidgetTester tester) =>
pumpApp(tester, testDependencies(authGateway: gateway));
/// Shows the app, on an instance offering passwords unless [passwords] is
/// false.
Future<void> showApp(WidgetTester tester, {bool passwords = true}) => pumpApp(
tester,
testDependencies(
authGateway: gateway,
passwordGateway: FakePasswordGateway(gateway)..offered = passwords,
),
);
/// Shows the app and opens settings, from the profile tab, down to the
/// account.
Future<void> openSettings(WidgetTester tester) async {
await showApp(tester);
Future<void> openSettings(
WidgetTester tester, {
bool passwords = true,
}) async {
await showApp(tester, passwords: passwords);
await openTab(tester, 'Profile');
await tester.tap(find.byTooltip('Settings'));
await tester.pumpAndSettle();
@ -156,7 +166,8 @@ void main() {
});
testWidgets('from there, a GitHub account nobody here signs in with is said '
'so, with where Learn adds GitHub', (tester) async {
'so, with an account to create in its place where passwords are '
'offered (ADR 0017)', (tester) async {
await openSettings(tester);
await tester.tap(find.text('Sign out'));
await tester.pumpAndSettle();
@ -169,6 +180,31 @@ void main() {
await tester.tap(find.text('Sign in with GitHub'));
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.',
),
findsOneWidget,
);
expect(gateway.status, const SignedOut());
});
testWidgets('where no passwords are offered, with where Learn adds GitHub', (
tester,
) async {
await openSettings(tester, passwords: false);
await tester.tap(find.text('Sign out'));
await tester.pumpAndSettle();
await tester.tap(find.text('Sign out').last);
await tester.pumpAndSettle();
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 yet. Start '
@ -176,7 +212,6 @@ void main() {
),
findsOneWidget,
);
expect(gateway.status, const SignedOut());
});
testWidgets('deleting the account asks first; Cancel keeps it', (