Files
OmniRoute/tests/unit/quota-pool-wizard-edit.test.ts
Diego Rodrigues de Sa e Souza b7a0c54139 chore(lint): batch 5 of #12146 — combos, endpoint, provider-stats, api-manager and costs react-hooks violations resolved (#12174)
* chore(lint): batch 5 of #12146 — resolve the react-hooks compiler violations in combos, endpoint, provider-stats, api-manager and costs

40 violations across 14 files, all real refactors (no eslint-disable, no new
suppressions; the areas' react-hooks entries are deleted from the freeze):

- set-state-in-effect (30): fetch-on-mount effects moved behind an async
  continuation (usePools, usePoolUsage, useApiKeyUsageLimits, Notion/Obsidian
  source cards, A2A/MCP dashboards, ComboControlCenterClient, provider-stats,
  combos modal loaders, ApiManager initial load); prop/state sync converted to
  state adjustment during render with prev tracking (ApiKeyUsageLimitCard,
  PoolWizard dimensions/reset/group snap, combos sortMethod, builder reset,
  builder stage guard, single-provider default, stale intelligent selection);
  localStorage reads became lazy useState initializers (combos usage guide).
- immutability / TDZ (8): effects that scheduled fetchers declared below them
  moved after the declarations (EndpointPageClient, ApiManagerPageClient,
  combos mount load); fetchData relocated below the per-key fetchers it calls.
- static-components (7): provider-stats SortIcon hoisted to module level.
- preserve-manual-memoization (2): ApiManager blockedModels dep destructured to
  a local; provider-scope derivation memoized so downstream memos see a stable
  dependency.

Validation: eslint (CI command with suppressions, --max-warnings 0) clean on the
14 files; dashboard typecheck within baseline; mutation gate no drift; area
tests 208/208 (node) + 29/29 (vitest).

Refs #12146

* chore(lint): batch 5 follow-up — hoist the render-adjustment predicates so the new-code complexity gates stay flat

The render adjustments added one cyclomatic branch to combos/page.tsx and one
cognitive point to PoolWizard (caught by the new-code gate on the committed
work); the compound conditions now live in pure module-level predicates.

* chore(lint): batch 5 follow-up 2 — PoolWizard render adjustments live in two small hooks

One consolidated hook tripped max-lines-per-function (>80) and the cognitive
budget; the dimensions and open/close adjustments now live in two focused hooks
with a shared WizardSetters type, and the group snap stays inline (one branch).
complexityNewCode=0, cognitiveComplexityNewCode=0.

* test(quota): repoint the two PoolWizard structural pins at the render-adjustment hook

quota-edit-opens-wizard anchored the pre-fill block on the old '} else if (editPool)'
effect literal and quota-pool-wizard-edit expected a bare 'if (editPool)' that only
existed there; both now anchor on the batch-5 structure (submit still branches via
if (!editPool)).
2026-08-31 03:10:49 -03:00

168 lines
6.7 KiB
TypeScript

/**
* Structure tests for PoolWizard editPool mode (Task 5 — Phase C1).
*
* Source-scan style, mirroring quota-pool-wizard.test.ts.
* No JSdom needed — pure text analysis of the source file.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
const WIZARD_PATH = path.join(
ROOT,
"src",
"app",
"(dashboard)",
"dashboard",
"costs",
"quota-share",
"components",
"PoolWizard.tsx"
);
const EN_JSON_PATH = path.join(ROOT, "src", "i18n", "messages", "en.json");
const PT_BR_JSON_PATH = path.join(ROOT, "src", "i18n", "messages", "pt-BR.json");
const wizardSrc = fs.readFileSync(WIZARD_PATH, "utf-8");
const enJson = JSON.parse(fs.readFileSync(EN_JSON_PATH, "utf-8")) as Record<string, unknown>;
const ptBrJson = JSON.parse(fs.readFileSync(PT_BR_JSON_PATH, "utf-8")) as Record<string, unknown>;
// ── PoolWizardProps: editPool field ───────────────────────────────────────────
test("PoolWizard.tsx: declares editPool in PoolWizardProps", () => {
assert.ok(wizardSrc.includes("editPool?"), "Expected optional editPool field in PoolWizardProps");
});
test("PoolWizard.tsx: imports QuotaPool type", () => {
assert.ok(
wizardSrc.includes("QuotaPool"),
"Expected QuotaPool type to be referenced in PoolWizard"
);
});
// ── Submit handler branching ──────────────────────────────────────────────────
test("PoolWizard.tsx: submit handler contains a PATCH to /api/quota/pools/ (edit branch)", () => {
assert.ok(
wizardSrc.includes("PATCH") && wizardSrc.includes("/api/quota/pools/"),
"Expected PATCH call to /api/quota/pools/ in PoolWizard"
);
});
test("PoolWizard.tsx: submit handler still contains a POST to /api/quota/pools (create branch)", () => {
assert.ok(
wizardSrc.includes('method: "POST"') && wizardSrc.includes("/api/quota/pools"),
"Expected POST call to /api/quota/pools in PoolWizard (create branch must remain)"
);
});
test("PoolWizard.tsx: submit handler branches on editPool", () => {
assert.ok(
wizardSrc.includes("editPool"),
"Expected editPool to appear in PoolWizard source (branching in submit)"
);
// The branching condition inside handleFinish (create path guards on !editPool;
// the old "} else if (editPool)" literal lived in the reset effect that #12146
// batch 5 turned into a render adjustment).
assert.ok(wizardSrc.includes("if (!editPool)"), "Expected the editPool branch in handleFinish");
});
// ── Pre-fill references ───────────────────────────────────────────────────────
test("PoolWizard.tsx: pre-fills pool name from editPool.name", () => {
assert.ok(
wizardSrc.includes("editPool.name"),
"Expected editPool.name used for pre-filling pool name"
);
});
test("PoolWizard.tsx: pre-fills allocations from editPool.allocations", () => {
assert.ok(
wizardSrc.includes("editPool.allocations"),
"Expected editPool.allocations used for pre-filling allocations"
);
});
test("PoolWizard.tsx: pre-fills connectionIds using editPool.connectionIds and editPool.connectionId", () => {
assert.ok(
wizardSrc.includes("editPool.connectionIds"),
"Expected editPool.connectionIds referenced in pre-fill logic"
);
assert.ok(
wizardSrc.includes("editPool.connectionId"),
"Expected editPool.connectionId referenced as fallback in pre-fill logic"
);
});
test("PoolWizard.tsx: pre-fills groupId from editPool.groupId", () => {
assert.ok(
wizardSrc.includes("editPool.groupId"),
"Expected editPool.groupId used for pre-filling group selector"
);
});
// ── i18n key usage ────────────────────────────────────────────────────────────
test('PoolWizard.tsx: uses t("saveChanges") for the submit button in edit mode', () => {
assert.ok(
wizardSrc.includes('t("saveChanges")'),
'Expected t("saveChanges") used in submit button (edit mode)'
);
});
test('PoolWizard.tsx: uses t("editPoolTitle") for the modal title in edit mode', () => {
assert.ok(
wizardSrc.includes('t("editPoolTitle")'),
'Expected t("editPoolTitle") used in modal title (edit mode)'
);
});
// ── i18n parity: en.json ─────────────────────────────────────────────────────
test("en.json quotaShare namespace: contains editPoolTitle key", () => {
const quotaShare = enJson["quotaShare"] as Record<string, unknown> | undefined;
assert.ok(quotaShare, "Expected quotaShare namespace in en.json");
assert.ok(
"editPoolTitle" in quotaShare,
"Expected editPoolTitle key in en.json quotaShare namespace"
);
assert.equal(typeof quotaShare["editPoolTitle"], "string", "editPoolTitle must be a string");
});
test("en.json quotaShare namespace: contains saveChanges key", () => {
const quotaShare = enJson["quotaShare"] as Record<string, unknown> | undefined;
assert.ok(quotaShare, "Expected quotaShare namespace in en.json");
assert.ok(
"saveChanges" in quotaShare,
"Expected saveChanges key in en.json quotaShare namespace"
);
assert.equal(typeof quotaShare["saveChanges"], "string", "saveChanges must be a string");
});
// ── i18n parity: pt-BR.json ──────────────────────────────────────────────────
test("pt-BR.json quotaShare namespace: contains editPoolTitle key", () => {
const quotaShare = ptBrJson["quotaShare"] as Record<string, unknown> | undefined;
assert.ok(quotaShare, "Expected quotaShare namespace in pt-BR.json");
assert.ok(
"editPoolTitle" in quotaShare,
"Expected editPoolTitle key in pt-BR.json quotaShare namespace"
);
assert.equal(typeof quotaShare["editPoolTitle"], "string", "editPoolTitle must be a string");
});
test("pt-BR.json quotaShare namespace: contains saveChanges key", () => {
const quotaShare = ptBrJson["quotaShare"] as Record<string, unknown> | undefined;
assert.ok(quotaShare, "Expected quotaShare namespace in pt-BR.json");
assert.ok(
"saveChanges" in quotaShare,
"Expected saveChanges key in pt-BR.json quotaShare namespace"
);
assert.equal(typeof quotaShare["saveChanges"], "string", "saveChanges must be a string");
});