|
| 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. |
0 commit comments