Files
app/frontend/tests/drafts.spec.ts
T

96 lines
3.4 KiB
TypeScript

import { expect, test } from "@playwright/test"
import { api, deleteAll, openedFlowId } 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)}`
/** Issued by the server when the first test creates it in the app. */
let flowId = ""
test.use({ storageState: "playwright/.auth/user.json" })
test.describe.configure({ mode: "serial" })
test.afterAll(async ({ browser }) => {
await deleteAll(browser, [`/flows/${flowId}`])
})
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()
flowId = await openedFlowId(page)
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")
// The publish glyph never moves; it is enabled only while there is
// something to put live.
await expect(page.getByTestId("publish-flow")).toBeEnabled()
// Nothing of this flow is loaded while it is only a draft.
await page.waitForTimeout(1500)
const before = await (await api(page, `/flows/${flowId}/state`)).json()
expect(before.nodes).toHaveLength(0)
await page.getByTestId("publish-flow").click()
// Discard is what marks a draft: it goes when the publish has landed. The
// publish glyph disables while the request is in flight too, so waiting on
// that would not wait for anything.
await expect(page.getByTestId("discard-draft")).toBeHidden()
await expect(page.getByTestId("publish-flow")).toBeDisabled()
const after = await (await api(page, `/flows/${flowId}/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/${flowId}`)
await page.waitForSelector(".react-flow__node")
const detail = await (await api(page, `/flows/${flowId}`)).json()
// Stand in for a second client that saved first.
const first = await api(page, `/flows/${flowId}`, {
method: "PUT",
data: { ...detail.definition, title: "Theirs" },
})
expect(first.ok()).toBeTruthy()
const stale = await api(page, `/flows/${flowId}`, {
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/${flowId}`)
await page.waitForSelector(".react-flow__node")
await page.getByTestId("discard-draft").click()
await page.getByTestId("confirm-discard-draft").click()
await expect(page.getByTestId("discard-draft")).toBeHidden()
await expect(page.getByTestId("publish-flow")).toBeDisabled()
const detail = await (await api(page, `/flows/${flowId}`)).json()
expect(detail.has_draft).toBe(false)
expect(detail.definition.title).not.toBe("Theirs")
})