import { expect, test, type Page } from "@playwright/test"; const PROFILE = `e2e-profile-${Date.now()}`; const TOPOLOGY = `e2e-topo-${Date.now()}`; const PROFILE_WITH_TOPO = `e2e-profile-topo-${Date.now()}`; async function dismissAllToasts(page: Page) { await page.locator(".toast").evaluateAll((els) => { for (const el of els) (el as HTMLElement).click(); }); } test.describe.serial("mirage dashboard e2e", () => { test("user story 1: overview shows metric cards and detected emulators", async ({ page }) => { await page.goto("/"); await expect(page.getByRole("heading", { name: "Overview" })).toBeVisible(); await expect(page.getByTestId("profile-stat")).toBeVisible(); await expect(page.getByTestId("session-stat")).toBeVisible(); await expect(page.getByTestId("healthy-stat")).toBeVisible(); await expect(page.getByTestId("execs-stat")).toBeVisible(); await expect(page.getByTestId("system-panel")).toBeVisible(); await expect(page.getByTestId("emulator-row-noop")).toBeVisible(); await expect(page.getByTestId("emulator-installed-noop")).toContainText( /installed/i, ); await expect(page.getByTestId("daemon-version")).toBeVisible(); }); test("user story 2: create profile through wizard with dropdown", async ({ page }) => { await page.goto("/profiles"); await expect(page.getByTestId("profiles-empty")).toBeVisible(); await page.getByTestId("open-profile-wizard").click(); const wizard = page.getByTestId("profile-wizard"); await expect(wizard).toBeVisible(); await page.getByTestId("wizard-name").fill(PROFILE); await page.getByTestId("wizard-emulator").click(); await page.getByTestId("wizard-emulator-option-noop").click(); await page.getByTestId("wizard-mode-functional").click(); await page.getByTestId("wizard-nodes").fill("1"); await page.getByTestId("wizard-gpus").fill("1"); await page.getByTestId("wizard-description").fill("e2e profile"); await page.getByTestId("wizard-submit").click(); await expect(wizard).toHaveCount(0); await expect(page.getByTestId(`profile-row-${PROFILE}`)).toBeVisible(); await expect(page.getByTestId("toast-success")).toBeVisible(); await dismissAllToasts(page); }); test("user story 3 + 4: start session card, run exec, see streamed output, then stop", async ({ page }) => { await page.goto("/sessions"); await expect(page.getByTestId("no-sessions")).toBeVisible(); await page.getByTestId("open-start-session").click(); const startModal = page.getByTestId("start-session-modal"); await expect(startModal).toBeVisible(); await page.getByTestId("start-modal-profile").click(); await page.getByTestId(`start-modal-profile-option-${PROFILE}`).click(); await page.getByTestId("start-modal-timeout").fill("10"); await page.getByTestId("start-session-confirm").click(); await expect(startModal).toHaveCount(0); const sessionCard = page.locator('[data-testid^="session-row-"]').first(); await expect(sessionCard).toBeVisible({ timeout: 30_000 }); const sessionId = (await sessionCard.getAttribute("data-testid"))!.replace( "session-row-", "", ); await expect .poll( async () => (await page .getByTestId(`session-healthy-${sessionId}`) .textContent()) ?? "", { timeout: 30_000 }, ) .toContain("healthy"); await page.getByTestId(`session-open-${sessionId}`).click(); await expect(page).toHaveURL(new RegExp(`/sessions/${sessionId}$`)); await page .getByTestId("exec-command") .fill("/bin/sh -c 'echo hello-mirage'"); await page.getByTestId("submit-exec").click(); await expect(page.getByTestId("attach-output")).toContainText( "hello-mirage", { timeout: 30_000 }, ); await expect(page.getByTestId("attach-exit")).toBeVisible({ timeout: 15_000, }); await page.goto("/sessions"); await page.getByTestId(`stop-session-${sessionId}`).click(); const confirmStop = page.getByTestId("confirm-stop-session"); await expect(confirmStop).toBeVisible(); await page.getByTestId("confirm-stop-session-confirm").click(); await expect(page.getByTestId(`session-row-${sessionId}`)).toHaveCount(0, { timeout: 15_000, }); await dismissAllToasts(page); }); test("user story 4b: terminal stdin is forwarded and a running exec can be killed", async ({ page }) => { await page.goto("/sessions"); await page.getByTestId("open-start-session").click(); const startModal = page.getByTestId("start-session-modal"); await expect(startModal).toBeVisible(); await page.getByTestId("start-modal-profile").click(); await page.getByTestId(`start-modal-profile-option-${PROFILE}`).click(); await page.getByTestId("start-modal-timeout").fill("10"); await page.getByTestId("start-session-confirm").click(); await expect(startModal).toHaveCount(0); const sessionCard = page.locator('[data-testid^="session-row-"]').first(); await expect(sessionCard).toBeVisible({ timeout: 30_000 }); const sessionId = (await sessionCard.getAttribute("data-testid"))!.replace( "session-row-", "", ); await expect .poll( async () => (await page .getByTestId(`session-healthy-${sessionId}`) .textContent()) ?? "", { timeout: 30_000 }, ) .toContain("healthy"); await page.getByTestId(`session-open-${sessionId}`).click(); await expect(page).toHaveURL(new RegExp(`/sessions/${sessionId}$`)); // `cat` echoes whatever it reads on stdin back to stdout, so it is a // perfect probe for the "is terminal input forwarded?" question and it // stays running until killed. await page.getByTestId("exec-command").fill("/bin/cat"); await page.getByTestId("submit-exec").click(); // The new exec row should appear with a Kill button (it is running). const killButton = page.locator('[data-testid^="kill-"]').first(); await expect(killButton).toBeVisible({ timeout: 30_000 }); // Type into the xterm terminal and expect `cat` to echo it back. The // real