import { afterEach, describe, expect, it, vi } from 'vitest' import { flushPromises } from '@vue/test-utils' import { MOBILE_WIDTH } from '@/components/__tests__/viewport' import { button, calls, chip, failWith, fieldWrapper, hasText, text, unmountAll, } from './entryEditorKit' import { focusedName, libraryBody, mediaButton, mediaState, mediaText, mountMedia, pickFromLibrary, } from './entryMediaKit' import { fieldLibrary } from './mediaFieldKit' vi.mock('@/composables/useApi', async (importOriginal) => { const actual = await importOriginal() return { ...actual, useApi: vi.fn() } }) afterEach(unmountAll) const dialog = () => document.body.querySelector('[role="dialog"]') const tiles = () => [...document.body.querySelectorAll('[data-picker-tile]')] async function open(opener = 'Change image') { mediaButton(opener)!.click() await flushPromises() await flushPromises() } describe('The picker opened from the entry editor', () => { it('loads only the library page and never the variants', async () => { await mountMedia('/content/events/42', { thumbnail: 7 }) await open() expect(calls.filter((url) => url.startsWith('/v1/media/'))).toEqual([ '/v1/media/?page=1&size=25', ]) expect(calls.some((url) => url.includes('image-variants'))).toBe(false) expect(text(dialog())).toContain('Choose an image') expect(text(dialog())).not.toContain('Alt text') }) it('marks the stored image as Current', async () => { await mountMedia('/content/events/42', { thumbnail: 7 }) await open() const current = tiles().filter((tile) => tile.getAttribute('aria-label')!.endsWith(', Current'), ) expect(current.map((tile) => tile.dataset.imageId)).toEqual(['7']) }) it('is 640 px wide on desktop and a bottom sheet on mobile', async () => { await mountMedia('/content/events/42', { thumbnail: 7 }) await open() expect(dialog()!.className).toContain('sm:max-w-160') unmountAll() await mountMedia('/content/events/42', { thumbnail: 7, width: MOBILE_WIDTH }) await open() expect(dialog()!.className).toContain('max-sm:!bottom-0') }) it('does not open while the form is saving', async () => { let release = () => {} await mountMedia('/content/events/42', { thumbnail: 7, writeEntry: () => new Promise((resolve) => (release = () => resolve(undefined))), }) const title = fieldWrapper('title').querySelector('input')! title.value = 'Changed' title.dispatchEvent(new Event('input', { bubbles: true })) await flushPromises() button('Save')!.click() await flushPromises() mediaButton('Change image')!.click() await flushPromises() expect(dialog()).toBeNull() expect(hasText('Saving…')).toBe(true) release() await flushPromises() }) it('shows the empty library with the field copy and focuses nothing else', async () => { await mountMedia('/content/events/new', { library: () => ({ ...libraryBody([]), total: 0 }), }) await open('Pick an image for Thumbnail') const library = [...document.body.querySelectorAll('[role="tab"]')].find( (tab) => text(tab) === 'Library', )! library.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, button: 0 })) await flushPromises() expect(text(dialog())).toContain( 'Images you upload appear here, ready to use in any article or entry.', ) }) it('shows the error alert when the library fails and keeps the entry untouched', async () => { await mountMedia('/content/events/42', { thumbnail: 7, library: failWith(500) }) await open() expect(text(dialog())).toContain("Couldn't load your library") expect(text(dialog())).toContain('Try again') expect(chip()!.textContent).toContain('Saved') }) }) describe('Focus and announcements in the editor', () => { it('lands on Change image after Use this image', async () => { await mountMedia('/content/events/42', { thumbnail: 7 }) await pickFromLibrary('bathroom-tiles.png') expect(focusedName()).toBe('Change image') expect(mediaState()).toBe('filled') expect(mediaText()).toContain('bathroom-tiles.png') }) it('lands on Pick an image after removing the image', async () => { await mountMedia('/content/events/42', { thumbnail: 7 }) mediaButton('Remove image from Thumbnail')!.click() await flushPromises() await flushPromises() expect(focusedName()).toBe('Pick an image for Thumbnail') expect(chip()!.textContent).toContain('Unsaved changes') }) it('returns to the opener with Cancel', async () => { await mountMedia('/content/events/42', { thumbnail: 7 }) const opener = mediaButton('Change image')! opener.focus() await open() ;[...dialog()!.querySelectorAll('button')].find((b) => text(b) === 'Cancel')!.click() await vi.waitFor(() => expect(document.activeElement).toBe(opener)) expect(fieldLibrary()).toHaveLength(12) }) })