Skip to content

Commit b1a97d6

Browse files
Merge pull request #141 from oriontech-me/validate/flow-rename-header
chore(flow-functionality): add @stable to flow-rename-header
2 parents fc97ef3 + 59d0435 commit b1a97d6

3 files changed

Lines changed: 108 additions & 8 deletions

File tree

QA-CHECKLIST.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@
558558
- [-] Create flow via JSON file import
559559

560560
#### 12.2 View and Edit Flow
561-
- [-] Rename flow via editor header
561+
- [x] Rename flow via editor header`flow-functionality/flow-rename-header.spec.ts`
562562
- [-] Edit flow name and description
563563
- [-] Flow auto-save on changes
564564
- [-] Flow settings
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Flow Functionality — Flow Rename via Header
2+
3+
**Last validated:** Langflow 1.10.x
4+
5+
---
6+
7+
## What this test validates *(required)*
8+
9+
Validates that a flow can be renamed via the **editor header** in two complementary ways:
10+
11+
1. **UI test:** Opens a blank flow, clicks the `flow_name` header, types a new name in the rename modal, saves, and asserts the header DOM commits the new name.
12+
2. **API test:** Creates a flow via `POST /api/v1/flows/`, renames via `PATCH /api/v1/flows/{id}`, and confirms via `GET /api/v1/flows/{id}` that the new name persisted server-side, with cleanup via `DELETE`.
13+
14+
The pair gives us both **interaction-level** coverage (the rename modal commits to React state and DOM) and **persistence-level** coverage (the PATCH round-trip is durable in the database). If either breaks, users either lose the ability to rename a flow from the editor or the rename silently fails to persist after refresh.
15+
16+
---
17+
18+
## Tags *(required)*
19+
20+
UI test: `@release` `@workspace` `@stable`
21+
API test: `@release` `@workspace` `@api` `@stable`
22+
23+
---
24+
25+
## Step by step *(required)*
26+
27+
### UI test — `flow can be renamed via the header edit`
28+
29+
1. Bootstrap the app and wait for the `blank-flow` card
30+
2. Click `blank-flow` to enter the editor; wait for `sidebar-search-input` to confirm the canvas loaded
31+
3. Generate a unique name `My Renamed Flow ${Date.now()}` and call `renameFlow(page, { flowName })` (helper opens the modal, fills the input, clicks save, dismisses the toast, and waits for the header DOM to update via `waitForFunction`)
32+
4. Assert `flow_name` header text equals the new name
33+
34+
### API test — `flow name persists after rename via API PATCH and GET`
35+
36+
1. Acquire a Bearer token via `getAuthToken(request)`
37+
2. `POST /api/v1/flows/` with `{ name: originalName, ...FLOW_BASE }` → expect `201` and capture `id`
38+
3. `PATCH /api/v1/flows/{id}` with `{ name: updatedName }` → expect `200` and `body.name === updatedName`
39+
4. `GET /api/v1/flows/{id}` → expect `200`, `body.name === updatedName`, and `body.name !== originalName`
40+
5. Cleanup: `DELETE /api/v1/flows/{id}` in a `finally` block
41+
42+
---
43+
44+
## Validation criterion *(required)*
45+
46+
The UI test must:
47+
48+
- Emit at least one explicit `expect()` (`flow_name` `toHaveText(newName)`) — the helper's internal `waitForFunction` is defensive but is not visible to the test runner, so the explicit `expect` is the framework-visible guard
49+
- Use a unique name per run (`Date.now()` suffix) to avoid colliding with persisted flows from prior runs
50+
51+
The API test must assert **all** of:
52+
53+
- POST returns `201`
54+
- PATCH returns `200` and the response body's `name` equals `updatedName`
55+
- GET returns `200` and the response body's `name` equals `updatedName`
56+
- The original name is no longer returned (`name !== originalName`)
57+
- Cleanup `DELETE` runs in `finally` to avoid leaking flows on test failure
58+
59+
---
60+
61+
## External dependencies *(required)*
62+
63+
- `tests/helpers/flows/rename-flow.ts` — opens the rename modal, fills `input-flow-name`, clicks `save-flow-settings`, dismisses the "Changes saved successfully" toast, and waits for the `flow_name` DOM to commit via `waitForFunction`
64+
- `tests/helpers/auth/get-auth-token.ts` — issues a Bearer token from the configured superuser credentials
65+
- `src/frontend/src/components/headerComponent/` — renders the `flow_name` header that opens the rename modal
66+
- `src/backend/base/langflow/api/v1/flows.py` — owns `POST/PATCH/GET/DELETE /api/v1/flows`; the round-trip in the API test exercises this endpoint directly
67+
68+
---
69+
70+
## What this test does not cover *(optional)*
71+
72+
- Renaming via the **flows list page** context menu (different code path)
73+
- Description editing (the helper supports `flowDescription` but this spec only exercises `flowName`)
74+
- Concurrent rename conflicts (two clients renaming the same flow)
75+
- Rename with names containing special characters or exceeding length limits
76+
- Cancel-rename flow (clicking `cancel-flow-settings` instead of save)
77+
78+
---
79+
80+
## Preconditions *(optional)*
81+
82+
- Langflow running at `PLAYWRIGHT_BASE_URL`
83+
- `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` configured for the API test's auth token
84+
- No LLM required
85+
86+
---
87+
88+
## When to review this test *(optional)*
89+
90+
- `tests/helpers/flows/rename-flow.ts` is refactored (e.g., changes to which testids it interacts with, removal of the toast click, or the `waitForFunction` guard)
91+
- The `flow_name` testid is renamed or split between editor and main-page contexts
92+
- `POST/PATCH/GET /api/v1/flows/{id}` is namespaced (e.g., to `/api/v2/flows`) — the API test would need updating
93+
- The Bearer-token auth scheme changes (e.g., to cookie-based or x-api-key)
94+
95+
---
96+
97+
## Notes *(optional)*
98+
99+
- The UI test runs against the editor's React state, but the rename helper's internal `waitForFunction` already polls until the DOM `flow_name` text matches. The explicit `expect.toHaveText` after the helper return is intentional: ESLint's `playwright/expect-expect` rule requires every `test()` to have a visible expect, and the explicit assertion is what shows up in the test report.
100+
- Persistence is verified by the API test, not by reloading the editor in the UI test. An earlier draft used `page.reload()` after rename, but it was flaky — on some runs the post-reload URL routed to the flows list page (not the editor), causing the `flow_name` testid to be absent and the assertion to time out. Splitting interaction (UI) and persistence (API) into two tests removed that flakiness.
101+
- Stress-validated under the CI worker configuration (`CI=true``workers: 2` per `playwright.config.ts`) with `--repeat-each=5` (10 invocations interleaved with the UI test). No `500` responses on `POST /api/v1/flows/` and no flakiness observed. The custom backend-error monitor in `tests/fixtures/fixtures.ts` extends only the `page` fixture, so a `500` on this API test would surface as a hard failure on the explicit `expect(createRes.status()).toBe(201)`, not as a downgraded warning.

