From f7df607a061b3f559572a8b5359c5cb07dbf5944 Mon Sep 17 00:00:00 2001 From: Henry Winkel Date: Sat, 16 May 2026 14:56:34 +0200 Subject: [PATCH] tests: add Playwright E2E for JobHistory and job detail navigation + cancel endpoint check\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/job-history.spec.ts | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/job-history.spec.ts diff --git a/tests/job-history.spec.ts b/tests/job-history.spec.ts new file mode 100644 index 0000000..82a96bb --- /dev/null +++ b/tests/job-history.spec.ts @@ -0,0 +1,44 @@ +import { test, expect } from "@playwright/test"; + +test("JobHistory shows jobs and job detail navigates", async ({ page }) => { + await page.goto("/stocks"); + await page.waitForSelector("table tbody tr"); + const firstRow = page.locator("tbody tr").first(); + const symbol = (await firstRow.locator("td a").textContent()) || ""; + const ticker = symbol.trim(); + + // Enqueue background analyze via API to get deterministic jobId + const base = new URL(page.url()).origin; + const resp = await page.request.post(`${base}/api/analyze`, { + data: { ticker, background: true }, + }); + expect([200, 202]).toContain(resp.status()); + const body = await resp.json(); + const jobId = body.jobId || body.job?.id; + expect(jobId).toBeTruthy(); + + // Navigate to stock detail page + await page.goto(`/stocks/${ticker}`); + + // Wait up to 10s for JobHistory to show at least one job + await page.waitForSelector('text=Job History', { timeout: 10000 }); + await page.waitForFunction((id) => { + const els = Array.from(document.querySelectorAll('div')).filter(el => el.textContent?.includes(id)); + return els.length > 0; + }, jobId, { timeout: 10000 }); + + // Click Details for the job (opens internal route) + const detailsLink = page.locator(`a:has-text("Details")`).first(); + await detailsLink.click(); + + // Should navigate to /jobs/:jobId + await page.waitForSelector('h1'); + const h1 = await page.locator('h1').textContent(); + expect(h1).toContain(jobId); + + // Try cancelling the job via API - may be already processed, but endpoint should respond + const cancelResp = await page.request.post(`${base}/api/jobs/${jobId}/cancel`); + expect(cancelResp.ok()).toBeTruthy(); + const cancelBody = await cancelResp.json(); + expect(Object.prototype.hasOwnProperty.call(cancelBody, 'cancelled')).toBeTruthy(); +}); \ No newline at end of file