From d551c4b0d49163801d9d4454a39ac1197bc7bbd4 Mon Sep 17 00:00:00 2001 From: le king fu Date: Sun, 18 Oct 2026 20:59:17 -0400 Subject: [PATCH] test: pin the collapsed sub-group order and the banner's dot (#446) reorderRows: a collapsed sub-group (a subtotal with no child row) followed by a sibling leaf gives Vide, z, A, the order read by running the case first; then the same block followed by a sibling root, a group (Vide, z, A, b, B) or a leaf (Vide, z, A, R). OnboardingBanner: the decorative h-1 w-1 dot is absent while the visit steps are not initialized and while the Budget entitlement is unknown, and present, between the counter and the next step, once the total is known. Co-Authored-By: Claude Opus 5.5 --- .../OnboardingBanner.render.test.tsx | 31 +++++++++++++++++-- src/utils/reorderRows.test.ts | 24 ++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/components/onboarding/OnboardingBanner.render.test.tsx b/src/components/onboarding/OnboardingBanner.render.test.tsx index ece4e51..a369166 100644 --- a/src/components/onboarding/OnboardingBanner.render.test.tsx +++ b/src/components/onboarding/OnboardingBanner.render.test.tsx @@ -96,6 +96,13 @@ const buttonNamed = (node: ReactNode, key: string) => { return button; }; +/** The dot between the counter and the next step: a decorative `h-1 w-1` span. */ +const isDot = (e: AnyElement) => { + const classes = String(e.props.className).split(/\s+/); + return e.type === "span" && classes.includes("h-1") && classes.includes("w-1"); +}; +const dots = (props: OnboardingBannerProps) => find(tree(props), isDot); + describe("OnboardingBanner — banner mode (#397)", () => { it("is a region named for the path, with the counter, the next step and its link", () => { const html = markup(bannerProps()); @@ -119,15 +126,35 @@ describe("OnboardingBanner — banner mode (#397)", () => { }); it("the counter waits for the Budget entitlement, the next step does not", () => { - const html = markup(bannerProps({ budgetReady: false })); + const props = bannerProps({ budgetReady: false }); + const html = markup(props); expect(html).not.toContain("onboarding.banner.progress"); expect(html).toMatch(/href="\/import"/); + // The dot waits with the counter it follows (#446). + expect(dots(props)).toHaveLength(0); }); it("the counter waits for the visit steps' initialization too, the next step does not (#425)", () => { - const html = markup(bannerProps({ visitStepsInitialized: false })); + const props = bannerProps({ visitStepsInitialized: false }); + const html = markup(props); expect(html).not.toContain("onboarding.banner.progress"); expect(html).toMatch(/href="\/import"/); + // No dot either: it would stand alone before the next step (#446). + expect(dots(props)).toHaveLength(0); + }); + + it("once the total is known, a decorative dot separates the counter from the next step (#446)", () => { + const props = bannerProps(); + const [dot] = dots(props); + expect(dots(props)).toHaveLength(1); + expect(dot.props["aria-hidden"]).toBe("true"); + const html = markup(props); + const counter = html.indexOf("t(onboarding.banner.progress"); + const dotAt = html.search(/