fix: element tests drive the widget host protocol; the image element gets tests (WR-25)
The transfer element's busy and state=error handling is now tested through the fake widget host, and golem15-seo-image gets tests for the upload id matching, the error display, Remove and the disabled state. The README's test gate runs npm test.
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { afterEach, beforeAll, describe, expect, it } from 'vitest'
|
||||
import { safeImageURL } from '../../assets/src/elements/image'
|
||||
import { labelsFor } from '../../assets/src/elements/labels'
|
||||
|
||||
// E7 golem15-seo-image: which stored URLs the preview may load.
|
||||
// E7 golem15-seo-image: which stored URLs the preview may load, the
|
||||
// upload round trip through summer-upload / summer-upload-result, errors
|
||||
// and Remove.
|
||||
|
||||
beforeAll(async () => {
|
||||
await import('../../assets/src/elements/index')
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
document.body.replaceChildren()
|
||||
})
|
||||
|
||||
describe('E7 safeImageURL', () => {
|
||||
it('accepts a path and an http(s) URL', () => {
|
||||
@@ -16,3 +27,74 @@ describe('E7 safeImageURL', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('E7 element (WR-25)', () => {
|
||||
type ImageNode = HTMLElement & { value: string }
|
||||
|
||||
function mount(value = ''): { node: ImageNode; changes: string[]; uploads: { id: string; file: File }[] } {
|
||||
const node = document.createElement('golem15-seo-image') as ImageNode
|
||||
node.setAttribute('ui-locale', 'en')
|
||||
document.body.append(node)
|
||||
node.value = value
|
||||
const changes: string[] = []
|
||||
const uploads: { id: string; file: File }[] = []
|
||||
node.addEventListener('summer-change', (ev) => changes.push((ev as CustomEvent).detail.value))
|
||||
node.addEventListener('summer-upload', (ev) => uploads.push((ev as CustomEvent).detail))
|
||||
return { node, changes, uploads }
|
||||
}
|
||||
|
||||
function choose(node: HTMLElement): File {
|
||||
const input = node.querySelector<HTMLInputElement>('input[type="file"]')!
|
||||
const file = new File(['x'], 'a.png', { type: 'image/png' })
|
||||
Object.defineProperty(input, 'files', { value: [file] })
|
||||
input.dispatchEvent(new Event('change'))
|
||||
return file
|
||||
}
|
||||
|
||||
function status(node: HTMLElement): string {
|
||||
return node.querySelector('.seo-image__status')?.textContent ?? ''
|
||||
}
|
||||
|
||||
it('shows a safe stored image and hides an unsafe one', () => {
|
||||
expect(mount('/media/a.png').node.querySelector('img')?.getAttribute('src')).toBe('/media/a.png')
|
||||
expect(mount('/\\evil.example/x.png').node.querySelector('img')).toBeNull()
|
||||
})
|
||||
|
||||
it('uploads through summer-upload and takes only the answer to its own id', () => {
|
||||
const { node, changes, uploads } = mount()
|
||||
const file = choose(node)
|
||||
expect(uploads).toHaveLength(1)
|
||||
expect(uploads[0].file).toBe(file)
|
||||
expect(status(node)).toBe(labelsFor('en').imageUploading)
|
||||
node.dispatchEvent(new CustomEvent('summer-upload-result', { detail: { id: 'other', url: '/media/wrong.png' } }))
|
||||
expect(changes).toEqual([])
|
||||
expect(status(node)).toBe(labelsFor('en').imageUploading)
|
||||
node.dispatchEvent(new CustomEvent('summer-upload-result', { detail: { id: uploads[0].id, url: '/media/new.png' } }))
|
||||
expect(changes).toEqual(['/media/new.png'])
|
||||
expect(node.value).toBe('/media/new.png')
|
||||
expect(node.querySelector('img')?.getAttribute('src')).toBe('/media/new.png')
|
||||
expect(status(node)).toBe('')
|
||||
})
|
||||
|
||||
it('shows the upload error, or imageFailed when the answer names none', () => {
|
||||
const { node, changes, uploads } = mount()
|
||||
choose(node)
|
||||
node.dispatchEvent(new CustomEvent('summer-upload-result', { detail: { id: uploads[0].id, error: 'Too big.' } }))
|
||||
expect(status(node)).toBe('Too big.')
|
||||
choose(node)
|
||||
node.dispatchEvent(new CustomEvent('summer-upload-result', { detail: { id: uploads[1].id } }))
|
||||
expect(status(node)).toBe(labelsFor('en').imageFailed)
|
||||
expect(node.querySelector('.seo-image__status--error')).not.toBeNull()
|
||||
expect(changes).toEqual([])
|
||||
})
|
||||
|
||||
it('Remove clears the value; a disabled element offers no actions', () => {
|
||||
const { node, changes } = mount('/media/a.png')
|
||||
node.querySelector<HTMLButtonElement>('.seo-image__button--secondary')!.click()
|
||||
expect(changes).toEqual([''])
|
||||
expect(node.querySelector('img')).toBeNull()
|
||||
const off = mount('/media/a.png').node
|
||||
off.setAttribute('disabled', '')
|
||||
expect(off.querySelector('.seo-image__actions')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user