From 7243111c57bb6fad870e2eee7eda4cfcada4d7af Mon Sep 17 00:00:00 2001 From: infinitycrew39 Date: Tue, 23 Jun 2026 23:25:25 +0700 Subject: [PATCH] test(desktop): cover fallback timeout onboarding downgrade regression --- apps/desktop/src/store/onboarding.test.ts | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/apps/desktop/src/store/onboarding.test.ts b/apps/desktop/src/store/onboarding.test.ts index 7173e89f572..ffd06b912d0 100644 --- a/apps/desktop/src/store/onboarding.test.ts +++ b/apps/desktop/src/store/onboarding.test.ts @@ -63,6 +63,16 @@ function onboardingContext(requestGateway: OnboardingContext['requestGateway']): return { requestGateway } } +function fallbackTimeoutGateway(): OnboardingContext['requestGateway'] { + return async method => { + if (method === 'setup.status' || method === 'setup.runtime_check') { + throw new Error(`request timed out: ${method}`) + } + + throw new Error(`unexpected gateway method: ${method}`) + } +} + describe('refreshOnboarding', () => { beforeEach(() => { window.localStorage.clear() @@ -116,6 +126,54 @@ describe('refreshOnboarding', () => { expect($desktopOnboarding.get().providers?.map(p => p.id)).toEqual(['cached']) }) + it('does not downgrade configured=true on fallback-only readiness failures', async () => { + const api = vi.fn(async ({ path }: { path: string }) => { + if (path === '/api/providers/oauth') { + return { providers: [provider('fresh')] } + } + + throw new Error(`unexpected api path: ${path}`) + }) + + installApiMock(api) + $desktopOnboarding.set( + baseState({ + configured: true, + providers: [provider('cached')], + reason: null, + requested: false + }) + ) + + const ready = await refreshOnboarding(onboardingContext(fallbackTimeoutGateway())) + + expect(ready).toBe(false) + expect(api).not.toHaveBeenCalled() + expect($desktopOnboarding.get().configured).toBe(true) + expect($desktopOnboarding.get().reason).toBeNull() + expect(window.localStorage.getItem('hermes-desktop-onboarded-v1')).toBeNull() + }) + + it('still surfaces onboarding when fallback failure happens before configured state', async () => { + const api = vi.fn(async ({ path }: { path: string }) => { + if (path === '/api/providers/oauth') { + return { providers: [provider('fresh')] } + } + + throw new Error(`unexpected api path: ${path}`) + }) + + installApiMock(api) + $desktopOnboarding.set(baseState({ configured: false, providers: null, requested: true })) + + const ready = await refreshOnboarding(onboardingContext(fallbackTimeoutGateway())) + + expect(ready).toBe(false) + expect(api).toHaveBeenCalledTimes(1) + expect($desktopOnboarding.get().configured).toBe(false) + expect($desktopOnboarding.get().reason).toContain('request timed out') + }) + it('deduplicates concurrent provider refresh calls', async () => { let resolveProviders!: (value: { providers: OAuthProvider[] }) => void