diff --git a/frontend/e2e/documents.spec.ts b/frontend/e2e/documents.spec.ts index 790d539c..4870f4e3 100644 --- a/frontend/e2e/documents.spec.ts +++ b/frontend/e2e/documents.spec.ts @@ -382,6 +382,9 @@ test.describe('PDF annotations — admin', () => { }); // Record count now — the draw test may have created more than one annotation const countBefore = await page.locator('[data-testid^="annotation-"]').count(); + // Guard against a missing seed: without this, a count of 0 would turn the + // post-delete assertion into toHaveCount(-1) and fail with a misleading timeout. + expect(countBefore).toBeGreaterThan(0); // Enable annotate mode — deletion is only available while annotating await page.getByRole('button', { name: /^annotieren$/i }).click(); @@ -389,6 +392,10 @@ test.describe('PDF annotations — admin', () => { // The on-canvas delete button was removed (issue #722). Delete via the // kept keyboard shortcut: focus an annotation, press Delete, confirm. const annotation = page.locator('[data-testid^="annotation-"]').first(); + // Capture the identity of the specific annotation we delete so we can assert + // that exact element is gone afterwards — a count drop alone is identity-blind. + const deletedTestId = await annotation.getAttribute('data-testid'); + expect(deletedTestId).toBeTruthy(); await annotation.click(); await annotation.press('Delete'); @@ -397,6 +404,10 @@ test.describe('PDF annotations — admin', () => { await expect(page.locator('[data-testid^="annotation-"]')).toHaveCount(countBefore - 1, { timeout: 8000 }); + // Identity check: the specific annotation we deleted must no longer exist. + await expect(page.locator(`[data-testid="${deletedTestId}"]`)).toHaveCount(0, { + timeout: 8000 + }); await page.screenshot({ path: 'test-results/e2e/annotation-deleted.png' }); }); diff --git a/frontend/src/lib/document/annotation/AnnotationLayer.svelte.spec.ts b/frontend/src/lib/document/annotation/AnnotationLayer.svelte.spec.ts index 12adfd7e..ae92db33 100644 --- a/frontend/src/lib/document/annotation/AnnotationLayer.svelte.spec.ts +++ b/frontend/src/lib/document/annotation/AnnotationLayer.svelte.spec.ts @@ -110,6 +110,10 @@ describe('AnnotationLayer', () => { }); await expect.element(page.getByTestId('annotation-ann-1')).toBeInTheDocument(); + // Positive control: the previously-removed testid must stay absent. await expect.element(page.getByTestId('annotation-delete-ann-1')).not.toBeInTheDocument(); + // Real invariant: the annotation must contain no clickable delete control at all. + const annotationEl = page.getByTestId('annotation-ann-1').element() as HTMLElement; + expect(annotationEl.querySelectorAll('button').length).toBe(0); }); }); diff --git a/frontend/src/lib/document/annotation/AnnotationLayer.svelte.test.ts b/frontend/src/lib/document/annotation/AnnotationLayer.svelte.test.ts index 3e5598d5..7dcc8cef 100644 --- a/frontend/src/lib/document/annotation/AnnotationLayer.svelte.test.ts +++ b/frontend/src/lib/document/annotation/AnnotationLayer.svelte.test.ts @@ -240,7 +240,7 @@ describe('AnnotationLayer', () => { expect(document.querySelector('[data-testid="annotation-ann-1"]')).not.toBeNull(); }); - it('renders without throwing when canDraw is true (delete button visible)', async () => { + it('renders without throwing when canDraw is true (no delete button)', async () => { expect(() => render(AnnotationLayer, { annotations: [annotation], diff --git a/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts b/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts index d9ec0ffc..79cb7680 100644 --- a/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts +++ b/frontend/src/lib/document/annotation/AnnotationShape.svelte.spec.ts @@ -50,7 +50,11 @@ describe('AnnotationShape', () => { }); await expect.element(page.getByTestId('annotation-ann-1')).toBeInTheDocument(); + // Positive control: the previously-removed testid must stay absent. await expect.element(page.getByTestId('annotation-delete-ann-1')).not.toBeInTheDocument(); + // Real invariant: the annotation must contain no clickable delete control at all. + const annotationEl = page.getByTestId('annotation-ann-1').element() as HTMLElement; + expect(annotationEl.querySelectorAll('button').length).toBe(0); }); it('calls onDeleteRequest when Delete key is pressed on the annotation', async () => {