Skip to content

Commit f06b866

Browse files
committed
fix(voice): let a failed STT probe recover on a later mount
The app QueryClient sets retryOnMount: false and retry: 1, and refetchOnWindowFocus only refetches stale queries — which an infinite staleTime never becomes. So one transient failure cached the error for the life of the client and hid the mic until a full page reload. The effect this replaced refetched on every run, so retryOnMount: true restores parity: no refetch after success, a retry per mount after failure. Test asserts recovery under the app's real query defaults and fails without the override.
1 parent 7af7b83 commit f06b866

2 files changed

Lines changed: 35 additions & 2 deletions

File tree

apps/sim/hooks/queries/voice.test.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import { useVoiceSettings, voiceSettingsKeys } from '@/hooks/queries/voice'
1616
/** Trees rendered by a test, torn down in afterEach so observers do not leak across tests. */
1717
const mountedRoots: Root[] = []
1818

19-
function renderHookWithClient<T>(useHook: () => T): { getResult: () => T } {
19+
function renderHookWithClient<T>(
20+
useHook: () => T,
21+
queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })
22+
): { getResult: () => T } {
2023
;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
21-
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })
2224
const container = document.createElement('div')
2325
const root: Root = createRoot(container)
2426
mountedRoots.push(root)
@@ -102,6 +104,30 @@ describe('useVoiceSettings', () => {
102104
expect(getResult().isError).toBe(true)
103105
})
104106

107+
/**
108+
* The app's QueryClient sets `retryOnMount: false`, and an infinite staleTime
109+
* never goes stale, so without an explicit override a single transient
110+
* failure would cache the error for the life of the client and keep the mic
111+
* hidden until a full reload.
112+
*/
113+
it('recovers on a later mount after a failed probe, under the app query defaults', async () => {
114+
const appDefaults = new QueryClient({
115+
defaultOptions: { queries: { retry: false, retryOnMount: false, staleTime: 30 * 1000 } },
116+
})
117+
118+
mockRequestJson.mockRejectedValueOnce(new Error('offline'))
119+
renderHookWithClient(() => useVoiceSettings(), appDefaults)
120+
await flush()
121+
expect(mockRequestJson).toHaveBeenCalledTimes(1)
122+
123+
mockRequestJson.mockResolvedValue({ sttAvailable: true })
124+
const second = renderHookWithClient(() => useVoiceSettings(), appDefaults)
125+
await flush()
126+
127+
expect(mockRequestJson).toHaveBeenCalledTimes(2)
128+
expect(second.getResult().data).toBe(true)
129+
})
130+
105131
it('dedupes across simultaneous consumers', async () => {
106132
mockRequestJson.mockResolvedValue({ sttAvailable: true })
107133

apps/sim/hooks/queries/voice.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@ async function fetchSttAvailable(signal?: AbortSignal): Promise<boolean> {
3131
* Deliberately no `initialData`: consumers derive their support flag from
3232
* `data === true`, so the first client render matches the server render
3333
* (unavailable) until the fetch resolves.
34+
*
35+
* `retryOnMount` overrides the app default of `false`. An infinite staleTime
36+
* never goes stale, and `refetchOnWindowFocus` only refetches stale queries, so
37+
* without this a single transient failure would cache the error for the life of
38+
* the QueryClient and hide the mic until a full reload. Retrying per mount
39+
* matches the effect this replaced, which refetched every time it ran.
3440
*/
3541
export function useVoiceSettings(options?: { enabled?: boolean }) {
3642
return useQuery({
3743
queryKey: voiceSettingsKeys.settings(),
3844
queryFn: ({ signal }) => fetchSttAvailable(signal),
3945
enabled: options?.enabled ?? true,
4046
staleTime: VOICE_SETTINGS_STALE_TIME,
47+
retryOnMount: true,
4148
})
4249
}

0 commit comments

Comments
 (0)