Guard locked through the desktop grid too
`mobile.spec.ts` covers the stacked editor, which draws through `DashboardView` on both sides. Desktop `?edit=true` swaps in `GridLayout` directly and never mounts `LockedProvider`, so the branch the stacked fix was matched to had no guard of its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KYM38KSb4V4v2T71eifnZv
This commit is contained in:
@@ -16,6 +16,9 @@ const flowName = `test_widgets_${Date.now().toString(36)}`
|
||||
const dashboardName = `${flowName}_panel`
|
||||
/** A panel of its own: a bar of three rows needs a tile to itself. */
|
||||
const stackName = `${flowName}_stack`
|
||||
/** A read-only dashboard, on its own so the lock guard below has a lamp the
|
||||
* interaction test above hasn't already flipped. */
|
||||
const lockedName = `${flowName}_locked`
|
||||
|
||||
/** A message of the flow under test, qualified the way the engine names it. */
|
||||
const w = (name: string) => `${flowName}.${name}`
|
||||
@@ -230,6 +233,30 @@ test.beforeAll(async ({ browser }) => {
|
||||
method: "POST",
|
||||
data: { version: stacked.version },
|
||||
})
|
||||
|
||||
const locked = await (
|
||||
await api(page, `/dashboards/${lockedName}`, { method: "POST" })
|
||||
).json()
|
||||
locked.settings = { ...(locked.settings ?? {}), locked: { value: true } }
|
||||
locked.widgets = [
|
||||
{
|
||||
id: "lamp",
|
||||
type: "switch",
|
||||
title: "Lamp",
|
||||
layout: { lg: { x: 0, y: 0, w: 3, h: 2 } },
|
||||
config: { target: w("lamp"), dtype: "bool", style: "button" },
|
||||
},
|
||||
]
|
||||
const lockedDraft = await (
|
||||
await api(page, `/dashboards/${lockedName}`, {
|
||||
method: "PUT",
|
||||
data: locked,
|
||||
})
|
||||
).json()
|
||||
await api(page, `/dashboards/${lockedName}/publish`, {
|
||||
method: "POST",
|
||||
data: { version: lockedDraft.version },
|
||||
})
|
||||
await page.close()
|
||||
})
|
||||
|
||||
@@ -237,6 +264,7 @@ test.afterAll(async ({ browser }) => {
|
||||
await deleteAll(browser, [
|
||||
`/dashboards/${dashboardName}`,
|
||||
`/dashboards/${stackName}`,
|
||||
`/dashboards/${lockedName}`,
|
||||
`/flows/${flowName}`,
|
||||
])
|
||||
})
|
||||
@@ -469,6 +497,29 @@ test("a control reads back what it published", async ({ page }) => {
|
||||
await expect(lamp).toHaveText("Off")
|
||||
})
|
||||
|
||||
/**
|
||||
* A locked dashboard, read and arranged on the desktop grid.
|
||||
*
|
||||
* mobile.spec.ts guards this same setting through the stacked editor, which a
|
||||
* phone's width routes through `DashboardView` on both the read and the
|
||||
* arrange side. Desktop takes a second path once editing starts — `?edit=true`
|
||||
* swaps in `<GridLayout>` directly, which never mounts `LockedProvider` at
|
||||
* all — so this is the same guard through the branch that path never reaches.
|
||||
*/
|
||||
test("a locked dashboard locks when read, not while arranged", async ({
|
||||
page,
|
||||
}) => {
|
||||
const lamp = page.getByRole("button", { name: "Lamp" })
|
||||
|
||||
await page.goto(`/dashboards/${lockedName}`)
|
||||
await lamp.waitFor({ timeout: 15000 })
|
||||
await expect(lamp, "a locked dashboard being read").toBeDisabled()
|
||||
|
||||
await page.goto(`/dashboards/${lockedName}?edit=true`)
|
||||
await lamp.waitFor({ timeout: 15000 })
|
||||
await expect(lamp, "a locked dashboard being arranged").toBeEnabled()
|
||||
})
|
||||
|
||||
test("an unbound widget says so and takes nothing down", async ({ page }) => {
|
||||
const crashes: string[] = []
|
||||
page.on("pageerror", (error) => crashes.push(error.message))
|
||||
|
||||
Reference in New Issue
Block a user