Files
ITWorx_MCP_Hub-Public/apps/web/tests/e2e/operator-review.spec.ts
T

119 lines
7.8 KiB
TypeScript

import { expect, loginAs, test } from "./fixtures";
test.describe("operator review regressions", () => {
test.beforeEach(async ({ page }) => { await loginAs(page, "hub-admin"); });
test("filter changes retain the URL project and environment at the API boundary", async ({ page }) => {
await page.goto("/connectors?project=ludarium&environment=prod");
await expect(page.getByLabel("Filter records")).toBeVisible();
const response = page.waitForResponse((value) => {
const url = new URL(value.url());
return url.pathname === "/api/connectors" && url.searchParams.get("q") === "knowledge-default";
});
await page.getByLabel("Filter records").fill("knowledge-default");
const actual = new URL((await response).url());
expect(actual.searchParams.get("project")).toBe("ludarium");
expect(actual.searchParams.get("environment")).toBe("prod");
await expect.poll(() => new URL(page.url()).searchParams.get("q")).toBe("knowledge-default");
expect(new URL(page.url()).searchParams.get("project")).toBe("ludarium");
expect(new URL(page.url()).searchParams.get("environment")).toBe("prod");
await expect(page.getByRole("link", { name: "Knowledge Default", exact: true })).toBeVisible();
});
test("catalog scope stays locked until an explicit apply finishes", async ({ page }) => {
let release!: () => void;
const pending = new Promise<void>((resolve) => { release = resolve; });
await page.route("**/api/catalog/preview", (route) => route.fulfill({ json: { valid: true, changes: ["Review fixture change"], errors: [] } }));
await page.route("**/api/catalog/apply", async (route) => { await pending; await route.fulfill({ json: { accepted: true, message: "Reviewed catalog apply completed" } }); });
await page.goto("/tools?project=ludarium");
const workflow = page.locator(".workflow-panel").filter({ has: page.getByRole("heading", { name: "Catalog validation and preview" }) });
await workflow.getByRole("button", { name: "Validate and preview" }).click();
await workflow.getByRole("button", { name: "Apply approved catalog" }).click();
await page.getByRole("button", { name: "Confirm apply" }).click();
await expect(workflow.getByRole("combobox", { name: "Project", exact: true })).toBeDisabled();
await expect(workflow.getByRole("button", { name: "Applying…" })).toBeDisabled();
release();
await expect(workflow.getByText("Reviewed catalog apply completed")).toBeVisible();
await expect(workflow.getByRole("combobox", { name: "Project", exact: true })).toBeEnabled();
});
test("a pending client created after SPA navigation retains a visible resume path", async ({ page }) => {
let release!: () => void;
const pending = new Promise<void>((resolve) => { release = resolve; });
let createdId = "";
await page.route("**/api/client-management", async (route) => {
if (route.request().method() !== "POST") { await route.continue(); return; }
const response = await route.fetch();
createdId = ((await response.json()) as { client: { id: string } }).client.id;
await pending;
await route.fulfill({ response });
});
await page.goto("/clients");
const name = `creation-navigation-${Date.now()}`;
await page.getByLabel("Name", { exact: true }).fill(name);
await page.getByRole("button", { name: "Create pending client" }).click();
await expect.poll(() => createdId).not.toBe("");
await page.getByRole("navigation", { name: "Primary navigation" }).getByRole("link", { name: "Operations", exact: true }).click();
await expect(page.getByRole("heading", { name: "Operations", level: 1 })).toBeVisible();
release();
const notice = page.locator(".client-created-notice");
await expect(notice).toContainText(name);
expect(new URL(page.url()).pathname).toBe("/operations");
await expect(notice.getByRole("link", { name: "Resume onboarding" })).toHaveAttribute("href", `/clients?onboard=${createdId}`);
await notice.getByRole("link", { name: "Resume onboarding" }).click();
await expect(page.getByText(/Resumable Hub identity/)).toBeVisible();
expect(new URL(page.url()).searchParams.get("onboard")).toBe(createdId);
});
test("operation-check results link to registered connector identities", async ({ page }) => {
await page.route("**/api/operations/check", (route) => route.fulfill({ json: {
generatedAt: new Date().toISOString(), healthy: true,
connectors: { "itworx-knowledge": { reachable: true, status: "healthy", detail: "Bounded contract fixture", connectorRefs: [{ id: "knowledge-default", name: "Knowledge Default" }], connectorRefsTruncated: false } },
} }));
await page.goto("/operations");
await page.getByRole("button", { name: "Run live checks" }).click();
const registration = page.locator(".connector-checks").getByRole("link", { name: "Knowledge Default", exact: true });
await expect(registration).toHaveAttribute("href", "/connectors/knowledge-default");
await registration.click();
await expect(page.getByRole("heading", { name: "Knowledge Default", exact: true })).toBeVisible();
});
test("Quick Jump sends an ordinary client to its filtered records instead of an unavailable onboarding workflow", async ({ page }) => {
await page.route("**/api/clients?*", (route) => route.fulfill({ json: {
kind: "clients", generatedAt: new Date().toISOString(),
rows: [{ id: "ordinary-fixture-client", name: "Ordinary fixture client", status: "healthy", summary: "Existing client", project: "ludarium", environment: "prod" }],
page: { total: 1, nextCursor: null },
} }));
await page.getByRole("button", { name: "Open quick jump" }).click();
const dialog = page.getByRole("dialog", { name: "Quick jump" });
await dialog.getByRole("combobox").fill("ordinary-fixture-client");
await dialog.getByRole("group", { name: "Clients", exact: true }).getByRole("option", { name: /Ordinary fixture client/ }).click();
await expect(page).toHaveURL(/\/clients\?q=ordinary-fixture-client$/);
await expect(page.locator(".desktop-data-table").getByText("Existing client", { exact: true })).toBeVisible();
const desktopRecord = page.locator(".desktop-data-table").getByRole("link", { name: "Ordinary fixture client", exact: true });
await expect(desktopRecord).toHaveAttribute("href", "/clients?q=ordinary-fixture-client");
await desktopRecord.click();
await expect(page).toHaveURL(/\/clients\?q=ordinary-fixture-client$/);
await page.setViewportSize({ width: 390, height: 844 });
const mobileRecord = page.locator(".mobile-record-list").getByRole("link", { name: "Ordinary fixture client", exact: true });
await expect(mobileRecord).toHaveAttribute("href", "/clients?q=ordinary-fixture-client");
await mobileRecord.click();
await expect(page).toHaveURL(/\/clients\?q=ordinary-fixture-client$/);
await expect(page.getByText(/Resumable Hub identity/)).toHaveCount(0);
});
test("Quick Jump retains the selected audit trace as its destination filter", async ({ page }) => {
await page.route("**/api/audit?*", (route) => route.fulfill({ json: {
kind: "audit", generatedAt: new Date().toISOString(),
rows: [{ id: "audit-fixture", name: "tool.invocation", status: "healthy", summary: "Fixture event", traceId: "review-fixture-trace", project: "ludarium" }],
page: { total: 1, nextCursor: null },
} }));
await page.getByRole("button", { name: "Open quick jump" }).click();
const dialog = page.getByRole("dialog", { name: "Quick jump" });
await dialog.getByRole("combobox").fill("review-fixture-trace");
await dialog.getByRole("group", { name: "Audit", exact: true }).getByRole("option", { name: /tool.invocation/ }).click();
await expect(page).toHaveURL(/\/audit\?q=review-fixture-trace$/);
await expect(page.getByLabel("Filter records")).toHaveValue("review-fixture-trace");
});
});