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
94 lines
3.0 KiB
TypeScript
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)
|
|
})
|