test(desktop): leftover 4001 rebind must not revive a deleted session
Cover the delete-transition race and the tombstone early-return so the Resume failed toast cannot come back through those paths.
This commit is contained in:
@@ -101,6 +101,60 @@ describe('useRouteResume', () => {
|
||||
expect(resumeSession).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not honor a leftover 4001 rebind during a /:sid -> /new delete transition', () => {
|
||||
const resumeSession = vi.fn(async () => undefined)
|
||||
const startFreshSessionDraft = vi.fn()
|
||||
const activeSessionIdRef: MutableRefObject<null | string> = { current: 'runtime-1' }
|
||||
const creatingSessionRef = { current: false }
|
||||
const runtimeIdByStoredSessionIdRef = { current: new Map([['session-1', 'runtime-1']]) }
|
||||
const selectedStoredSessionIdRef: MutableRefObject<null | string> = { current: 'session-1' }
|
||||
|
||||
const { rerender } = render(
|
||||
<RouteResumeHarness
|
||||
activeSessionId="runtime-1"
|
||||
activeSessionIdRef={activeSessionIdRef}
|
||||
creatingSessionRef={creatingSessionRef}
|
||||
currentView="chat"
|
||||
freshDraftReady={false}
|
||||
gatewayState="open"
|
||||
locationPathname="/session-1"
|
||||
resumeSession={resumeSession}
|
||||
routedSessionId="session-1"
|
||||
runtimeIdByStoredSessionIdRef={runtimeIdByStoredSessionIdRef}
|
||||
selectedStoredSessionId="session-1"
|
||||
selectedStoredSessionIdRef={selectedStoredSessionIdRef}
|
||||
startFreshSessionDraft={startFreshSessionDraft}
|
||||
/>
|
||||
)
|
||||
|
||||
expect(resumeSession).not.toHaveBeenCalled()
|
||||
|
||||
// Idle reap queued requestSessionResume, then the user deleted the chat.
|
||||
// Draft state lands before React Router flips /:sid -> /new.
|
||||
activeSessionIdRef.current = null
|
||||
selectedStoredSessionIdRef.current = null
|
||||
rerender(
|
||||
<RouteResumeHarness
|
||||
activeSessionId={null}
|
||||
activeSessionIdRef={activeSessionIdRef}
|
||||
creatingSessionRef={creatingSessionRef}
|
||||
currentView="chat"
|
||||
freshDraftReady
|
||||
gatewayState="open"
|
||||
locationPathname="/session-1"
|
||||
resumeSession={resumeSession}
|
||||
routedSessionId="session-1"
|
||||
runtimeIdByStoredSessionIdRef={runtimeIdByStoredSessionIdRef}
|
||||
selectedStoredSessionId={null}
|
||||
selectedStoredSessionIdRef={selectedStoredSessionIdRef}
|
||||
sessionResumeRequest={{ sequence: 1, sessionId: 'session-1' }}
|
||||
startFreshSessionDraft={startFreshSessionDraft}
|
||||
/>
|
||||
)
|
||||
|
||||
expect(resumeSession).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('self-heals a stranded routed session (null selected/active, same pathname, not a fresh draft)', () => {
|
||||
const resumeSession = vi.fn(async () => undefined)
|
||||
const startFreshSessionDraft = vi.fn()
|
||||
|
||||
@@ -1077,6 +1077,8 @@ describe('resumeSession failure recovery', () => {
|
||||
setResumeFailedSessionId(null)
|
||||
setMessages([])
|
||||
setSessions([])
|
||||
$removedSessionIds.set(new Set())
|
||||
$sessionMutationsInFlight.set(new Set())
|
||||
clearClarifyRequest()
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
@@ -1094,6 +1096,20 @@ describe('resumeSession failure recovery', () => {
|
||||
await resume!('stored-1', true)
|
||||
}
|
||||
|
||||
it('does not resume a tombstoned session after delete', async () => {
|
||||
$removedSessionIds.set(new Set(['stored-1']))
|
||||
|
||||
const requestGateway = vi.fn(async () => {
|
||||
throw new Error('404: Session not found')
|
||||
})
|
||||
|
||||
await runResume(requestGateway)
|
||||
|
||||
expect(requestGateway).not.toHaveBeenCalled()
|
||||
expect($resumeFailedSessionId.get()).toBeNull()
|
||||
expect($selectedStoredSessionId.get()).toBeNull()
|
||||
})
|
||||
|
||||
it.each([
|
||||
['Codex tool-only', ''],
|
||||
['DeepSeek text-plus-tool', 'I found two paths; choose one.']
|
||||
|
||||
Reference in New Issue
Block a user