Files
wehub-resource-sync a9cd7750f4
CI / unit-test (push) Has been cancelled
CI / detect-changes (push) Has been cancelled
CI / build (push) Has been cancelled
Publish docs via GitHub Pages / Deploy docs (push) Has been cancelled
CI / test-harness (push) Has been cancelled
CI / generate-e2e-matrix (push) Has been cancelled
CI / e2e (push) Has been cancelled
CI / build-ui (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
UI v2 Integration CI / E2E (Integration) (push) Has been cancelled
UI v2 CI / Lint, Format & Test (push) Has been cancelled
UI v2 CI / E2E (Mocked) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:37:56 +08:00

129 lines
4.4 KiB
TypeScript

/**
* Integration tests — Workflow Executions
*
* Starts real workflow executions via the API and verifies the search UI
* can find and display them. Uses a SET_VARIABLE workflow so executions
* reach COMPLETED state immediately without needing a worker process.
*/
import { expect, test } from "@playwright/test";
import {
createWorkflowDef,
deleteWorkflowDef,
startWorkflow,
terminateWorkflow,
type WorkflowDef,
} from "./api-client";
const RUN_ID = Date.now();
const WF_NAME = `e2e_exec_${RUN_ID}`;
const WORKFLOW_DEF: WorkflowDef = {
name: WF_NAME,
version: 1,
description: "Created by Playwright E2E test — safe to delete",
tasks: [
{
name: "set_var",
taskReferenceName: "set_var_ref",
type: "SET_VARIABLE",
inputParameters: { result: "e2e-test-value" },
},
],
};
// IDs of executions we start — cleaned up in afterAll.
const startedWorkflowIds: string[] = [];
test.beforeAll(async () => {
await createWorkflowDef(WORKFLOW_DEF);
});
test.afterAll(async () => {
// Terminate any running executions before deleting the definition.
await Promise.allSettled(
startedWorkflowIds.map((id) => terminateWorkflow(id)),
);
await deleteWorkflowDef(WF_NAME).catch(() => {});
});
// ── Helpers ────────────────────────────────────────────────────────────────────
/** Navigates to /executions with the workflow type pre-filled and waits for
* the results table to finish loading. */
async function openExecutionsSearch(
page: import("@playwright/test").Page,
workflowType: string,
) {
// The WorkflowSearch page reads its initial state from URL query params.
// workflowType is the most reliable filter to narrow results to our test data.
await page.goto(
`/executions?workflowType=${encodeURIComponent(workflowType)}`,
);
await page.waitForLoadState("networkidle");
}
// ── Tests ─────────────────────────────────────────────────────────────────────
test("started workflow execution appears in the executions search", async ({
page,
}) => {
const workflowId = await startWorkflow(WF_NAME, { value: "test" });
startedWorkflowIds.push(workflowId);
await openExecutionsSearch(page, WF_NAME);
// The workflow type column should show our workflow name.
await expect(page.getByText(WF_NAME).first()).toBeVisible();
});
test("execution row shows the workflow ID", async ({ page }) => {
const workflowId = await startWorkflow(WF_NAME, { value: "test" });
startedWorkflowIds.push(workflowId);
await openExecutionsSearch(page, WF_NAME);
// The full ID or a truncated prefix should appear somewhere in the table.
const idPrefix = workflowId.substring(0, 8);
await expect(page.getByText(new RegExp(idPrefix))).toBeVisible();
});
test("clicking an execution row opens the execution detail page", async ({
page,
}) => {
const workflowId = await startWorkflow(WF_NAME, { value: "test" });
startedWorkflowIds.push(workflowId);
await openExecutionsSearch(page, WF_NAME);
// The workflow ID is unique to the results table — click its prefix so we
// don't accidentally click the workflow type text in the search filter.
const idPrefix = workflowId.substring(0, 8);
await page.getByText(new RegExp(idPrefix)).first().click();
await expect(page).toHaveURL(new RegExp(`/execution/${workflowId}`));
await page.waitForLoadState("networkidle");
// Detail page content
await expect(page.locator("#main-content")).toBeVisible();
await expect(page.getByText(WF_NAME)).toBeVisible();
await expect(page.getByText(/COMPLETED/i)).toBeVisible();
// The full workflow ID should appear somewhere on the detail page.
await expect(page.getByText(new RegExp(workflowId))).toBeVisible();
// The SET_VARIABLE task should be listed in the task list.
await expect(page.getByText("set_var_ref")).toBeVisible();
});
test("executions page renders the search form", async ({ page }) => {
await page.goto("/executions");
await page.waitForLoadState("networkidle");
// The page always renders a search form regardless of results.
await expect(page.locator("#main-content")).toBeVisible();
// There should be at least one text input for filtering.
await expect(page.locator("#main-content input").first()).toBeVisible();
});