Merge branch 'master' into feat/web-plugin-settings-tabs
This commit is contained in:
@@ -143,8 +143,55 @@ it('accepts pasted images into the composer rail in order and removes them', asy
|
||||
},
|
||||
})
|
||||
const toast = await screen.findByRole('alert')
|
||||
expect(toast.textContent).toContain('Unsupported image format: text/plain')
|
||||
expect(toast.textContent).toContain('Only PNG, JPG, WebP, and GIF images are supported')
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByRole('alert')).toBeNull()
|
||||
}, { timeout: 6_000 })
|
||||
})
|
||||
|
||||
it('accepts a whole-page drop under the limits-labeled overlay and refuses an over-limit batch at intake', async () => {
|
||||
mountAssembledApp()
|
||||
|
||||
const tree = await screen.findByRole('tree', { name: 'Sessions' }, { timeout: 10_000 })
|
||||
const start = tree.querySelector<HTMLButtonElement>('button[aria-label="New session in fixture"]')
|
||||
if (start === null) throw new Error('fixture Workspace new-session action missing')
|
||||
fireEvent.click(start)
|
||||
const textarea = await screen.findByPlaceholderText('Describe what you want to build', {}, { timeout: 10_000 })
|
||||
|
||||
// A file drag anywhere over the page raises the full-viewport overlay whose
|
||||
// desc line carries the projected limits — copy that can only render after
|
||||
// the imageLimits projection crossed the real fixture transport.
|
||||
const image = new File([new Uint8Array([137, 80, 78, 71])], 'dropped.png', { type: 'image/png' })
|
||||
const dataTransfer = { types: ['Files'], files: [image], dropEffect: 'none' }
|
||||
fireEvent.dragEnter(document.body, { dataTransfer })
|
||||
const overlay = await screen.findByRole('status')
|
||||
expect(overlay.textContent).toContain('Drag images here to add them')
|
||||
await waitFor(() => {
|
||||
expect(overlay.textContent).toContain('Up to 20 images, 5MB each')
|
||||
})
|
||||
|
||||
// Dropping on the transcript area (not the composer card) lands in the rail.
|
||||
fireEvent.drop(document.body, { dataTransfer })
|
||||
await waitFor(() => {
|
||||
const rail = document.querySelector('[role="group"][aria-label="Pending images"]')
|
||||
if (rail === null) throw new Error('attachment rail missing after page drop')
|
||||
expect([...rail.querySelectorAll('img')].map(img => img.getAttribute('alt'))).toEqual(['dropped.png'])
|
||||
}, { timeout: 5_000 })
|
||||
expect(screen.queryByRole('status')).toBeNull()
|
||||
|
||||
// An intake that would exceed the projected per-message count is refused as
|
||||
// a whole batch at add time: the banner names the limit and the rail keeps
|
||||
// only the previously accepted thumbnail — no submit-time rollback.
|
||||
const batch = Array.from({ length: 20 }, (_, i) =>
|
||||
new File([new Uint8Array([137, 80, 78, 71])], `bulk-${String(i)}.png`, { type: 'image/png' }))
|
||||
fireEvent.paste(textarea, {
|
||||
clipboardData: {
|
||||
items: batch.map(file => ({ kind: 'file', type: 'image/png', getAsFile: () => file })),
|
||||
getData: () => '',
|
||||
},
|
||||
})
|
||||
const banner = await screen.findByRole('alert')
|
||||
expect(banner.textContent).toContain('A message can include up to 20 images')
|
||||
const rail = document.querySelector('[role="group"][aria-label="Pending images"]')
|
||||
expect([...(rail?.querySelectorAll('img') ?? [])]).toHaveLength(1)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user