Files
ui/e2e/tests/detection_endpoints.e2e.ts
T
Oleksandr Bezdieniezhnykh 6d03643c2c
ci/woodpecker/push/build-arm Pipeline was successful
[AZ-461] [AZ-464] [AZ-470] [AZ-472] Batch 5 - detection/bulk-validate/panel-width/classes tests
- AZ-461 sync image detect URL canary (FT-P-11) PASS;
  async-video QUARANTINE (FT-P-12) + X-Refresh-Token drift
  (FT-P-13) recorded as it.fails() with controls.
- AZ-464 bulk-validate URL + UI sync (≤2 s) PASS;
  body shape drift {annotationIds,status} vs contract
  {ids,targetStatus:30} captured as it.fails().
- AZ-470 panel-width debounce + rehydration: entire task
  is Phase-B target (useResizablePanel has no PUT writer
  / no rehydration); 3 ACs as it.fails() with controls.
- AZ-472 DetectionClasses load + click + fallback PASS;
  hotkey arithmetic P=0 PASS, P=20/P=40 it.fails() for
  classes[idx+P]-against-dense-array drift.

Code review: PASS (0 findings). Fast: 18/18 files,
102 passed / 13 skipped. Static: 21/21 PASS.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:38:22 +03:00

86 lines
3.4 KiB
TypeScript

import { test, expect } from '@playwright/test'
// AZ-461 — e2e companion for sync image detect.
//
// AC-1 (FT-P-11): clicking the Detect button on an image issues exactly one
// POST whose URL matches `^/api/detect/[0-9]+$`.
// AC-2 (FT-P-12) — async video detect — is QUARANTINEd in CI (fast-profile
// it.fails() handles the assertion shape; the e2e companion
// intentionally omits it until AC-25 lands so the suite-e2e
// lane stays green).
// AC-3 (FT-P-13): drift today — `test.fail()` until production adds the
// `X-Refresh-Token` header for long-video detect.
//
// Requires the suite docker-compose stack and a media fixture exposing at
// least one image item that the Detect button can target. Skips with a clear
// reason when the seed is absent.
test.describe('AZ-461 — detection endpoints (e2e companion)', () => {
test('AC-1 (FT-P-11) — sync image detect URL canary', async ({ page }) => {
const detectRequests: { url: string; method: string }[] = []
await page.route('**/api/detect/**', async (route) => {
const req = route.request()
detectRequests.push({ url: req.url(), method: req.method() })
await route.continue()
})
await page.goto('/annotations')
const detectBtn = page.getByRole('button', { name: /AI Detect/i }).first()
if (!(await detectBtn.isVisible({ timeout: 5000 }).catch(() => false))) {
test.skip(true, 'Suite seed has no media for detect')
}
if (await detectBtn.isDisabled().catch(() => true)) {
// Need a media selected first. Click the first media-list row.
const firstMedia = page.locator('div.cursor-pointer').first()
if (!(await firstMedia.isVisible({ timeout: 5000 }).catch(() => false))) {
test.skip(true, 'No media row visible for detect target')
}
await firstMedia.click()
}
await detectBtn.click({ timeout: 5000 }).catch(() => {})
await page.waitForFunction(
() => true,
undefined,
{ timeout: 3000 },
).catch(() => null)
expect(detectRequests.length).toBeGreaterThan(0)
for (const r of detectRequests) {
const path = new URL(r.url).pathname
expect(path).toMatch(/^\/api\/detect\/[0-9a-zA-Z-]+$/)
expect(r.method).toBe('POST')
}
})
test.fail('AC-3 (FT-P-13) — long-video detect carries `X-Refresh-Token` header (drift)', async ({ page }) => {
const headersByUrl: Record<string, Record<string, string>> = {}
await page.route('**/api/detect/**', async (route) => {
const req = route.request()
headersByUrl[req.url()] = req.headers()
await route.continue()
})
await page.goto('/annotations')
const detectBtn = page.getByRole('button', { name: /AI Detect/i }).first()
if (!(await detectBtn.isVisible({ timeout: 5000 }).catch(() => false))) {
test.skip(true, 'Suite seed has no media for detect')
}
if (await detectBtn.isDisabled().catch(() => true)) {
const firstMedia = page.locator('div.cursor-pointer').first()
await firstMedia.click({ timeout: 5000 }).catch(() => {})
}
await detectBtn.click({ timeout: 5000 }).catch(() => {})
await page.waitForTimeout(1000)
const urls = Object.keys(headersByUrl)
expect(urls.length).toBeGreaterThan(0)
for (const u of urls) {
const h = headersByUrl[u]
expect(h).toHaveProperty('x-refresh-token')
expect(h['x-refresh-token']).not.toBe('')
}
})
})