Files
OmniRoute/tests/unit/ui/compressionCockpit.test.tsx
nguyenha935 4012bac41d fix(i18n): preserve remaining Vietnamese localization (#7935)
* fix(i18n): preserve remaining Vietnamese localization

* chore(quality): rebaseline file-size cap for 9 dashboard components (i18n wiring)

Restoring the Vietnamese localization on 9 dashboard components (useTranslations
wiring + t()/tc() call-site swaps for previously hardcoded strings) grows each
file by a small, irreducible amount. Bumps the frozen file-size-baseline.json
caps to match, with a justification entry per the project's own ratchet policy.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(i18n): wire weekday localization + add missing qwen CLI description

Two gaps left by this PR's own new contract tests, caught while
reconciling the branch against the release tip:

- CostOverviewTab.tsx added formatWeekdayLabel() but never called it;
  the Weekly Usage Pattern chart still showed raw English day
  abbreviations regardless of locale. Now maps weeklyPattern rows
  through it before handing them to WeeklyPatternCard.
- cliTools.toolDescriptions was missing an entry for "qwen" (a
  baseUrlSupport:"full" tool) in both en.json and vi.json, failing
  the PR's own cli-catalog-display-contract.test.ts.

Covered by the PR's existing tests/unit/dashboard-localization-contract.test.ts
and tests/unit/cli-catalog-display-contract.test.ts (both now pass).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* i18n(vi): backfill the 4 proxySubscription keys #7299 added to en.json

#7299 (proxy subscriptions) merged while this branch was rebasing, adding
settings.proxySubscriptionsTab and settings.proxySubscription.error.{LOCAL_CORE_ENDPOINT_INVALID,
NEEDS_CORE_NOT_CONFIGURED,NO_USABLE_NODES} to en.json. This PR's own
i18n-vi-completeness contract asserts full en↔vi key parity, so the merge of the
current release tip surfaced them as missing. Adds the Vietnamese translations,
keeping the SS/VMess/Trojan/VLESS/SOCKS5 technical terms verbatim.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: nguyenha935 <208228297+nguyenha935@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: nguyenha935 <nguyenha935@users.noreply.github.com>
2026-07-21 13:41:02 -03:00

191 lines
7.2 KiB
TypeScript

// @vitest-environment jsdom
import React, { act } from "react";
import { createRoot } from "react-dom/client";
import { describe, it, expect, beforeAll, beforeEach, afterEach, vi } from "vitest";
import { NextIntlClientProvider } from "next-intl";
import messages from "../../../src/i18n/messages/en.json";
import type { CompressionRunModel } from "@/app/(dashboard)/dashboard/compression/studio/compressionFlowModel";
// ── Polyfill ResizeObserver (required by ReactFlow) ───────────────────────
beforeAll(() => {
globalThis.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
} as unknown as typeof ResizeObserver;
});
// ── Mocks ─────────────────────────────────────────────────────────────────
// Stub @xyflow/react so ReactFlow renders without canvas/DOM measurement APIs
vi.mock("@xyflow/react", async () => {
const actual = (await vi.importActual("@xyflow/react")) as Record<string, unknown>;
return {
...actual,
Handle: (_props: Record<string, unknown>) => null,
Position: { Left: "left", Right: "right", Top: "top", Bottom: "bottom" },
};
});
// ── Import after mocks ─────────────────────────────────────────────────────
const { CompressionCockpit } =
await import("@/app/(dashboard)/dashboard/compression/studio/CompressionCockpit");
// ── Helpers ───────────────────────────────────────────────────────────────
const containers: HTMLElement[] = [];
function mount(ui: React.ReactElement): HTMLElement {
const container = document.createElement("div");
document.body.appendChild(container);
containers.push(container);
const root = createRoot(container);
act(() => {
root.render(
<NextIntlClientProvider
locale="en"
messages={{ compressionStudio: messages.compressionStudio }}
>
{ui}
</NextIntlClientProvider>
);
});
return container;
}
function click(el: Element | null): void {
act(() => {
el?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
}
beforeEach(() => {
(
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
).IS_REACT_ACT_ENVIRONMENT = true;
});
afterEach(() => {
while (containers.length > 0) {
containers.pop()?.remove();
}
document.body.innerHTML = "";
});
// ── Sample run ────────────────────────────────────────────────────────────
const SAMPLE_RUN: CompressionRunModel = {
requestId: "test-req-001",
comboId: "daily-cascade",
mode: "stacked",
originalTokens: 12480,
compressedTokens: 6090,
savingsPercent: 51.2,
timestamp: 1718000000000,
steps: [
{
engine: "rtk",
originalTokens: 12480,
compressedTokens: 9734,
savingsPercent: 22.0,
techniquesUsed: ["strip-comments", "shell-filter"],
durationMs: 1.8,
},
{
engine: "headroom",
originalTokens: 9734,
compressedTokens: 8524,
savingsPercent: 12.4,
techniquesUsed: ["smartcrusher"],
durationMs: 0.9,
},
{
engine: "caveman",
originalTokens: 8524,
compressedTokens: 6896,
savingsPercent: 19.1,
techniquesUsed: ["pt-BR", "filler-drop"],
durationMs: 0.6,
},
],
};
// ── Tests ─────────────────────────────────────────────────────────────────
describe("CompressionCockpit", () => {
it("renders the cockpit wrapper when a run is provided", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
expect(container.querySelector("[data-testid='compression-cockpit']")).toBeTruthy();
});
it("renders the ReactFlow canvas", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
expect(container.querySelector(".react-flow")).toBeTruthy();
});
it("shows the mode in the header", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
expect(container.textContent).toContain("stacked");
});
it("shows the comboId in the header", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
expect(container.textContent).toContain("daily-cascade");
});
it("shows the total savings percentage in the header", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
expect(container.textContent).toContain("51.2");
});
it("shows engine names (from node labels via ReactFlow)", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
// The engine names appear in the header text even if ReactFlow node internals
// don't render in jsdom — we also check the header region.
const text = container.textContent ?? "";
// At minimum the run metadata renders correctly
expect(text).toContain("test-req-001");
});
it("renders the empty state when no run is given", () => {
const container = mount(<CompressionCockpit />);
expect(container.querySelector("[data-testid='compression-cockpit-empty']")).toBeTruthy();
expect(container.textContent).toContain("No compression run available");
});
it("renders replay controls when a run is provided", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
// Replay button present
const text = container.textContent ?? "";
expect(text).toContain("Replay");
});
it("offers a Canvas/Waterfall view toggle", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
expect(container.querySelector("[data-testid='cockpit-view-canvas']")).toBeTruthy();
expect(container.querySelector("[data-testid='cockpit-view-waterfall']")).toBeTruthy();
});
it("switches to the waterfall inspector and back to the canvas", () => {
const container = mount(<CompressionCockpit run={SAMPLE_RUN} />);
// Default view is the ReactFlow canvas, waterfall hidden.
expect(container.querySelector(".react-flow")).toBeTruthy();
expect(container.querySelector("[data-testid='waterfall-inspector']")).toBeFalsy();
// Switch to the waterfall (A1) view — the previously-orphan component is now reachable.
click(container.querySelector("[data-testid='cockpit-view-waterfall']"));
expect(container.querySelector("[data-testid='waterfall-inspector']")).toBeTruthy();
expect(container.querySelector(".react-flow")).toBeFalsy();
expect(
container.querySelector("[data-testid='waterfall-total-savings']")?.textContent
).toContain("51.2");
// Switch back to the canvas.
click(container.querySelector("[data-testid='cockpit-view-canvas']"));
expect(container.querySelector(".react-flow")).toBeTruthy();
expect(container.querySelector("[data-testid='waterfall-inspector']")).toBeFalsy();
});
});