fix(admin): preview public images through the admin thumb route when their URL fails
When a public image's thumb_url or url fails to load, the fileupload field fetches its preview once through the authenticated thumb route (session key in the header) and shows it from an object URL, revoked when the item is forgotten and on unmount. The preview is reported as unavailable only when that fetch or the object-URL image fails too. Protected fields behave as before.
This commit is contained in:
@@ -355,6 +355,79 @@ describe('protected thumbnails (backstop 3)', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('public preview fallback', () => {
|
||||
const thumbPath = `${BASE}/7/files/photos/41/thumb`
|
||||
|
||||
it('previews a public image through the thumb route when its URL fails and revokes the object URL on unmount', async () => {
|
||||
const create = vi.fn(() => 'blob:fallback-41')
|
||||
const revoke = vi.fn()
|
||||
objectUrls(create, revoke)
|
||||
const { wrapper, calls } = await setup({
|
||||
routes: {
|
||||
[`GET ${BASE}/7/files/photos`]: listOf([item(41, 'a.png')]),
|
||||
[`GET ${thumbPath}`]: () => ({ body: 'png-bytes' }),
|
||||
},
|
||||
})
|
||||
expect(wrapper.find('[data-file-item] img').attributes('src')).toBe('/storage/app/uploads/public/thumb_a.png')
|
||||
expect(requestsTo(calls, 'GET', thumbPath)).toHaveLength(0)
|
||||
await wrapper.find('[data-file-item] img').trigger('error')
|
||||
await flushPromises()
|
||||
const [thumb] = requestsTo(calls, 'GET', thumbPath)
|
||||
expect(thumb).toBeDefined()
|
||||
expect(thumb!.headers.get(SESSION_HEADER)).toBe(KEY)
|
||||
expect(new URL(thumb!.url).search).toBe('')
|
||||
expect(create).toHaveBeenCalledTimes(1)
|
||||
expect(wrapper.find('[data-file-item] img').attributes('src')).toBe('blob:fallback-41')
|
||||
expect(wrapper.find('[data-preview-unavailable]').exists()).toBe(false)
|
||||
expect(revoke).not.toHaveBeenCalled()
|
||||
wrapper.unmount()
|
||||
expect(revoke).toHaveBeenCalledWith('blob:fallback-41')
|
||||
})
|
||||
|
||||
it('shows the preview as unavailable when the thumb route fails too', async () => {
|
||||
objectUrls(vi.fn(() => 'blob:x'), vi.fn())
|
||||
const { wrapper, calls } = await setup({
|
||||
routes: { [`GET ${BASE}/7/files/photos`]: listOf([item(41, 'a.png')]) },
|
||||
})
|
||||
await wrapper.find('[data-file-item] img').trigger('error')
|
||||
await flushPromises()
|
||||
expect(requestsTo(calls, 'GET', thumbPath)).toHaveLength(1)
|
||||
expect(wrapper.find('[data-preview-unavailable]').exists()).toBe(true)
|
||||
expect(wrapper.find('[data-file-item] img').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('makes no thumb request while the public URL loads', async () => {
|
||||
objectUrls(vi.fn(() => 'blob:x'), vi.fn())
|
||||
const { wrapper, calls } = await setup({
|
||||
routes: {
|
||||
[`GET ${BASE}/7/files/photos`]: listOf([item(41, 'a.png')]),
|
||||
[`GET ${thumbPath}`]: () => ({ body: 'png-bytes' }),
|
||||
},
|
||||
})
|
||||
await flushPromises()
|
||||
expect(requestsTo(calls, 'GET', thumbPath)).toHaveLength(0)
|
||||
expect(wrapper.find('[data-file-item] img').attributes('src')).toBe('/storage/app/uploads/public/thumb_a.png')
|
||||
expect(wrapper.find('[data-preview-unavailable]').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('shows the preview as unavailable when the fallback image fails as well, after one thumb request', async () => {
|
||||
objectUrls(vi.fn(() => 'blob:fallback-41'), vi.fn())
|
||||
const { wrapper, calls } = await setup({
|
||||
routes: {
|
||||
[`GET ${BASE}/7/files/photos`]: listOf([item(41, 'a.png')]),
|
||||
[`GET ${thumbPath}`]: () => ({ body: 'not-an-image' }),
|
||||
},
|
||||
})
|
||||
await wrapper.find('[data-file-item] img').trigger('error')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('[data-file-item] img').attributes('src')).toBe('blob:fallback-41')
|
||||
await wrapper.find('[data-file-item] img').trigger('error')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('[data-preview-unavailable]').exists()).toBe(true)
|
||||
expect(requestsTo(calls, 'GET', thumbPath)).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('keyboard reorder (backstop 4)', () => {
|
||||
const three = [item(41, 'a.png'), item(42, 'b.png'), item(43, 'c.png')]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user