From 6fd05e08d8f7fcc361d93725aa5e1f51e41a7be7 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 4 Jun 2026 17:16:03 +0200 Subject: [PATCH] test(transcribe): prove Delete fires once via real shape + action (#327) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review follow-up (Sara): the prior single-owner evidence was two separate unit facts against an inert DOM stub. This renders a real AnnotationShape, attaches the live transcribeShortcuts action, focuses the region, and presses Delete once — asserting deleteCurrentRegion fires exactly once. A genuine integration guard against re-introducing a double-bind. Co-Authored-By: Claude Sonnet 4.6 --- .../annotation/AnnotationShape.svelte.spec.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts b/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts index 0170bbc9..4a23eece 100644 --- a/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts +++ b/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts @@ -2,9 +2,32 @@ import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import AnnotationShape from './AnnotationShape.svelte'; +import { + transcribeShortcuts, + type TranscribeShortcutOptions +} from '$lib/shared/actions/transcribeShortcuts'; afterEach(cleanup); +function noopShortcutOptions( + overrides: Partial = {} +): TranscribeShortcutOptions { + return { + isPanelOpen: () => true, + isCheatsheetOpen: () => false, + panelMode: () => 'edit', + goToNextRegion: () => {}, + goToPrevRegion: () => {}, + toggleMode: () => {}, + closePanel: () => {}, + startDrawMode: () => {}, + toggleTrainingMark: () => {}, + deleteCurrentRegion: () => {}, + openCheatsheet: () => {}, + ...overrides + }; +} + function makeAnnotation(id = 'ann-1') { return { id, @@ -128,4 +151,29 @@ describe('AnnotationShape', () => { expect(onfocus).toHaveBeenCalledOnce(); }); + + // Integration: a real rendered shape + the live transcribeShortcuts action. + // Pressing Delete on the focused region must delete exactly once — proving the + // action is the single owner and the shape contributes no competing handler. + it('with the transcribeShortcuts action active, Delete deletes the focused region exactly once', () => { + const deleteCurrentRegion = vi.fn(); + render(AnnotationShape, { + annotation: makeAnnotation(), + isHovered: false, + isActive: true, + showDelete: true, + onclick: () => {}, + onpointerenter: () => {}, + onpointerleave: () => {} + }); + + const annotationEl = page.getByTestId('annotation-ann-1').element() as HTMLElement; + const action = transcribeShortcuts(annotationEl, noopShortcutOptions({ deleteCurrentRegion })); + + annotationEl.focus(); + annotationEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'Delete', bubbles: true })); + + expect(deleteCurrentRegion).toHaveBeenCalledTimes(1); + action.destroy(); + }); });