Files
app/frontend/tests/endpoints.spec.ts
T
stroblmeandClaude Opus 5 2ba56f57b2 Publish the dashboard the endpoint test asserts on
A dashboard edit is a draft now, and the flow canvas draws the controls the
panels actually carry, so the fixture has to publish it the same way it
already publishes the flow. The assertion is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XC2jX6Hdj7pxGGKzBTrbqB
2026-08-17 12:03:54 +02:00

117 lines
3.5 KiB
TypeScript

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` },
},
]
const draft = await (
await api(page, `/dashboards/${dashboardName}`, {
method: "PUT",
data: dashboard,
})
).json()
// A dashboard edit is a draft, and the flow canvas draws the controls the
// panels actually carry — so the endpoint only exists once this is published,
// the same way the flow above had to be.
await api(page, `/dashboards/${dashboardName}/publish`, {
method: "POST",
data: { version: draft.version },
})
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",
])
})