import { expect, test } from "@playwright/test"; const validUpload = { name: "sample.evtx", mimeType: "application/octet-stream", buffer: Buffer.from("synthetic") }; test("malformed successful analysis keeps the previous investigation", async ({ page }) => { await page.goto("/#analysis"); await page.getByRole("button", { name: "Load demo", exact: true }).first().click(); await expect(page.getByRole("region", { name: "Current investigation context" })).toContainText("bundled-demo"); await page.route("**/api/analyze", (route) => route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ source: "bad.evtx", events: [], incidents: [{ id: "broken" }] }), })); await page.locator('input[type="file"]').setInputFiles(validUpload); await expect(page.getByRole("alert")).toContainText("Analysis returned an invalid response."); await expect(page.getByRole("region", { name: "Current investigation context" })).toContainText("bundled-demo"); await page.getByRole("button", { name: "Timeline", exact: false }).click(); await expect(page.getByRole("heading", { name: "Inspector", exact: true })).toBeVisible(); }); test("structured parser errors have safe, useful wording", async ({ page }) => { await page.route("**/api/analyze", (route) => route.fulfill({ status: 422, contentType: "application/json", body: JSON.stringify({ detail: { code: "no_readable_events", message: "No readable Windows events were found in this file." } }), })); await page.goto("/#analysis"); await page.locator('input[type="file"]').setInputFiles(validUpload); await expect(page.getByRole("alert")).toContainText("No readable Windows events were found in this file."); await expect(page.getByRole("alert")).not.toContainText("HTTP 422"); }); test("rejecting an invalid file cancels an older pending analysis", async ({ page }) => { await page.goto("/#analysis"); await page.getByRole("button", { name: "Load demo", exact: true }).first().click(); await expect(page.getByRole("region", { name: "Current investigation context" })).toContainText("bundled-demo"); let routeStarted!: () => void; let releaseRoute!: () => void; const started = new Promise((resolve) => { routeStarted = resolve; }); const released = new Promise((resolve) => { releaseRoute = resolve; }); await page.route("**/api/analyze", async (route) => { routeStarted(); await released; try { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ source: "late.evtx", events: [], incidents: [] }) }); } catch { // The route can already be cancelled by the browser request abort. } }); const fileInput = page.locator('input[type="file"]'); await fileInput.setInputFiles(validUpload); await started; await fileInput.setInputFiles({ name: "invalid.txt", mimeType: "text/plain", buffer: Buffer.from("invalid") }); await expect(page.getByRole("alert")).toContainText("Choose a Windows .evtx file."); releaseRoute(); await page.waitForTimeout(300); await expect(page.getByRole("region", { name: "Current investigation context" })).toContainText("bundled-demo"); await expect(page.getByRole("alert")).toContainText("Choose a Windows .evtx file."); });