diff --git a/apps/desktop/src/lib/chat-runtime.test.ts b/apps/desktop/src/lib/chat-runtime.test.ts index 1b4efb33ad5..46ebcfefb1a 100644 --- a/apps/desktop/src/lib/chat-runtime.test.ts +++ b/apps/desktop/src/lib/chat-runtime.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import type { ComposerAttachment } from '@/store/composer' -import { coerceThinkingText, optimisticAttachmentRef, parseCommandDispatch } from './chat-runtime' +import { attachmentDisplayText, coerceThinkingText, optimisticAttachmentRef, parseCommandDispatch } from './chat-runtime' const DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANS' @@ -36,6 +36,32 @@ describe('optimisticAttachmentRef', () => { '@file:src/a.ts' ) }) + + // Session switches / draft restores can leave undefined|null holes in the + // composer attachments array. AttachmentList already filters them (#49624), + // but the submit path maps the same array through these helpers — an unguarded + // hole threw "Cannot read properties of undefined (reading 'refText')", + // crashing the chat surface (blank pane). The helpers must no-op on holes. + it('returns null for an undefined attachment instead of throwing', () => { + expect(() => optimisticAttachmentRef(undefined as unknown as ComposerAttachment)).not.toThrow() + expect(optimisticAttachmentRef(undefined as unknown as ComposerAttachment)).toBeNull() + }) + + it('returns null for a null attachment instead of throwing', () => { + expect(optimisticAttachmentRef(null as unknown as ComposerAttachment)).toBeNull() + }) +}) + +describe('attachmentDisplayText', () => { + it('returns null for undefined|null instead of reading .kind/.refText on a hole', () => { + expect(() => attachmentDisplayText(undefined as unknown as ComposerAttachment)).not.toThrow() + expect(attachmentDisplayText(undefined as unknown as ComposerAttachment)).toBeNull() + expect(attachmentDisplayText(null as unknown as ComposerAttachment)).toBeNull() + }) + + it('still resolves a normal file ref', () => { + expect(attachmentDisplayText(attachment({ kind: 'file', refText: '@file:src/a.ts' }))).toBe('@file:src/a.ts') + }) }) describe('coerceThinkingText', () => {