mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-15 19:32:20 +03:00
* 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)).
168 lines
6.7 KiB
TypeScript
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");
|
|
});
|