Files
app/frontend/tests/panel.spec.ts
T
stroblme 579eb8e61a Size the rail to what it carries
Stretched end to end, a panel with two dashboards showed a pill nine
tenths empty — which was tolerable while the rail was chrome outside the
canvas and obvious once it moved onto the panel itself. It now hugs its
entries and sits centred in the column it reserves; that column is the
same width either way, so no arrangement moves.

A rail longer than the panel is tall still scrolls, and still draws no
bar: a wall panel is swiped, and there is no room for one.
2026-08-24 11:20:32 +02:00

147 lines
4.7 KiB
TypeScript

import { expect, test } from "@playwright/test"
import { api, apiPage, deleteAll } from "./utils/api"
/**
* A panel carrying more than one dashboard draws the way between them.
*
* The rail is part of what the screen shows rather than chrome beside it: it
* is inside the canvas, scaled with it, and wearing the dashboard's own look.
* Drawn outside, it was a strip of the app's design bolted to the edge of
* somebody's wall panel — and on a scaled canvas it did not even line up.
*
* It is also as tall as what it carries. Stretched end to end, a panel with
* two dashboards showed a pill nine tenths empty.
*/
const flowName = `test_panel_${Date.now().toString(36)}`
const first = `${flowName}_a`
const second = `${flowName}_b`
test.use({ storageState: "playwright/.auth/user.json" })
test.describe.configure({ mode: "serial" })
test.beforeAll(async ({ browser }) => {
const page = await apiPage(browser)
await api(page, `/flows/${flowName}`, {
method: "PUT",
data: {
name: flowName,
title: "Panel",
version: 1,
nodes: [
{
id: "emit",
type: "python",
provides: [{ name: "level", dtype: "float" }],
},
],
},
})
const flow = await (await api(page, `/flows/${flowName}?draft=true`)).json()
await api(page, `/flows/${flowName}/publish`, {
method: "POST",
data: { version: flow.definition.version },
})
await api(page, `/messages/${flowName}.level`, {
method: "POST",
data: { value: 4 },
})
for (const name of [first, second]) {
await api(page, `/dashboards/${name}`, { method: "POST" })
const doc = await (await api(page, `/dashboards/${name}?draft=true`)).json()
doc.settings = { look: { value: "glass" } }
doc.pages[0].sections[0].widgets = [
{
id: "stat",
type: "stat",
title: "Level",
layout: { lg: { x: 0, y: 0, w: 3, h: 2 } },
config: { message: `${flowName}.level`, dtype: "float" },
},
]
const put = await (
await api(page, `/dashboards/${name}`, { method: "PUT", data: doc })
).json()
await api(page, `/dashboards/${name}/publish`, {
method: "POST",
data: { version: put.version },
})
}
await api(page, "/panels/", {
method: "PUT",
data: {
panels: [{ id: flowName, title: "Hall", dashboards: [first, second] }],
},
})
await page.close()
})
test.afterAll(async ({ browser }) => {
await deleteAll(browser, [
`/dashboards/${first}`,
`/dashboards/${second}`,
`/flows/${flowName}`,
])
})
test("the rail is drawn on the panel, in the panel's own look", async ({
page,
}) => {
await page.goto(`/panel/${flowName}?d=${first}`)
const rail = page.getByTestId("panel-rail")
await rail.waitFor({ timeout: 20000 })
const canvas = (await page.getByTestId("canvas-surface").boundingBox())!
const box = (await rail.boundingBox())!
expect(box.x, "the rail starts left of the panel").toBeGreaterThanOrEqual(
canvas.x - 1,
)
expect(box.y, "the rail starts above the panel").toBeGreaterThanOrEqual(
canvas.y - 1,
)
expect(
box.x + box.width,
"the rail runs off the right of the panel",
).toBeLessThanOrEqual(canvas.x + canvas.width + 1)
expect(
box.y + box.height,
"the rail runs off the bottom of the panel",
).toBeLessThanOrEqual(canvas.y + canvas.height + 1)
// Inside the canvas is also what makes it wear the look: the attributes and
// the palette are stated on the canvas, and inheritance does the rest.
const inside = await rail.evaluate(
(el) => el.closest("[data-testid=canvas-surface]") !== null,
)
expect(inside, "the rail is drawn outside the panel it belongs to").toBe(true)
// As tall as what it carries rather than as tall as the panel: a rail of
// two stretched end to end is mostly empty pill.
expect(
box.height,
"the rail is stretched to the height of the panel",
).toBeLessThan(canvas.height / 2)
const centres = Math.abs(
box.y + box.height / 2 - (canvas.y + canvas.height / 2),
)
expect(centres, "the rail is not centred in its column").toBeLessThan(2)
// And the arrangement keeps clear of it rather than sitting under it.
const tile = (await page.getByTestId("widget-frame").first().boundingBox())!
expect(tile.x, "a widget is drawn under the rail").toBeGreaterThanOrEqual(
box.x + box.width,
)
})
test("the rail switches the panel between its dashboards", async ({ page }) => {
await page.goto(`/panel/${flowName}?d=${first}`)
await page.getByTestId(`panel-rail-${second}`).click()
await expect(page).toHaveURL(new RegExp(`d=${second}`))
await expect(page.getByTestId(`panel-rail-${second}`)).toHaveAttribute(
"aria-current",
"page",
)
})