fix: sample the SkillsScreen geometry only once the Frontmatter highlighter has landed
The "Long Skill Document" story compared the section heights before and after a collapse-then-reopen of the Skill Resource panel, and #2291 wrapped the second sample in a `waitFor` on the reading that the first was fine and the second was taken mid-layout. It was not: `[…, 155, 285]` is the layout with the Frontmatter section showing `CodeHighlight`'s plain `Code` placeholder (a 57px `<pre>`), and `[…, 178, 262]` is the same layout once the lazily imported Prism runtime and YAML grammar have landed and the highlighter has replaced it (an 80px `<pre><code>`). Both are settled; the section's content changed between the two samples, so no retry converges. Whether the swap has happened when the story reaches its first sample depends on how long those dynamic imports take. On a quiet machine an earlier story in the file has already loaded them; under the gate's load they land between the samples. Running the story on its own, so the cache is cold, reproduces the failure deterministically: 3/3 red with the exact four numbers from #2350, 3/3 green with this change, 3/3 red reverted. The whole storybook project under a concurrent unit-suite load (load average 38-51) is 3/3 green with it. The wait's budget is stated at the site: three dynamic imports through the Vite server every story iframe shares measure 100-150ms cold on an idle server and exceeded Testing Library's 1000ms default under load, so it takes the same 10s the Ace-worker wait in `JsonObjectInput.stories.tsx` carries, under the project's 15s `testTimeout`. Closes #2350 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PsmUAZ6aLUAFqenjJKSSRp Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
4673e04e13
commit
274e3adca4
1 changed files with 49 additions and 6 deletions
|
|
@ -440,6 +440,45 @@ export const LongSkillDocument: Story = {
|
|||
const geometry = () =>
|
||||
sections().map((s) => Math.round(s.getBoundingClientRect().height));
|
||||
|
||||
// Hold the first geometry sample until the Frontmatter section has settled
|
||||
// on its final content. That section renders its YAML through
|
||||
// `CodeHighlight`, which paints a plain `Code` block until the lazily
|
||||
// imported Prism runtime and grammar land and then swaps the highlighter
|
||||
// in — for this fixture a rendering 23px taller (the theme's `<pre>`
|
||||
// padding against Mantine's). Whether the swap has happened by the time
|
||||
// the story gets here depends on how long those dynamic imports take: on
|
||||
// a quiet machine an earlier story in this file has already loaded them,
|
||||
// and on a loaded one they land between the two samples below, so
|
||||
// `before` measured the placeholder and the reopen measured the
|
||||
// highlighter — `[…, 155, 285]` against `[…, 178, 262]`, one total
|
||||
// redistributed (#2350). Neither sample was mid-layout; the section's
|
||||
// content changed under the story. Waiting for the highlighted output
|
||||
// makes both samples measure the same content, which is what the
|
||||
// collapse-then-reopen comparison at the end assumes.
|
||||
const frontmatterPanel = (
|
||||
await canvas.findByRole("button", { name: /Frontmatter/ })
|
||||
)
|
||||
.closest(".mantine-Accordion-item")
|
||||
?.querySelector(".mantine-Accordion-panel");
|
||||
if (!(frontmatterPanel instanceof HTMLElement)) {
|
||||
throw new Error("Frontmatter panel not found");
|
||||
}
|
||||
await waitFor(
|
||||
async () => {
|
||||
// `<pre><code>` is the highlighter's output; the placeholder is a
|
||||
// Mantine `Code` block, a bare `<pre>`.
|
||||
await expect(frontmatterPanel.querySelector("pre code")).not.toBeNull();
|
||||
},
|
||||
// What this waits on is three dynamic imports served by the Vite dev
|
||||
// server every story iframe in the run shares, not a React commit:
|
||||
// 100-150ms cold on an idle server, and past Testing Library's 1000ms
|
||||
// default under the gate's load, which is how the two samples came to
|
||||
// straddle it. The same shape and budget as the Ace-worker wait in
|
||||
// `JsonObjectInput.stories.tsx` (#2292), and for the same reason under
|
||||
// the storybook project's 15s `testTimeout`.
|
||||
{ timeout: 10000 },
|
||||
);
|
||||
|
||||
// Every section keeps a usable height: none is crushed to nothing by the
|
||||
// viewer's content, which is exactly what a content-sized basis did.
|
||||
const before = geometry();
|
||||
|
|
@ -483,12 +522,16 @@ export const LongSkillDocument: Story = {
|
|||
// still not settled when the click resolves: `userEvent.click` returns once
|
||||
// the event is dispatched, ahead of React committing the `openSections`
|
||||
// update, remounting the panel's content, and the browser running the
|
||||
// layout pass that redistributes height across the flex sections. Sampling
|
||||
// once lands mid-redistribution under load and fails intermittently
|
||||
// (#2278), so read the geometry under `waitFor` and let it retry until the
|
||||
// panes stop moving. The reopened layout only ever converges ON `before`
|
||||
// rather than passing through it, so retrying cannot mask a real
|
||||
// regression.
|
||||
// layout pass that redistributes height across the flex sections. So read
|
||||
// the geometry under `waitFor` and let it retry until the panes stop
|
||||
// moving. The reopened layout only ever converges ON `before` rather than
|
||||
// passing through it, so retrying cannot mask a real regression.
|
||||
//
|
||||
// ⚠️ This retry is not what fixed the intermittent `[…, 178, 262]` failure
|
||||
// (#2278, then #2350): that was the Frontmatter highlighter landing between
|
||||
// the two samples — a settled second layout for changed content, which no
|
||||
// amount of retrying converges — and it is removed by the wait above, not
|
||||
// by this one.
|
||||
await userEvent.click(viewerControl);
|
||||
await userEvent.click(viewerControl);
|
||||
await waitFor(async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue