Files
AITrader/tests/job-history.spec.ts
T

46 lines
2.0 KiB
TypeScript

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 directly (use absolute URL to avoid SPA navigation races)
const base = new URL(page.url()).origin;
await page.goto(`${base}/stocks/${ticker}`, { waitUntil: 'load', timeout: 20000 });
await page.waitForSelector('text=Job History', { timeout: 10000 });
// 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();
});