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`
|
const dashboardName = `${flowName}_panel`
|
||||||
/** A panel of its own: a bar of three rows needs a tile to itself. */
|
/** A panel of its own: a bar of three rows needs a tile to itself. */
|
||||||
const stackName = `${flowName}_stack`
|
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. */
|
/** A message of the flow under test, qualified the way the engine names it. */
|
||||||
const w = (name: string) => `${flowName}.${name}`
|
const w = (name: string) => `${flowName}.${name}`
|
||||||
@@ -230,6 +233,30 @@ test.beforeAll(async ({ browser }) => {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
data: { version: stacked.version },
|
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()
|
await page.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -237,6 +264,7 @@ test.afterAll(async ({ browser }) => {
|
|||||||
await deleteAll(browser, [
|
await deleteAll(browser, [
|
||||||
`/dashboards/${dashboardName}`,
|
`/dashboards/${dashboardName}`,
|
||||||
`/dashboards/${stackName}`,
|
`/dashboards/${stackName}`,
|
||||||
|
`/dashboards/${lockedName}`,
|
||||||
`/flows/${flowName}`,
|
`/flows/${flowName}`,
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@@ -469,6 +497,29 @@ test("a control reads back what it published", async ({ page }) => {
|
|||||||
await expect(lamp).toHaveText("Off")
|
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 }) => {
|
test("an unbound widget says so and takes nothing down", async ({ page }) => {
|
||||||
const crashes: string[] = []
|
const crashes: string[] = []
|
||||||
page.on("pageerror", (error) => crashes.push(error.message))
|
page.on("pageerror", (error) => crashes.push(error.message))
|
||||||
|
|||||||
Reference in New Issue
Block a user