Create in both overviews now opens a dialog, so the toolbar is a search box and one button. The specs and the capture script open it first. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7LwYgJfpkbLCTeiAf8U4A
88 lines
3.0 KiB
TypeScript
88 lines
3.0 KiB
TypeScript
import { expect, test } from "@playwright/test"
|
|
import { api, deleteAll } from "./utils/api"
|
|
|
|
/**
|
|
* Editing writes a draft; only publishing hands it to the engine. The two
|
|
* things worth proving here are that the engine ignores a draft until it is
|
|
* published, and that a second client cannot quietly overwrite the first.
|
|
*/
|
|
|
|
const flowName = `test_draft_${Date.now().toString(36)}`
|
|
|
|
test.use({ storageState: "playwright/.auth/user.json" })
|
|
|
|
test.describe.configure({ mode: "serial" })
|
|
|
|
test.afterAll(async ({ browser }) => {
|
|
await deleteAll(browser, [`/flows/${flowName}`])
|
|
})
|
|
|
|
test("a draft stays off the engine until it is published", async ({ page }) => {
|
|
await page.goto("/flows")
|
|
await page.getByTestId("new-flow").click()
|
|
await page.getByTestId("new-flow-name").fill(flowName)
|
|
await page.getByTestId("create-flow").click()
|
|
await page.waitForURL(`/flows/${flowName}`)
|
|
|
|
await page.getByTestId("add-node").click()
|
|
await page
|
|
.getByRole("option", { name: /function/i })
|
|
.first()
|
|
.click()
|
|
await expect(page.locator(".react-flow__node")).toHaveCount(1)
|
|
// Adding a node opens its panel, and the floating chrome steps aside for it.
|
|
await page.keyboard.press("Escape")
|
|
|
|
await expect(page.getByTestId("publish-flow")).toBeVisible()
|
|
|
|
// Nothing of this flow is loaded while it is only a draft.
|
|
await page.waitForTimeout(1500)
|
|
const before = await (await api(page, `/flows/${flowName}/state`)).json()
|
|
expect(before.nodes).toHaveLength(0)
|
|
|
|
await page.getByTestId("publish-flow").click()
|
|
await expect(page.getByTestId("publish-flow")).toBeHidden()
|
|
|
|
const after = await (await api(page, `/flows/${flowName}/state`)).json()
|
|
expect(after.nodes.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
test("a save against a version someone else moved on from is refused", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto(`/flows/${flowName}`)
|
|
await page.waitForSelector(".react-flow__node")
|
|
|
|
const detail = await (await api(page, `/flows/${flowName}`)).json()
|
|
|
|
// Stand in for a second client that saved first.
|
|
const first = await api(page, `/flows/${flowName}`, {
|
|
method: "PUT",
|
|
data: { ...detail.definition, title: "Theirs" },
|
|
})
|
|
expect(first.ok()).toBeTruthy()
|
|
|
|
const stale = await api(page, `/flows/${flowName}`, {
|
|
method: "PUT",
|
|
data: { ...detail.definition, title: "Mine" },
|
|
})
|
|
expect(stale.status()).toBe(409)
|
|
expect((await stale.json()).detail.current_version).toBe(
|
|
detail.definition.version + 1,
|
|
)
|
|
})
|
|
|
|
test("discarding a draft goes back to the published flow", async ({ page }) => {
|
|
await page.goto(`/flows/${flowName}`)
|
|
await page.waitForSelector(".react-flow__node")
|
|
|
|
await page.getByTestId("edit-flow").click()
|
|
await page.getByTestId("discard-draft").click()
|
|
await page.getByTestId("confirm-discard-draft").click()
|
|
|
|
await expect(page.getByTestId("publish-flow")).toBeHidden()
|
|
const detail = await (await api(page, `/flows/${flowName}`)).json()
|
|
expect(detail.has_draft).toBe(false)
|
|
expect(detail.definition.title).not.toBe("Theirs")
|
|
})
|