From 3d6d775d2f0c24f92a2005f45ff618f4cdea3349 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:45:23 -0700 Subject: [PATCH 1/2] deps(ui-kit): publish the recharts v3 migration, with coverage for what it rewrote MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @loopover/ui-kit has been stuck on 1.3.0 while carrying an unreleased, user-visible change: `chore(deps): migrate recharts to v3 across all three workspaces (#8610)` rewrote src/components/chart.tsx and shipped to nobody. release-please would never cut that release on its own. It decides whether a component HAS a release before it decides how much to bump, and that decision keeps only "user facing" commits -- those whose type is not `hidden: true` in changelog-sections. `chore` is hidden here, so its own dry run says: ✔ Building candidate release pull request for path: packages/loopover-ui-kit ✔ No user facing commits found since 0fa52ed838... - skipping This is deliberately typed `deps` -- the repo's own non-hidden "Dependencies" section -- because that is what the release publishes: the recharts v3 migration. `Release-As:` was the other candidate and does not work here; the skip above is on an empty changelog and runs after the version is computed, so a footer on a hidden-type commit is still skipped. The diff is the coverage that migration never had. chart.tsx had NO tests at all, so the load-bearing parts of a major-version rewrite were resting on the type-checker: that payload/label now arrive through context rather than as Tooltip props, that config labels (not raw dataKeys) are what a reader sees, that an inactive or empty payload paints nothing, and that both arms of ChartConfig's color/theme union reach the stylesheet. ResponsiveContainer is replaced with a passthrough for these tests and nothing else is: it measures through a ResizeObserver that never resolves under jsdom, so it renders nothing and discards its children -- which would have made the "renders nothing" assertions pass for entirely the wrong reason. Mutation-tested: forcing the tooltip to always render, inverting ChartStyle's empty-config guard, and dropping useChart's provider check each fail. --- .../src/components/chart.test.tsx | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 packages/loopover-ui-kit/src/components/chart.test.tsx diff --git a/packages/loopover-ui-kit/src/components/chart.test.tsx b/packages/loopover-ui-kit/src/components/chart.test.tsx new file mode 100644 index 0000000000..15326edf2e --- /dev/null +++ b/packages/loopover-ui-kit/src/components/chart.test.tsx @@ -0,0 +1,135 @@ +import { render } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +// ResponsiveContainer measures its parent through a ResizeObserver, and under jsdom that measurement never +// resolves -- it renders NOTHING, discarding its children entirely. Every assertion below would then fail, and +// the "renders nothing" ones would pass for entirely the wrong reason. +// +// Only that one measuring wrapper is replaced, with a plain passthrough; everything else -- including +// ChartContainer, which is the context provider under test -- stays real. Stubbing the whole module would mean +// asserting against a mock rather than against `chart.tsx`. +vi.mock("recharts", async (importOriginal) => ({ + ...(await importOriginal()), + ResponsiveContainer: ({ children }: { children?: React.ReactNode }) =>
{children}
, +})); + +import { + ChartContainer, + ChartLegendContent, + ChartStyle, + ChartTooltipContent, + type ChartConfig, +} from "./chart.js"; + +// #9937: `chart.tsx` is the one file the recharts v3 migration (#8610) rewrote, and it shipped with no tests +// at all -- so the migration's load-bearing behaviours were resting on the type-checker alone. +// +// What v3 actually changed here: `payload` and `label` moved OFF Tooltip's own props and are supplied through +// context, and the render-prop shape is published as `TooltipContentProps`. Everything below drives +// ChartTooltipContent the way recharts now drives it -- as a component receiving that shape -- inside the real +// ChartContainer, so the context wiring the migration touched is exercised rather than assumed. + +const config = { + revenue: { label: "Revenue", color: "#0ea5e9" }, + cost: { label: "Cost", theme: { light: "#111827", dark: "#f9fafb" } }, +} satisfies ChartConfig; + +const payload = [ + { dataKey: "revenue", name: "revenue", value: 120, color: "#0ea5e9", payload: { month: "Jan", revenue: 120 } }, + { dataKey: "cost", name: "cost", value: 80, color: "#111827", payload: { month: "Jan", cost: 80 } }, +]; + +/** ChartTooltipContent calls useChart(), so it must render inside a provider. ChartContainer is that + * provider and is exercised deliberately rather than mocked. Queries are scoped to the slot, never the whole + * container: ChartContainer also emits a