diff --git a/tests/browser/workspace-inspect.spec.mjs b/tests/browser/workspace-inspect.spec.mjs index 698cd3d0..3d77f112 100644 --- a/tests/browser/workspace-inspect.spec.mjs +++ b/tests/browser/workspace-inspect.spec.mjs @@ -290,6 +290,29 @@ test('D155: an unreadable file stays on the page with its alert', async ({ page await expect(viewer(page)).toHaveCount(0); }); +test('D155: an AVI keeps its note and toast and does not open the viewer', async ({ page }) => { + await openInspect(page); + // AVI and WMV metadata is never read and the browser cannot play them, so the page keeps the selection's note. + const avi = { name: 'clip.avi', mimeType: 'video/x-msvideo', buffer: Buffer.concat([Buffer.from('RIFF'), Buffer.alloc(4), Buffer.from('AVI LIST'), Buffer.alloc(64)]) }; + await choose(page, avi); + await expect(page.locator('#workspace-toast')).toHaveText(TOAST); + await expect(action(page)).toHaveAttribute('aria-disabled', 'false'); + await expect(viewer(page)).toHaveCount(0); + await reopenViewer(page); + await expect(viewer(page).locator('#viewer-title')).toHaveText('clip.avi'); +}); + +test('D155: a selection that lands while another dialog is open leaves the viewer closed', async ({ page }) => { + await openInspect(page); + await page.evaluate(() => { const other = document.createElement('dialog'); other.id = 'other-dialog'; other.textContent = 'Other'; document.body.append(other); other.showModal(); }); + await choose(page, parityPng('f02.png')); + await expect(action(page)).toHaveAttribute('aria-disabled', 'false'); + await expect(viewer(page)).toHaveCount(0); + await page.evaluate(() => document.querySelector('#other-dialog').close()); + await reopenViewer(page); + await expect(viewer(page).locator('#viewer-title')).toHaveText('f02.png'); +}); + test('D155: at 390px the opened details are reachable below the media', async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); await openInspect(page); diff --git a/web/js/workspace/inspect.mjs b/web/js/workspace/inspect.mjs index 6c0ca899..ee67d7ec 100644 --- a/web/js/workspace/inspect.mjs +++ b/web/js/workspace/inspect.mjs @@ -280,11 +280,12 @@ export function mountInspect(main, { parentScope, api, sender }) { /** Runs `run` after this task, or once `preview`'s video stops starting (metadata, an error, or the D62 limit). */ function whenSettled(preview, run) { if (!preview || !isStarting(preview.node)) { queueMicrotask(run); return; } + // `run` checks that the page and the selection are still current, so the page's end may call `done` too. const settled = new AbortController(); - const done = () => { settled.abort(); clearTimeout(timer); if (!scope.signal.aborted) run(); }; + const done = () => { settled.abort(); clearTimeout(timer); run(); }; const timer = setTimeout(done, STARTING_VIDEO_MS); for (const type of ['loadedmetadata', 'error']) preview.node.addEventListener(type, done, { once: true, signal: settled.signal }); - scope.signal.addEventListener('abort', () => { settled.abort(); clearTimeout(timer); }, { once: true, signal: settled.signal }); + scope.cleanup(done); } /** The viewer on the current selection, details showing (D155 amends D97); focus returns to `trigger` on close. */ function openViewer(trigger) {