From 32c79f6e2999a684cda07730844db66052831ff9 Mon Sep 17 00:00:00 2001 From: jim139129 Date: Fri, 17 Jul 2026 17:51:15 +0800 Subject: [PATCH] fix(stage-ui): allow retrying canceled mobile login (#2058) --- packages/stage-ui/src/stores/auth.test.ts | 40 +++++++++++++++++++++++ packages/stage-ui/src/stores/auth.ts | 5 +++ 2 files changed, 45 insertions(+) create mode 100644 packages/stage-ui/src/stores/auth.test.ts diff --git a/packages/stage-ui/src/stores/auth.test.ts b/packages/stage-ui/src/stores/auth.test.ts new file mode 100644 index 000000000..1d79963c0 --- /dev/null +++ b/packages/stage-ui/src/stores/auth.test.ts @@ -0,0 +1,40 @@ +import { createPinia, setActivePinia } from 'pinia' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { nextTick } from 'vue' + +import { triggerSignIn } from '../libs/auth' +import { useAuthStore } from './auth' + +vi.mock('../libs/auth', () => ({ + triggerSignIn: vi.fn(), +})) + +describe('auth store sign-in requests', () => { + beforeEach(() => { + setActivePinia(createPinia()) + vi.mocked(triggerSignIn).mockReset() + vi.mocked(triggerSignIn).mockResolvedValue() + }) + + it('allows sign-in to be requested again after an external flow is canceled', async () => { + const authStore = useAuthStore() + + // ROOT CAUSE: + // + // Pocket remains mounted after launching the external login page. If the + // user returns without authenticating, `needsLogin` used to remain true, + // so a later click could not produce the transition that triggers sign-in. + // Consuming each request restores the false -> true transition. + authStore.needsLogin = true + await nextTick() + + expect(triggerSignIn).toHaveBeenCalledTimes(1) + expect(authStore.needsLogin).toBe(false) + + authStore.needsLogin = true + await nextTick() + + expect(triggerSignIn).toHaveBeenCalledTimes(2) + expect(authStore.needsLogin).toBe(false) + }) +}) diff --git a/packages/stage-ui/src/stores/auth.ts b/packages/stage-ui/src/stores/auth.ts index e0a05c343..56a005f92 100644 --- a/packages/stage-ui/src/stores/auth.ts +++ b/packages/stage-ui/src/stores/auth.ts @@ -50,6 +50,11 @@ export const useAuthStore = defineStore('auth', () => { whenever(needsLogin, async () => { if (isStageTamagotchi()) return + + // Consume the request before opening an external browser. Pocket stays + // mounted when the user cancels there, so leaving this true would make + // the next button click a no-op instead of starting a new OIDC flow. + needsLogin.value = false await triggerSignIn() })