diff --git a/src/components/Badge.test.tsx b/src/components/Badge.test.tsx index 00fd6c7c..44d7415a 100644 --- a/src/components/Badge.test.tsx +++ b/src/components/Badge.test.tsx @@ -23,22 +23,18 @@ describe("Badge component", () => { expect(badge).toHaveClass("border-rmigray-200"); }); - // Type assertions: children must be scalar (string|number) it("disallows ReactNode children for Badge at compile-time", () => { // @ts-expect-error - Badge children must be string | number render( - Not allowed +
Not allowed
, ); }); it("applies pathwayType styling when variant is 'pathwayType'", () => { const { container } = render( - , + Pathway Type, ); const badge = container.firstChild as HTMLElement; @@ -48,12 +44,7 @@ describe("Badge component", () => { }); it("applies temperature styling when variant is 'temperature'", () => { - const { container } = render( - , - ); + const { container } = render(1.5°C); const badge = container.firstChild as HTMLElement; expect(badge).toHaveClass("bg-rmired-100"); @@ -62,12 +53,7 @@ describe("Badge component", () => { }); it("applies year styling when variant is 'year'", () => { - const { container } = render( - , - ); + const { container } = render(2050); const badge = container.firstChild as HTMLElement; expect(badge).toHaveClass("bg-rmiblue-100"); @@ -77,10 +63,7 @@ describe("Badge component", () => { it("applies geography styling when variant is 'geographyGlobal'", () => { const { container } = render( - , + Global, ); const badge = container.firstChild as HTMLElement; @@ -91,10 +74,7 @@ describe("Badge component", () => { it("applies geography styling when variant is 'geographyRegion'", () => { const { container } = render( - , + RegionName, ); const badge = container.firstChild as HTMLElement; @@ -105,10 +85,7 @@ describe("Badge component", () => { it("applies geography styling when variant is 'geographyCountry'", () => { const { container } = render( - , + CountryName, ); const badge = container.firstChild as HTMLElement; @@ -118,12 +95,7 @@ describe("Badge component", () => { }); it("applies sector styling when variant is 'sector'", () => { - const { container } = render( - , - ); + const { container } = render(Energy); const badge = container.firstChild as HTMLElement; expect(badge).toHaveClass("bg-solar-100"); @@ -140,16 +112,9 @@ describe("Badge component", () => { }); it("always includes base badge styling", () => { - // Testing that common styles are applied to all variants - const { container } = render( - , - ); + const { container } = render(Test); const badge = container.firstChild as HTMLElement; - // Check for common styling classes that should be on all badges expect(badge).toHaveClass("inline-flex"); expect(badge).toHaveClass("items-center"); expect(badge).toHaveClass("rounded-full"); @@ -161,18 +126,13 @@ describe("Badge component", () => { }); it("renders as a span element", () => { - const { container } = render(); + const { container } = render(Test); expect(container.firstChild?.nodeName).toBe("SPAN"); }); - // Tooltip tests it("does not render tooltip when no tooltip is provided", () => { render(No Tooltip); - - // Find the badge span const badge = screen.getByText("No Tooltip"); - - // Check that it's a plain span without tabindex expect(badge).toBeInTheDocument(); expect(badge).not.toHaveAttribute("tabindex"); }); @@ -180,25 +140,16 @@ describe("Badge component", () => { it("uses TextWithTooltip when tooltip is provided", () => { render(With Tooltip); - // Badge text should still be present const badgeText = screen.getByText("With Tooltip"); expect(badgeText).toBeInTheDocument(); - // The outer span from TextWithTooltip should have tabindex attribute - // We need to look for a parent element with tabindex since the badge text itself - // is wrapped in its own span const triggerElement = badgeText.closest("span")?.parentElement; expect(triggerElement).toHaveAttribute("tabindex", "0"); - - // The aria-describedby attribute is added when tooltip is visible expect(triggerElement).not.toHaveAttribute("aria-describedby"); }); - // Testing tooltip visibility requires checking document.body, since tooltips are now in portals it("doesn't show tooltip initially", () => { render(Hover me); - - // Initially the tooltip shouldn't be in document.body const tooltipElement = document.querySelector("[role='tooltip']"); expect(tooltipElement).not.toBeInTheDocument(); }); @@ -280,9 +231,11 @@ describe("Badge component", () => { describe("BadgeMaybeAbsent", () => { it("renders 'None' for undefined/null", () => { - const { rerender } = render(); + const { rerender } = render( + {undefined}, + ); expect(screen.getByText("None")).toBeInTheDocument(); - rerender(); + rerender({null}); expect(screen.getByText("None")).toBeInTheDocument(); }); @@ -301,14 +254,13 @@ describe("BadgeMaybeAbsent", () => { it("uses toLabel only for present values", () => { const toLabel = (v: number) => `Y${v}`; const { rerender } = render( - toLabel={toLabel}>2030, + toLabel={toLabel}>{2030}, ); expect(screen.getByText("Y2030")).toBeInTheDocument(); rerender( - - text={undefined} - toLabel={toLabel} - />, + toLabel={toLabel}> + {undefined} + , ); expect(screen.getByText("None")).toBeInTheDocument(); }); @@ -317,17 +269,14 @@ describe("BadgeMaybeAbsent", () => { // @ts-expect-error - BadgeMaybeAbsent children must be string | number | null | undefined render( - Not allowed +
Not allowed
, ); }); it("supports noneLabel override", () => { render( - , + {undefined}, ); expect(screen.getByText("No Value")).toBeInTheDocument(); }); diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx index 9c312244..4dc930b4 100644 --- a/src/components/Badge.tsx +++ b/src/components/Badge.tsx @@ -13,7 +13,9 @@ interface BadgeProps { | "geographyGlobal" | "geographyRegion" | "geographyCountry" - | "sector"; + | "sector" + | "metric" + | "keyFeature"; className?: string; } @@ -53,13 +55,10 @@ const Badge: React.FC = ({ ? `${badgeStylesBase} ${className}` : badgeStylesBase; - // If no tooltip, just return the basic badge - // If no tooltip, just return the basic badge if (!tooltip) { return {children}; } - // With tooltip, use the TextWithTooltip component return ( {children}} @@ -70,7 +69,6 @@ const Badge: React.FC = ({ }; export default Badge; -// --- value-aware helpers (schema-agnostic) -------------------- export type BadgeMaybeAbsentProps = Omit< React.ComponentProps, @@ -83,7 +81,7 @@ export type BadgeMaybeAbsentProps = Omit< /** Visible text for the "None" case (default "None"). */ noneLabel?: string; /** Optional decorator for the final label (e.g., highlight search matches). */ - renderLabel?: (label: string, isAbsent: boolean) => React.ReactNode; + renderLabel?: (label: string, isAbsent: boolean) => string | number; }; export function BadgeMaybeAbsent({ @@ -104,11 +102,11 @@ export function BadgeMaybeAbsent({ } else if (typeof children === "string" || typeof children === "number") { base = String(children); } else { - // Should be unreachable at runtime due to typing, but keep a safe fallback base = String(children as unknown as string | number); } const content = renderLabel && typeof base === "string" ? renderLabel(base, absent) : base; - return {content}; + + return {String(content)}; }