Skip to content

Commit 920bde8

Browse files
Merge pull request #172 from oriontech-me/validate/playground-session-id-stable
chore(playground): rewrite playground-session-id and mark @stable
2 parents c4f286d + 3634f40 commit 920bde8

3 files changed

Lines changed: 108 additions & 130 deletions

File tree

QA-CHECKLIST.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@
431431
- [x] Pre-filled Input Text can be sent as the first message of the session → `core-functionality/playground/playground-input-text-prefill.spec.ts`
432432

433433
#### 9.2 History and Session
434-
- [-] Configure custom session ID → `playground/playground-session-id.spec.ts` (needs rewrite — see issue)
434+
- [x] Configure custom session ID → `core-functionality/playground/playground-session-id.spec.ts`
435435
- [x] Switch session — messages are isolated per session → `core-functionality/playground/playground-session-nav.spec.ts`
436436
- [x] Edit user message — hover reveals edit button, saved changes replace original text → `core-functionality/playground/playground-message-edit.spec.ts`
437437
- [x] Cancel message edit — original text is preserved → `core-functionality/playground/playground-message-edit.spec.ts`
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Playground — Session ID Input
2+
3+
**Last validated:** Langflow 1.10.x
4+
5+
---
6+
7+
## What this test validates *(required)*
8+
9+
Validates that the Playground session ID input field is editable and correctly reflects a custom value typed by the user. If this breaks, users cannot control which session context their messages are sent to — affecting multi-session workflows.
10+
11+
---
12+
13+
## Tags *(required)*
14+
15+
`@stable` `@release` `@regression` `@playground`
16+
17+
---
18+
19+
## Step by step *(required)*
20+
21+
1. Use `setupPlayground(page)` to create a blank flow with ChatInput → ChatOutput connected and capture the created `flowId`
22+
2. Click `playground-btn-flow-io` and wait for `input-chat-playground` to be visible (confirms playground is open)
23+
3. Clear `popover-anchor-input-session_id` and fill it with `session-${Date.now()}`
24+
4. Assert the field's value equals the filled string via `toHaveValue`
25+
26+
`afterEach` navigates to `/` and deletes the flow created by the helper via `DELETE /api/v1/flows/{id}`.
27+
28+
---
29+
30+
## Validation criterion *(required)*
31+
32+
- After `.fill()`, `popover-anchor-input-session_id` holds the exact string typed (web-first `toHaveValue` assertion)
33+
34+
---
35+
36+
## External dependencies *(required)*
37+
38+
- `src/frontend/src/components/core/chatComponents/` — session ID input rendered inside the Playground header
39+
- `data-testid="popover-anchor-input-session_id"` — session ID input field
40+
- `data-testid="playground-btn-flow-io"` — opens the Playground from the editor
41+
- `data-testid="input-chat-playground"` — chat input field used as a readiness signal for the Playground
42+
43+
---
44+
45+
## What this test does not cover *(optional)*
46+
47+
- Actual backend isolation between sessions (messages from session A not appearing in session B) — covered by `llm-agents/memory-history-regression.spec.ts`
48+
- The sidebar-based session management (create / switch / rename) introduced in Langflow 1.9+ — covered by `playground-session-nav.spec.ts` and `playground-session-rename.spec.ts`
49+
- Sending a message after switching the session ID — out of scope for this spec
50+
51+
---
52+
53+
## Preconditions *(optional)*
54+
55+
- Langflow running at `PLAYWRIGHT_BASE_URL`
56+
- No LLM required — the test only types into the session ID field, no flow execution happens
57+
58+
---
59+
60+
## Notes *(optional)*
61+
62+
- Test runs in `serial` mode for consistency with sibling playground specs and to keep the cleanup contract simple
63+
- Cleanup deletes only the flow created by this test (id captured from `setupPlayground`'s return value)
Lines changed: 44 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,47 @@
11
import { expect, test } from "../../../../fixtures/fixtures";
2-
import { adjustScreenView } from "../../../../helpers/ui/adjust-screen-view";
3-
import { awaitBootstrapTest } from "../../../../helpers/other/await-bootstrap-test";
4-
import { zoomOut } from "../../../../helpers/ui/zoom-out";
5-
6-
async function setupMockedChatFlow(page: any) {
7-
await awaitBootstrapTest(page);
8-
await page.waitForSelector('[data-testid="blank-flow"]', { timeout: 30000 });
9-
await page.getByTestId("blank-flow").click();
10-
11-
// Add ChatOutput
12-
await page.getByTestId("sidebar-search-input").fill("chat output");
13-
await page.waitForSelector('[data-testid="input_outputChat Output"]', {
14-
timeout: 30000,
15-
});
16-
await page
17-
.getByTestId("input_outputChat Output")
18-
.hover()
19-
.then(async () => {
20-
await page.getByTestId("add-component-button-chat-output").click();
21-
});
22-
23-
await zoomOut(page, 2);
24-
25-
// Add ChatInput via drag
26-
await page.getByTestId("sidebar-search-input").fill("chat input");
27-
await page.waitForSelector('[data-testid="input_outputChat Input"]', {
28-
timeout: 30000,
29-
});
30-
await page
31-
.getByTestId("input_outputChat Input")
32-
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
33-
targetPosition: { x: 100, y: 100 },
34-
});
35-
36-
await adjustScreenView(page);
37-
38-
await expect(page.locator(".react-flow__node")).toHaveCount(2, {
39-
timeout: 10000,
40-
});
41-
42-
// Connect ChatInput → ChatOutput
43-
await page
44-
.getByTestId("handle-chatinput-noshownode-chat message-source")
45-
.click();
46-
await page
47-
.getByTestId("handle-chatoutput-noshownode-inputs-target")
48-
.click();
49-
50-
await expect(page.locator(".react-flow__edge")).toHaveCount(1, {
51-
timeout: 8000,
52-
});
53-
54-
// Mock the run endpoint so no real LLM call is made
55-
await page.route("**/api/v1/run/**", async (route: import("@playwright/test").Route) => {
56-
await route.fulfill({
57-
status: 200,
58-
contentType: "application/json",
59-
body: JSON.stringify({
60-
outputs: [
61-
{
62-
outputs: [
63-
{ results: { message: { text: "Mocked response" } } },
64-
],
65-
},
66-
],
67-
session_id: "mocked-session",
68-
}),
69-
});
2+
import { setupPlayground } from "../../../../helpers/flows/setup-playground";
3+
4+
test.describe("Playground — Session ID input", () => {
5+
test.describe.configure({ mode: "serial" });
6+
7+
let createdFlowId: string | null = null;
8+
9+
test.afterEach(async ({ page }) => {
10+
if (createdFlowId) {
11+
// Navigate to home before deleting to stop background browser requests
12+
// for the current flow; without this, pending polling GETs complete
13+
// after the DELETE and trigger spurious 404 fixture errors.
14+
await page.goto("/");
15+
await page.request.delete(`/api/v1/flows/${createdFlowId}`);
16+
createdFlowId = null;
17+
}
7018
});
71-
}
72-
73-
test(
74-
"playground opens with a chat input field after connecting ChatInput and ChatOutput",
75-
{ tag: ["@release", "@workspace", "@regression", "@playground"] },
76-
async ({ page }) => {
77-
await setupMockedChatFlow(page);
78-
79-
await page.getByTestId("playground-btn-flow-io").click();
80-
await page.waitForSelector('[data-testid="input-chat-playground"]', {
81-
timeout: 15000,
82-
});
83-
84-
const inputField = page.getByTestId("input-chat-playground").last();
85-
await expect(inputField).toBeVisible({ timeout: 5000 });
86-
await expect(inputField).toBeEnabled({ timeout: 3000 });
87-
},
88-
);
89-
90-
test(
91-
"playground session ID input accepts a custom session value",
92-
{ tag: ["@release", "@workspace", "@regression", "@playground"] },
93-
async ({ page }) => {
94-
await setupMockedChatFlow(page);
95-
96-
await page.getByTestId("playground-btn-flow-io").click();
97-
await page.waitForSelector('[data-testid="input-chat-playground"]', {
98-
timeout: 15000,
99-
});
100-
101-
const customSession = `session-${Date.now()}`;
102-
103-
await page.getByTestId("popover-anchor-input-session_id").clear();
104-
await page.getByTestId("popover-anchor-input-session_id").fill(customSession);
105-
await expect(page.getByTestId("popover-anchor-input-session_id")).toHaveValue(customSession);
106-
},
107-
);
108-
109-
test(
110-
"changing session ID in playground resets the conversation history display",
111-
{ tag: ["@release", "@workspace", "@regression", "@playground"] },
112-
async ({ page }) => {
113-
await setupMockedChatFlow(page);
114-
115-
await page.getByTestId("playground-btn-flow-io").click();
116-
await page.waitForSelector('[data-testid="input-chat-playground"]', {
117-
timeout: 15000,
118-
});
119-
120-
await expect(page.getByTestId("input-chat-playground").last()).toBeVisible({ timeout: 5000 });
121-
122-
const sessionA = `session-a-${Date.now()}`;
123-
await page.getByTestId("popover-anchor-input-session_id").clear();
124-
await page.getByTestId("popover-anchor-input-session_id").fill(sessionA);
125-
await expect(page.getByTestId("popover-anchor-input-session_id")).toHaveValue(sessionA);
12619

127-
const sessionB = `session-b-${Date.now()}`;
128-
await page.getByTestId("popover-anchor-input-session_id").clear();
129-
await page.getByTestId("popover-anchor-input-session_id").fill(sessionB);
130-
await expect(page.getByTestId("popover-anchor-input-session_id")).toHaveValue(sessionB);
131-
},
132-
);
20+
test(
21+
"session ID input accepts a custom value",
22+
{ tag: ["@stable", "@release", "@regression", "@playground"] },
23+
async ({ page }) => {
24+
await test.step("set up ChatInput → ChatOutput flow", async () => {
25+
createdFlowId = await setupPlayground(page);
26+
});
27+
28+
await test.step("open playground and wait for chat input", async () => {
29+
await page.getByTestId("playground-btn-flow-io").click();
30+
await expect(
31+
page.getByTestId("input-chat-playground").last(),
32+
).toBeVisible({ timeout: 15000 });
33+
});
34+
35+
await test.step("fill session ID and confirm value persists", async () => {
36+
const customSession = `session-${Date.now()}`;
37+
const sessionInput = page.getByTestId(
38+
"popover-anchor-input-session_id",
39+
);
40+
41+
await sessionInput.clear();
42+
await sessionInput.fill(customSession);
43+
await expect(sessionInput).toHaveValue(customSession);
44+
});
45+
},
46+
);
47+
});

0 commit comments

Comments
 (0)