fix(desktop): match current assistant-ui lookup errors
This commit is contained in:
parent
0405c26645
commit
bb9434d307
|
|
@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|||
|
||||
import { ErrorBoundary } from './error-boundary'
|
||||
|
||||
const TAP_LOOKUP_ERROR = new Error('tapClientLookup: Index 6 out of bounds (length: 2)')
|
||||
const CURRENT_LOOKUP_ERROR = new Error('useClientLookup: Index 6 out of bounds (length: 2)')
|
||||
const RELOAD_WINDOW = { name: 'Reload window', role: 'button' } as const
|
||||
|
||||
function makeBomb(box: { error: Error | null }) {
|
||||
|
|
@ -17,9 +17,9 @@ function makeBomb(box: { error: Error | null }) {
|
|||
}
|
||||
|
||||
const recoveryWarningCount = (calls: unknown[][]) =>
|
||||
calls.filter(call => call.some(value => String(value).includes('auto-recovering from tapClientLookup'))).length
|
||||
calls.filter(call => call.some(value => String(value).includes('auto-recovering from assistant-ui lookup'))).length
|
||||
|
||||
describe('ErrorBoundary tapClientLookup recovery', () => {
|
||||
describe('ErrorBoundary assistant-ui lookup recovery', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.spyOn(console, 'error').mockImplementation(() => undefined)
|
||||
|
|
@ -31,9 +31,13 @@ describe('ErrorBoundary tapClientLookup recovery', () => {
|
|||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('recovers the root boundary after a transient lookup race clears', () => {
|
||||
it.each([
|
||||
['the current useClientLookup error', CURRENT_LOOKUP_ERROR],
|
||||
['the legacy tapClientLookup error', new Error('tapClientLookup: Index 6 out of bounds (length: 2)')],
|
||||
['the legacy tapClientResource error', new Error('tapClientResource: Index 6 out of bounds (length: 2)')]
|
||||
])('recovers the root boundary after %s clears', (_label, error) => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
||||
const box: { error: Error | null } = { error: TAP_LOOKUP_ERROR }
|
||||
const box: { error: Error | null } = { error }
|
||||
const Bomb = makeBomb(box)
|
||||
|
||||
render(
|
||||
|
|
@ -52,7 +56,7 @@ describe('ErrorBoundary tapClientLookup recovery', () => {
|
|||
|
||||
it('stops retrying a persistent lookup error after the recovery budget is exhausted', () => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
||||
const box: { error: Error | null } = { error: TAP_LOOKUP_ERROR }
|
||||
const box: { error: Error | null } = { error: CURRENT_LOOKUP_ERROR }
|
||||
const Bomb = makeBomb(box)
|
||||
|
||||
render(
|
||||
|
|
@ -72,7 +76,7 @@ describe('ErrorBoundary tapClientLookup recovery', () => {
|
|||
|
||||
it('does not auto-recover the same error in a scoped boundary', () => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
||||
const Bomb = makeBomb({ error: TAP_LOOKUP_ERROR })
|
||||
const Bomb = makeBomb({ error: CURRENT_LOOKUP_ERROR })
|
||||
|
||||
render(
|
||||
<ErrorBoundary fallback={() => <div>scoped fallback</div>} label="thread">
|
||||
|
|
@ -87,7 +91,7 @@ describe('ErrorBoundary tapClientLookup recovery', () => {
|
|||
})
|
||||
|
||||
it.each([
|
||||
['a renamed lookup error', new Error('useClientLookup: Index 6 out of bounds (length: 2)')],
|
||||
['a non-bounds lookup error', new Error('useClientLookup: Key "missing" not found')],
|
||||
['an unrelated render error', new Error('some unrelated application error')]
|
||||
])('does not auto-recover %s at root', (_label, error) => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ interface ErrorBoundaryState {
|
|||
// Some assistant-ui lookup races escape the message-local boundary and reach
|
||||
// the root. Retry only that exact transient error class, never arbitrary render
|
||||
// failures, and cap retries so a persistent failure still exposes the fallback.
|
||||
const TAP_CLIENT_LOOKUP_ERROR = /^tapClientLookup: Index \d+\s+out of bounds \(length:\s*\d+\)$/i
|
||||
const ASSISTANT_UI_LOOKUP_ERROR = /(useClientLookup|tapClient(Lookup|Resource)).*out of bounds/i
|
||||
const MAX_AUTO_RECOVERIES = 3
|
||||
const AUTO_RECOVERY_WINDOW_MS = 5_000
|
||||
|
||||
const isTransientTapClientLookupError = (error: Error): boolean => TAP_CLIENT_LOOKUP_ERROR.test(error.message)
|
||||
const isTransientAssistantUiLookupError = (error: Error): boolean => ASSISTANT_UI_LOOKUP_ERROR.test(error.message)
|
||||
|
||||
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
||||
state: ErrorBoundaryState = { error: null }
|
||||
|
|
@ -44,8 +44,8 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|||
console.error(tag, error, info.componentStack)
|
||||
this.props.onError?.(error, info)
|
||||
|
||||
if (this.props.label === 'root' && isTransientTapClientLookupError(error) && this.takeAutoRecoveryAttempt()) {
|
||||
console.warn(`${tag} auto-recovering from tapClientLookup render race`, error.message)
|
||||
if (this.props.label === 'root' && isTransientAssistantUiLookupError(error) && this.takeAutoRecoveryAttempt()) {
|
||||
console.warn(`${tag} auto-recovering from assistant-ui lookup render race`, error.message)
|
||||
this.scheduleAutoRecovery()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue