Files
OmniRoute/tests/unit/remaining-tasks.test.mjs
diegosouzapw f77dd89d53 feat(remaining): deferred tasks — error pages, UX components, telemetry, domain extraction
T-20 — .gitignore cleanup:
- Add .analysis/ and antigravity-manager-analysis/ to gitignore
- Whitelist FASE docs, PLANO-IMPLANTACAO.md, TASKS.md

T-21 — Error pages:
- Create not-found.js (404 page with gradient design)
- Create global-error.js (root error boundary with dev details)

T-36 — Breadcrumbs:
- Create Breadcrumbs.js with path-to-label mapping and ARIA semantics

T-37 — Empty states:
- Create EmptyState.js with bounce animation and optional CTA

T-45 — Request telemetry:
- Create requestTelemetry.js (7-phase lifecycle, p50/p95/p99 aggregation)

T-46 — Domain extraction:
- Create comboResolver.js (priority/round-robin/random/least-used strategies)
- Create lockoutPolicy.js (sliding window lockout with force-unlock)

Tests: 13/13 new tests pass (88/88 total)
2026-02-14 18:43:07 -03:00

157 lines
4.8 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
// ═════════════════════════════════════════════════════
// Remaining Tasks Tests: Telemetry, Domain Extraction
// ═════════════════════════════════════════════════════
// ─── Request Telemetry (T-45) ────────────────────
import {
RequestTelemetry,
recordTelemetry,
getTelemetrySummary,
} from "../../src/shared/utils/requestTelemetry.js";
test("RequestTelemetry: records phases", async () => {
const t = new RequestTelemetry("tel-1");
t.startPhase("parse");
t.endPhase();
t.startPhase("validate");
t.endPhase();
const summary = t.getSummary();
assert.equal(summary.phases.length, 2);
assert.equal(summary.phases[0].phase, "parse");
assert.equal(summary.phases[1].phase, "validate");
});
test("RequestTelemetry: measure() wraps async functions", async () => {
const t = new RequestTelemetry("tel-2");
const result = await t.measure("parse", async () => "parsed");
assert.equal(result, "parsed");
assert.equal(t.getSummary().phases.length, 1);
assert.equal(t.getSummary().phases[0].phase, "parse");
});
test("RequestTelemetry: measure() records errors", async () => {
const t = new RequestTelemetry("tel-3");
await assert.rejects(
() => t.measure("connect", async () => { throw new Error("timeout"); }),
(err) => err.message === "timeout"
);
assert.equal(t.getSummary().phases[0].error, "timeout");
});
test("RequestTelemetry: getTelemetrySummary returns valid output", () => {
const t = new RequestTelemetry("tel-4");
t.startPhase("parse");
t.endPhase();
recordTelemetry(t);
const summary = getTelemetrySummary();
assert.ok(summary.count > 0);
assert.ok(typeof summary.p50 === "number");
assert.ok(typeof summary.p95 === "number");
});
// ─── Combo Resolver (T-46) ──────────────────────
import {
resolveComboModel,
getComboFallbacks,
} from "../../src/domain/comboResolver.js";
test("comboResolver: priority returns first model", () => {
const combo = {
name: "test-combo",
strategy: "priority",
models: ["gpt-4", "claude-3.5-sonnet", "gemini-pro"],
};
const result = resolveComboModel(combo);
assert.equal(result.model, "gpt-4");
assert.equal(result.index, 0);
});
test("comboResolver: random returns a valid model", () => {
const combo = {
name: "test-random",
strategy: "random",
models: ["a", "b", "c"],
};
const result = resolveComboModel(combo);
assert.ok(["a", "b", "c"].includes(result.model));
});
test("comboResolver: least-used picks model with lowest count", () => {
const combo = {
name: "test-least",
strategy: "least-used",
models: ["a", "b", "c"],
};
const result = resolveComboModel(combo, {
modelUsageCounts: { a: 10, b: 2, c: 5 },
});
assert.equal(result.model, "b");
});
test("comboResolver: throws on empty models", () => {
assert.throws(
() => resolveComboModel({ name: "empty", strategy: "priority", models: [] }),
/no models configured/
);
});
test("comboResolver: getComboFallbacks returns remaining models", () => {
const combo = { models: ["a", "b", "c", "d"] };
const fallbacks = getComboFallbacks(combo, 1); // primary = "b"
assert.deepEqual(fallbacks, ["c", "d", "a"]);
});
// ─── Lockout Policy (T-46) ──────────────────────
import {
checkLockout,
recordFailedAttempt,
recordSuccess,
forceUnlock,
} from "../../src/domain/lockoutPolicy.js";
test("lockoutPolicy: initially not locked", () => {
const result = checkLockout("user-fresh");
assert.equal(result.locked, false);
});
test("lockoutPolicy: locks after max attempts", () => {
const config = { maxAttempts: 3, lockoutDurationMs: 60000, attemptWindowMs: 60000 };
const id = "user-lock-test-" + Date.now();
recordFailedAttempt(id, config);
recordFailedAttempt(id, config);
const result = recordFailedAttempt(id, config);
assert.equal(result.locked, true);
assert.ok(result.remainingMs > 0);
});
test("lockoutPolicy: recordSuccess clears state", () => {
const id = "user-success-" + Date.now();
recordFailedAttempt(id);
recordSuccess(id);
const result = checkLockout(id);
assert.equal(result.locked, false);
assert.equal(result.attempts, 0);
});
test("lockoutPolicy: forceUnlock works", () => {
const config = { maxAttempts: 1, lockoutDurationMs: 60000, attemptWindowMs: 60000 };
const id = "user-force-" + Date.now();
recordFailedAttempt(id, config);
forceUnlock(id);
const result = checkLockout(id);
assert.equal(result.locked, false);
});