Files
app/frontend/tests/values.spec.ts
T
stroblmeandClaude Opus 5.5 f44d7ebfcf Clipboard and values specs wait out the side panel's animation
The clipboard spec selected text in the previous node's panel while it was
still sliding out after the paste, so the selection collapsed when it
unmounted and the canvas took the copy. The values spec read the panel's box
mid-slide-in, where the translate leaves the width a float off 400.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:12:10 +02:00

97 lines
3.1 KiB
TypeScript

import { expect, test } from "@playwright/test"
import { api, apiPage, deleteAll } from "./utils/api"
/**
* What a message carrying a dictionary looks like in a panel four hundred
* pixels wide.
*
* The regression this exists for: a record or an artifact reference was
* serialised into the row, and the panel widened until the type selects and
* the buttons beside them were pushed off the edge. The shape shows instead,
* and the contents unfold on request — so the check is both that the summary
* is what appears, and that the panel is still the width it was told to be.
*/
const flowName = `test_values_${Date.now().toString(36)}`
/** The panel's fixed width; the whole point is that a value cannot change it. */
const PANEL_WIDTH = 400
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: "Values",
version: 1,
nodes: [
{
id: "emit",
type: "python",
provides: [
{ name: "shape", dtype: "record" },
{ name: "label", dtype: "str" },
],
},
],
},
})
// Saving writes a draft and moves the version on, so publish what is
// actually there rather than what it was a moment ago.
const draft = await (await api(page, `/flows/${flowName}?draft=true`)).json()
await api(page, `/flows/${flowName}/publish`, {
method: "POST",
data: { version: draft.definition.version },
})
// Values a flow could plausibly hold: one structured, one longer than the
// room a 400px panel has for it.
await api(page, `/messages/${flowName}.shape`, {
method: "POST",
data: {
value: { title: "Recovered", body: "R2 = 0.98", severity: "info" },
},
})
await api(page, `/messages/${flowName}.label`, {
method: "POST",
data: {
value: "ubuntu-gpu-node-01.lab.internal (numpy 2.5.2, cuda 12.4)",
},
})
await page.close()
})
test.afterAll(async ({ browser }) => {
await deleteAll(browser, [`/flows/${flowName}`])
})
test("a dictionary shows its shape, and its contents on request", async ({
page,
}) => {
await page.goto(`/flows/${flowName}`)
const node = page.locator(".react-flow__node").first()
await node.waitFor({ timeout: 20000 })
await node.click()
const panel = page.locator('aside[role="complementary"]').first()
await expect(panel).toBeVisible()
// The shape, not the values.
const summary = page.getByTestId("value-preview-toggle")
await expect(summary).toContainText("record · 3 fields")
await expect(panel).not.toContainText("Recovered")
// A value cannot push the panel open, however long it is. Polled, because
// the panel slides in and a box read mid-slide is a hair off 400.
await expect
.poll(async () => (await panel.boundingBox())?.width)
.toBe(PANEL_WIDTH)
// The contents are one click away.
await summary.click()
await expect(panel).toContainText("Recovered")
expect((await panel.boundingBox())?.width).toBe(PANEL_WIDTH)
})