Files
app/frontend/tests/values.spec.ts
T
stroblmeandClaude Fable 5 8f72728437 A message shows its shape, and its contents when asked
A record or an artifact reference was serialised into the port row, and the
panel widened until the type selects and the buttons beside them were pushed
off its edge — a checkpoint reference is 130 characters of digest, and none of
them are what you want while wiring a flow. What shows now is what the value
*is*: 'artifact · weights.json · 60B', 'record · 3 fields'. A chevron unfolds
the whole of it, wrapped, inside the panel it belongs to.

A scalar still reads as itself, and scrolls its own overflow into view when it
is longer than the room it was given. That behaviour already existed inside
the edge inspector; it moves to Common/Marquee so the panel can have it too,
and the inspector drops its own copy of the raw-JSON block along with it.

The rows are smaller for it: the type select finally fits the word 'artifact',
and a port nothing has come through on says so with a dash rather than a
sentence — nine ports of 'nothing has come through yet' is a panel of prose
about the absence of values.

The e2e check asserts both halves: that the summary is what appears, and that
the panel is still exactly 400px with the value unfolded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AD8SfVhzXBG2nAfFcVh3iD
2026-08-19 13:20:12 +02:00

94 lines
3.0 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.
expect((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)
})