fix(auth): offer Google on the sign-up tab, not only on Log In (#345) #354

Merged
bermudalamb merged 2 commits from fix/google-button-missing-on-signup into main 2026-09-11 10:06:55 -05:00
3 changed files with 51 additions and 2 deletions
+21
View File
@@ -233,6 +233,27 @@ export default function AuthForm({ mode, onModeChange, onForgotPassword, onSucce
By creating an account you agree to our{' '}
<a href="/privacy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>.
</Text>
{/* On this tab too, and its absence here was a bug (#345).
A passkey belongs only on Log In, because you cannot
register an account with one — but creating an account is
exactly what a new customer reaches for Google to do, so
leaving it off the sign-up tab hid the feature from the
people it helps most.
The two consent boxes above are not carried across. Google
takes the customer off this site entirely, and a tick that
survived that round trip would be a consent recorded from a
form nobody submitted. They are asked again, with the same
wording, on the step they land on (#342). */}
{googleEnabled && (
<>
<Divider plain style={{ marginBlock: 16 }}>
<Text type="secondary" style={{ fontSize: 12 }}>or</Text>
</Divider>
<GoogleSignInButton returnTo={returnTo} intent="sign-up" />
</>
)}
</Form>
)
},
+13 -2
View File
@@ -37,6 +37,17 @@ function GoogleMark() {
type Props = Readonly<{
/** Where to send the customer back to. Validated again on the server. */
returnTo: string;
/**
* Which tab this sits on, which changes only the wording.
*
* One endpoint serves both: it signs in a known identity, links a verified
* address, or creates an account. The customer does not know or care which
* of those will happen, so the label matches what they came to the tab to
* do rather than what the server ends up doing.
*
* Both spellings are in Google identity guidelines alongside the mark.
*/
intent?: 'sign-in' | 'sign-up';
}>;
/**
@@ -51,7 +62,7 @@ type Props = Readonly<{
* here. It has to be, since anyone can type the URL, and doing it in one place
* beats doing it in two languages. See `google/returnTo.ts`.
*/
export default function GoogleSignInButton({ returnTo }: Props) {
export default function GoogleSignInButton({ returnTo, intent = 'sign-in' }: Props) {
return (
<Button
block
@@ -62,7 +73,7 @@ export default function GoogleSignInButton({ returnTo }: Props) {
window.location.assign(`/api/auth/google/start?returnTo=${encodeURIComponent(returnTo)}`);
}}
>
Sign in with Google
{intent === 'sign-up' ? 'Sign up with Google' : 'Sign in with Google'}
</Button>
);
}
+17
View File
@@ -124,6 +124,23 @@ test.describe('Customer accounts', () => {
// So the button being ABSENT is the behaviour under test here, and it is the
// one that matters: a control that appears and then fails at Google is worse
// than one that was never offered.
// The sign-up tab, which #345 left it off entirely. A passkey belongs only on
// Log In, because you cannot register an account with one — but creating an
// account is exactly what a new customer reaches for Google to do, so its
// absence there hid the feature from the people it helps most.
//
// Asserted as absent for the same reason as the login one: local and QA have
// no credentials, so absence is the behaviour that actually runs here.
test('offers no Google button on the sign-up tab either, when unconfigured', async ({
authModal
}) => {
await authModal.gotoRegister();
await expect(
authModal.registerDialog.getByRole('button', { name: /with Google/i })
).toHaveCount(0);
});
test('offers no Google button when the environment is not configured for it', async ({
authModal,
accountModal,