Skip to content

Commit f51ad35

Browse files
🤖 fix: stabilize scroll position in CodeBlocks story to prevent flaky snapshots (#1214)
The CodeBlocks story was flaky because `useAutoScroll`'s ResizeObserver fires when Shiki highlighting completes, causing scroll-to-bottom which shifts elements by a few pixels. **Fix:** - Wait for all 3 `.code-block-wrapper` elements to have Shiki spans (ensures highlighting is done) - Scroll to top after highlighting and wait a frame for ResizeObserver to settle --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
1 parent 1adeaec commit f51ad35

File tree

1 file changed

+28
-15
lines changed

1 file changed

+28
-15
lines changed

‎src/browser/stories/App.markdown.stories.tsx‎

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,28 +254,41 @@ export const CodeBlocks: AppStory = {
254254
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
255255
await waitForChatMessagesLoaded(canvasElement);
256256

257-
const url = "https://github.com/coder/mux/pull/new/chat-autocomplete-b24r";
258-
259-
// Find the highlighted code block containing the URL.
260-
const container = await waitFor(
257+
// Wait for ALL code blocks with language hints to be highlighted.
258+
// CODE_CONTENT has 3 language-tagged blocks (2× typescript, 1× text) that use async Shiki.
259+
// Waiting for all prevents flaky snapshots from partial highlighting state.
260+
await waitFor(
261261
() => {
262-
const candidates = Array.from(canvasElement.querySelectorAll(".code-block-container"));
263-
const found = candidates.find((el) => el.textContent?.includes(url));
264-
if (!found) {
265-
throw new Error("URL code block not found");
262+
const candidates = canvasElement.querySelectorAll(".code-block-wrapper");
263+
if (candidates.length < 3) {
264+
throw new Error(`Expected 3 code-block-wrappers, found ${candidates.length}`);
265+
}
266+
// Each must have highlighted spans (Shiki wraps tokens in spans)
267+
for (const wrapper of candidates) {
268+
if (!wrapper.querySelector(".code-line span")) {
269+
throw new Error("Not all code blocks highlighted yet");
270+
}
266271
}
267-
return found;
268272
},
269273
{ timeout: 5000 }
270274
);
271275

272-
// Ensure we capture the post-highlight DOM (Shiki wraps tokens in spans).
273-
await waitFor(
276+
// Scroll to bottom and wait a frame for ResizeObserver to settle.
277+
// Shiki highlighting can trigger useAutoScroll's ResizeObserver, causing scroll jitter.
278+
const scrollContainer = canvasElement.querySelector('[data-testid="message-window"]');
279+
if (scrollContainer) {
280+
scrollContainer.scrollTop = scrollContainer.scrollHeight;
281+
await new Promise((r) => requestAnimationFrame(r));
282+
}
283+
284+
const url = "https://github.com/coder/mux/pull/new/chat-autocomplete-b24r";
285+
const container = await waitFor(
274286
() => {
275-
const hasHighlightedSpans = container.querySelector(".code-line span");
276-
if (!hasHighlightedSpans) {
277-
throw new Error("Code block not highlighted yet");
278-
}
287+
const found = Array.from(canvasElement.querySelectorAll(".code-block-container")).find(
288+
(c) => c.textContent?.includes(url)
289+
);
290+
if (!found) throw new Error("URL code block not found");
291+
return found;
279292
},
280293
{ timeout: 5000 }
281294
);

0 commit comments

Comments
 (0)