tests/tests-automations/regression/flow-functionality/flow-rename-header.spec.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,23 @@ const FLOW_BASE = {
1212
test.describe("Flow Rename via Header", () => {
1313
test(
1414
"flow can be renamed via the header edit",
15-
{ tag: ["@release", "@regression"] },
15+
{ tag: ["@release", "@workspace", "@stable"] },
1616
async ({ page }) => {
1717
await awaitBootstrapTest(page);
18-
await page.waitForSelector('[data-testid="blank-flow"]', {
18+
await expect(page.getByTestId("blank-flow")).toBeVisible({
1919
timeout: 30000,
2020
});
2121
await page.getByTestId("blank-flow").click();
2222

23-
// Wait for canvas to load (sidebar-search-input visible means editor is ready)
24-
await page.waitForSelector('[data-testid="sidebar-search-input"]', {
23+
await expect(page.getByTestId("sidebar-search-input")).toBeVisible({
2524
timeout: 30000,
2625
});
2726

28-
// Use the shared renameFlow utility (handles dirty-state and save)
2927
const newName = `My Renamed Flow ${Date.now()}`;
3028
await renameFlow(page, { flowName: newName });
3129

32-
// The header must show the new name
30+
// Header reflects the new name (renameFlow's waitForFunction already confirms the DOM
31+
// committed before returning — this expect is the test-framework-visible guard)
3332
await expect(page.getByTestId("flow_name")).toHaveText(newName, {
3433
timeout: 10000,
3534
});
@@ -38,7 +37,7 @@ test.describe("Flow Rename via Header", () => {
3837

3938
test(
4039
"flow name persists after rename via API PATCH and GET",
41-
{ tag: ["@release", "@regression"] },
40+
{ tag: ["@release", "@workspace", "@api", "@stable"] },
4241
async ({ request }) => {
4342
const authToken = await getAuthToken(request);
4443
const originalName = `Rename Test Flow - ${Date.now()}`;

0 commit comments

Comments
 (0)