From bf528b2b653cf25a2ded481cd66c3886929b840c Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Thu, 28 May 2026 13:52:03 -0300 Subject: [PATCH] test(ui): cover StackedAllocationBar segments + weights + usage labels (B/G4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New test file stacked-allocation-bar.test.tsx covers: - empty allocations → null render - 3 segments with correct widths (50%/30%/20%) - 1 segment at 100% - labels without usedSuffix when usage=null - usedSuffix labels when usage provided (consumed/fairShare%) - fallback to apiKeyId when keyLabel missing pool-card.test.tsx updated: mock StackedAllocationBar, assert it renders when pool.allocations is non-empty. --- tests/unit/ui/pool-card.test.tsx | 12 ++ tests/unit/ui/stacked-allocation-bar.test.tsx | 138 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 tests/unit/ui/stacked-allocation-bar.test.tsx diff --git a/tests/unit/ui/pool-card.test.tsx b/tests/unit/ui/pool-card.test.tsx index fc0bdd8d6b..f702f185af 100644 --- a/tests/unit/ui/pool-card.test.tsx +++ b/tests/unit/ui/pool-card.test.tsx @@ -35,6 +35,13 @@ vi.mock( "../../../src/app/(dashboard)/dashboard/costs/quota-share/components/BurnRateChart", () => ({ default: () =>
}) ); +vi.mock( + "../../../src/app/(dashboard)/dashboard/costs/quota-share/components/StackedAllocationBar", + () => ({ + default: ({ allocations }: { allocations: Array }) => + allocations.length > 0 ?
: null, + }) +); const { default: PoolCard } = await import( "../../../src/app/(dashboard)/dashboard/costs/quota-share/components/PoolCard" @@ -115,6 +122,11 @@ describe("PoolCard", { timeout: 10000 }, () => { expect(document.querySelector("[data-testid='burn-rate-chart']")).not.toBeNull(); }); + it("renders StackedAllocationBar when pool has allocations", async () => { + await renderCard(); + expect(document.querySelector("[data-testid='stacked-alloc-bar']")).not.toBeNull(); + }); + it("calls onEdit when edit button clicked", async () => { const onEdit = vi.fn(); container = document.createElement("div"); diff --git a/tests/unit/ui/stacked-allocation-bar.test.tsx b/tests/unit/ui/stacked-allocation-bar.test.tsx new file mode 100644 index 0000000000..57130a6268 --- /dev/null +++ b/tests/unit/ui/stacked-allocation-bar.test.tsx @@ -0,0 +1,138 @@ +// @vitest-environment jsdom +import React from "react"; +import { act } from "react"; +import { createRoot } from "react-dom/client"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +vi.mock("next-intl", () => ({ + useTranslations: () => (key: string, params?: Record) => { + if (params && "percent" in params) return `${key}:${params.percent}`; + return key; + }, +})); + +const { default: StackedAllocationBar } = await import( + "../../../src/app/(dashboard)/dashboard/costs/quota-share/components/StackedAllocationBar" +); + +const ALLOCATIONS_3 = [ + { apiKeyId: "key_1", weight: 50, policy: "hard" as const }, + { apiKeyId: "key_2", weight: 30, policy: "soft" as const }, + { apiKeyId: "key_3", weight: 20, policy: "burst" as const }, +]; + +const ALLOCATIONS_1 = [{ apiKeyId: "key_1", weight: 100, policy: "hard" as const }]; + +const KEY_LABELS: Record = { + key_1: "KeyOne", + key_2: "KeyTwo", + key_3: "KeyThree", +}; + +let container: HTMLDivElement | null = null; +let root: ReturnType | null = null; + +async function render(props: Parameters[0]) { + (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = + true; + container = document.createElement("div"); + document.body.appendChild(container); + await act(async () => { + root = createRoot(container!); + root.render(); + }); +} + +describe("StackedAllocationBar", { timeout: 10000 }, () => { + afterEach(() => { + if (root && container) act(() => root!.unmount()); + container?.remove(); + container = null; + root = null; + }); + + it("returns null when allocations is empty", async () => { + await render({ allocations: [], usage: null, keyLabels: {} }); + // Nothing rendered — container should be empty + expect(container!.innerHTML).toBe(""); + }); + + it("renders 3 segments when given 3 allocations", async () => { + await render({ allocations: ALLOCATIONS_3, usage: null, keyLabels: KEY_LABELS }); + // Each segment is a div inside the stacked bar flex container + const bar = container!.querySelector(".flex.h-3.rounded"); + expect(bar).not.toBeNull(); + const segments = bar!.children; + expect(segments.length).toBe(3); + }); + + it("each segment has the correct width style", async () => { + await render({ allocations: ALLOCATIONS_3, usage: null, keyLabels: KEY_LABELS }); + const bar = container!.querySelector(".flex.h-3.rounded"); + expect(bar).not.toBeNull(); + const segments = bar!.children; + expect((segments[0] as HTMLElement).style.width).toBe("50%"); + expect((segments[1] as HTMLElement).style.width).toBe("30%"); + expect((segments[2] as HTMLElement).style.width).toBe("20%"); + }); + + it("renders 1 segment when given 1 allocation", async () => { + await render({ allocations: ALLOCATIONS_1, usage: null, keyLabels: KEY_LABELS }); + const bar = container!.querySelector(".flex.h-3.rounded"); + expect(bar).not.toBeNull(); + expect(bar!.children.length).toBe(1); + expect((bar!.children[0] as HTMLElement).style.width).toBe("100%"); + }); + + it("renders segments with weight but no 'usedSuffix' text when usage is null", async () => { + await render({ allocations: ALLOCATIONS_3, usage: null, keyLabels: KEY_LABELS }); + // Labels exist with weight + expect(container!.innerHTML).toContain("KeyOne 50%"); + expect(container!.innerHTML).toContain("KeyTwo 30%"); + expect(container!.innerHTML).toContain("KeyThree 20%"); + // No "usedSuffix" text since no usage + expect(container!.innerHTML).not.toContain("usedSuffix"); + }); + + it("renders usedSuffix labels when usage is provided", async () => { + const usage = { + poolId: "pool_1", + generatedAt: new Date().toISOString(), + dimensions: [ + { + unit: "tokens", + window: "daily", + limit: 1000, + consumedTotal: 600, + perKey: [ + { apiKeyId: "key_1", consumed: 400, fairShare: 500, deficit: -100, borrowing: false }, + { apiKeyId: "key_2", consumed: 120, fairShare: 300, deficit: 180, borrowing: false }, + ], + }, + ], + }; + await render({ + allocations: ALLOCATIONS_3, + usage: usage as never, + keyLabels: KEY_LABELS, + dimensionIndex: 0, + }); + // key_1: consumed 400, fairShare 500 → 80% + expect(container!.innerHTML).toContain("usedSuffix:80"); + // key_2: consumed 120, fairShare 300 → 40% + expect(container!.innerHTML).toContain("usedSuffix:40"); + // key_3 has no usage entry — no usedSuffix for that key + expect(container!.innerHTML).toContain("KeyThree 20%"); + }); + + it("renders the stackedBarTitle header", async () => { + await render({ allocations: ALLOCATIONS_1, usage: null, keyLabels: KEY_LABELS }); + expect(container!.innerHTML).toContain("stackedBarTitle"); + }); + + it("falls back to apiKeyId when keyLabel is not provided", async () => { + await render({ allocations: ALLOCATIONS_1, usage: null, keyLabels: {} }); + // No label provided — apiKeyId "key_1" should appear + expect(container!.innerHTML).toContain("key_1"); + }); +});