Skip to content

Commit 352527c

Browse files
committed
fix: add play functions to ensure Chromatic captures scrolled state
- Add waitForChatScroll play function that waits for messages to load and scroll to complete before Chromatic takes screenshots - Add data-testid="message-window" to scroll container in AIView - Add data-testid="chat-message" to message wrappers for test queries - Apply play function to ActiveWorkspaceWithChat and MarkdownTables stories - Fix ProviderIcon lint error: remove redundant "mux-gateway" union type (already included in ProviderName)
1 parent a61c99c commit 352527c

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

bun.lock

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@
11791179

11801180
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.17", "", { "dependencies": { "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "tailwindcss": "4.1.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA=="],
11811181

1182-
"@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="],
1182+
"@testing-library/dom": ["@testing-library/dom@10.4.0", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" } }, "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ=="],
11831183

11841184
"@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="],
11851185

@@ -3747,6 +3747,8 @@
37473747

37483748
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
37493749

3750+
"@testing-library/dom/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
3751+
37503752
"@testing-library/dom/pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
37513753

37523754
"@testing-library/jest-dom/aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
@@ -4165,6 +4167,8 @@
41654167

41664168
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
41674169

4170+
"@testing-library/dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
4171+
41684172
"@testing-library/dom/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
41694173

41704174
"@testing-library/dom/pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],

src/browser/App.stories.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,49 @@
11
import type { Meta, StoryObj } from "@storybook/react-vite";
22
import { useMemo } from "react";
3+
import { waitFor, within } from "storybook/test";
34
import { AppLoader } from "./components/AppLoader";
45
import type { ProjectConfig } from "@/node/config";
56
import type { FrontendWorkspaceMetadata } from "@/common/types/workspace";
67
import type { WorkspaceChatMessage } from "@/common/orpc/types";
78
import { DEFAULT_RUNTIME_CONFIG } from "@/common/constants/workspace";
89
import { createMockORPCClient, type MockORPCClientOptions } from "../../.storybook/mocks/orpc";
910

11+
/**
12+
* Play function that waits for chat messages to load and scroll to complete.
13+
* Used by Chromatic to ensure screenshots capture the final scrolled state.
14+
*/
15+
async function waitForChatScroll({ canvasElement }: { canvasElement: HTMLElement }) {
16+
const canvas = within(canvasElement);
17+
18+
// Wait for messages to appear (they load via setTimeout in mock)
19+
await waitFor(
20+
() => {
21+
const messages = canvas.queryAllByTestId("chat-message");
22+
if (messages.length === 0) {
23+
throw new Error("No messages yet");
24+
}
25+
},
26+
{ timeout: 2000 }
27+
);
28+
29+
// Wait for scroll to be at or near bottom
30+
await waitFor(
31+
() => {
32+
const messageWindow = canvasElement.querySelector('[data-testid="message-window"]');
33+
if (!messageWindow) {
34+
throw new Error("Message window not found");
35+
}
36+
const { scrollTop, scrollHeight, clientHeight } = messageWindow;
37+
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
38+
// Allow 50px tolerance for "at bottom"
39+
if (distanceFromBottom > 50) {
40+
throw new Error(`Not scrolled to bottom yet (${distanceFromBottom}px from bottom)`);
41+
}
42+
},
43+
{ timeout: 2000 }
44+
);
45+
}
46+
1047
// Stable timestamp for testing active states (use fixed time minus small offsets)
1148
// This ensures workspaces don't show as "Older than 1 day" and keeps stories deterministic
1249
const NOW = 1700000000000; // Fixed timestamp: Nov 14, 2023
@@ -1093,6 +1130,7 @@ main
10931130
/>
10941131
);
10951132
},
1133+
play: waitForChatScroll,
10961134
};
10971135

10981136
/**
@@ -1234,4 +1272,5 @@ These tables should render cleanly without any disruptive copy or download actio
12341272

12351273
return <AppWithMocks projects={projects} workspaces={workspaces} onChat={onChat} />;
12361274
},
1275+
play: waitForChatScroll,
12371276
};

src/browser/components/AIView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ const AIViewInner: React.FC<AIViewProps> = ({
476476
aria-busy={canInterrupt}
477477
aria-label="Conversation transcript"
478478
tabIndex={0}
479+
data-testid="message-window"
479480
className="h-full overflow-y-auto p-[15px] leading-[1.5] break-words whitespace-pre-wrap"
480481
>
481482
<div className={cn("max-w-4xl mx-auto", mergedMessages.length === 0 && "h-full")}>
@@ -505,6 +506,7 @@ const AIViewInner: React.FC<AIViewProps> = ({
505506
return (
506507
<React.Fragment key={msg.id}>
507508
<div
509+
data-testid="chat-message"
508510
data-message-id={
509511
msg.type !== "history-hidden" && msg.type !== "workspace-init"
510512
? msg.historyId

0 commit comments

Comments
 (0)