import { expect, test } from "@playwright/test" import { api, apiPage, deleteAll } from "./utils/api" /** * Dashboards and other flows appear on the canvas but are not part of the flow. * * The risk this covers: they are React Flow nodes like any other, so anything * that writes the document — autosave, undo, delete, drag — could pick one up * and store it. A dashboard widget written into flow.json would become a node * the engine then tries to build. */ const flowName = `test_endpoint_${Date.now().toString(36)}` const dashboardName = `${flowName}_panel` test.use({ storageState: "playwright/.auth/user.json" }) test.describe.configure({ mode: "serial" }) test.beforeAll(async ({ browser }) => { const page = await apiPage(browser) // A flow reading a message, and a dashboard control that sets it. await api(page, `/flows/${flowName}`, { method: "PUT", data: { name: flowName, nodes: [ { id: "sink", type: "python", requires: [{ name: "level", port: "level", dtype: "float" }], provides: [], }, ], inputs: [ { spec: { name: "level", port: "level", dtype: "float" }, initial: 0 }, ], version: 1, }, }) const saved = await (await api(page, `/flows/${flowName}`)).json() await api(page, `/flows/${flowName}/publish`, { method: "POST", data: { version: saved.definition.version }, }) await api(page, `/dashboards/${dashboardName}`, { method: "POST" }) const dashboard = await ( await api(page, `/dashboards/${dashboardName}`) ).json() dashboard.pages[0].sections[0].widgets = [ { id: "lever", type: "slider", title: "Lever", layout: {}, config: { target: `${flowName}.level` }, }, ] await api(page, `/dashboards/${dashboardName}`, { method: "PUT", data: dashboard, }) await page.close() }) test.afterAll(async ({ browser }) => { await deleteAll(browser, [ `/dashboards/${dashboardName}`, `/flows/${flowName}`, ]) }) test("a dashboard control is drawn on the flow it feeds", async ({ page }) => { await page.goto(`/flows/${flowName}`) await page.waitForSelector(".react-flow__node") await expect(page.getByText("Lever")).toBeVisible() }) test("moving a node does not save the dashboard into the flow", async ({ page, }) => { await page.goto(`/flows/${flowName}`) const node = page.locator(".react-flow__node-flow").first() await node.waitFor() const box = await node.boundingBox() if (!box) throw new Error("the node has no position to drag from") await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2) await page.mouse.down() await page.mouse.move(box.x + box.width / 2 + 80, box.y + box.height / 2 + 40) await page.mouse.up() // The autosave is debounced; give it room to land. await page.waitForTimeout(2000) const detail = await (await api(page, `/flows/${flowName}`)).json() expect(detail.definition.nodes.map((n: { id: string }) => n.id)).toEqual([ "sink", ]) // Still reported as an endpoint, just never as a node. expect(detail.endpoints.map((e: { label: string }) => e.label)).toEqual([ "Lever", ]) })