import { test, expect } from '@playwright/test' // AZ-474 — e2e companion for FT-P-51 (tile-split endpoint contract) and // FT-P-53 (DatasetItem.isSplit honored). // // Per the task spec, only FT-P-51 and FT-P-53 are `fast + e2e`. The other // rows (FT-P-52 parser, FT-P-54 auto-zoom, FT-P-55 indicator, FT-N-10 // malformed) are fast-only. Both e2e tests are `test.fail()` today // because the split surface is QUARANTINED in production (per // `_docs/04_refactoring/01-testability-refactoring/deferred_to_refactor.md` // row D11 and the traceability matrix's `[Q]` marker on AC-39). // // Once the SPA wires a "Split tile" affordance and starts honoring // `DatasetItem.isSplit`, remove the `test.fail` and these flip green. test.describe('AZ-474 — tile-split surface (e2e companion)', () => { test.fail( 'FT-P-51 — clicking Split tile POSTs /api/annotations/dataset//split', async ({ page }) => { test.setTimeout(20_000) const splitPosts: string[] = [] await page.route('**/api/annotations/dataset/*/split', async (route) => { if (route.request().method() === 'POST') { splitPosts.push(route.request().url()) } await route.continue() }) await page.goto('/dataset') // Suite seed must include at least one dataset item — if not, mark // the gap explicitly. The seed today produces images via the // annotations service; if it doesn't, the test reports the seed gap // and skips rather than hiding the contract. const firstCard = page.locator('img').first() if (!(await firstCard.isVisible({ timeout: 5000 }).catch(() => false))) { test.skip(true, 'Suite seed has no dataset items') } await firstCard.hover() // Drift today: no Split-tile button is rendered. The locator below // is intentionally tolerant of any reasonable button shape so that // when the affordance lands, the test does not need surgery. const splitBtn = page.getByRole('button', { name: /split/i }) await expect(splitBtn.first()).toBeVisible({ timeout: 1500 }) await splitBtn.first().click() await expect.poll(() => splitPosts.length, { timeout: 2000 }).toBeGreaterThan(0) expect(splitPosts[0]).toMatch(/\/api\/annotations\/dataset\/[^/]+\/split$/) }, ) test.fail( 'FT-P-53 — items with isSplit:true render a distinct affordance vs non-split', async ({ page }) => { test.setTimeout(15_000) // Stub the dataset response so the test is independent of seed // shape — what matters is the renderer's behaviour given the // contract, not which rows happen to live in the suite seed. await page.route('**/api/annotations/dataset*', async (route) => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ items: [ { annotationId: 'ann-split', imageName: 'split.jpg', thumbnailPath: '/thumbs/split.jpg', status: 20, createdDate: '2026-05-11T10:00:00Z', createdEmail: 'op_alice@test.local', flightName: 'Flight 1', source: 0, isSeed: false, isSplit: true, }, { annotationId: 'ann-nosplit', imageName: 'nosplit.jpg', thumbnailPath: '/thumbs/nosplit.jpg', status: 10, createdDate: '2026-05-11T10:01:00Z', createdEmail: 'op_alice@test.local', flightName: 'Flight 1', source: 1, isSeed: false, isSplit: false, }, ], totalCount: 2, }), }) }) await page.goto('/dataset') await expect(page.locator('img').first()).toBeVisible({ timeout: 5_000 }) // Spec: the rendered card for an isSplit annotation MUST carry a // visible affordance the non-split card does NOT carry. const splitCard = page.locator('img[alt*="split"]').first() const nonSplitCard = page.locator('img[alt*="nosplit"]').first() const splitData = await splitCard.evaluate((n) => (n.closest('div') as HTMLElement | null)?.getAttribute('data-is-split'), ) const nonSplitData = await nonSplitCard.evaluate((n) => (n.closest('div') as HTMLElement | null)?.getAttribute('data-is-split'), ) expect(splitData).toBe('true') expect(nonSplitData).not.toBe('true') }, ) })