Files
smart-org/apps/web/src/test/engine-labels.test.ts
T
mjalmoudy94 d532929189 feat(integration): prepaid billing, engine UI, credits console, direct tasks, v2 final
- Prepaid credit system: org wallet, debit on usage, chat gate, admin credit console
- Engine UI: /manager, /tasks, /tasks/[id], /workforce, /dashboard, /traces pages
- Direct task creation (HTTP POST /tasks, MCP tasks_create) at pending_manager_review
- Pause/resume/cancel/answer actions in engine API and UI
- Employee cap (7 per org default), review pipeline guard (active reviewer required)
- Scheduler: wide window prevents org starvation; archived employees excluded from cap
- Tenant isolation: project-id cross-org 404, engine never uses another tenant's sandbox
- Order route fix: manager built with pipeline states + employee profiles
- Contract extension: ModelGrantPort.get_org_policy with DefaultOrgPolicy
- Engine event types in @agy/contracts (task.step, task.gate, run.log, run.tool, team.changed)
- api-engine.ts typed client; api-credit.ts client
- Alembic migration c4d5e6f7a8b9: prepaid credit + engine UI tables
- 859 tests passed, 1 skipped; ruff/mypy/tsc/eslint/vitest all green

Refs: PLAN-v2.md §9 (T1–T43), todo-v2-final.md
2026-10-14 23:19:05 +03:30

112 lines
3.8 KiB
TypeScript

/**
* The engine's labels and board columns: every stage lands in exactly one column, a legacy
* task lands by its status, and grouping keeps the order the tasks came in.
*/
import { describe, expect, it } from "vitest";
import {
BOARD_COLUMNS,
columnFor,
groupByColumn,
ROLE_LABELS,
STAGE_LABELS,
stageTone,
TIER_LABELS,
} from "@/lib/engine-labels";
const STAGES = [
"pending_manager_review",
"pending_analysis",
"pending_implementation",
"pending_review",
"pending_test",
"pending_final_review",
"merge_request",
"completed",
"pending_user_decision",
"error_review",
"paused",
"cancelled",
"failed",
];
describe("the board", () => {
it("places every one of the thirteen stages in exactly one column", () => {
for (const stage of STAGES) {
const homes = BOARD_COLUMNS.filter((column) => column.stages.includes(stage as never));
expect(homes, stage).toHaveLength(1);
expect(STAGE_LABELS[stage], stage).toBeTruthy();
}
const placed = BOARD_COLUMNS.flatMap((column) => column.stages as readonly string[]);
expect([...placed].sort()).toEqual([...STAGES].sort());
});
it("uses the stage column whenever the engine owns the task", () => {
expect(columnFor("pending_test", "running")).toBe("test");
expect(columnFor("pending_final_review", "running")).toBe("review");
expect(columnFor("paused", "waiting_approval")).toBe("decision");
expect(columnFor("completed", "done")).toBe("done");
});
it("places a legacy task by its coarse status", () => {
expect(columnFor(null, "new")).toBe("manager_review");
expect(columnFor(null, "triaged")).toBe("implementation");
expect(columnFor(null, "running")).toBe("implementation");
expect(columnFor(null, "waiting_approval")).toBe("decision");
for (const status of ["done", "failed", "cancelled"]) {
expect(columnFor(null, status)).toBe("done");
}
});
it("sends an unknown stage or status to the decision column", () => {
expect(columnFor("some_new_stage", "running")).toBe("decision");
expect(columnFor(null, "some_new_status")).toBe("decision");
});
it("groups tasks by column, keeps every column, and keeps the order inside each", () => {
const tasks = [
{ id: "a", stage: "pending_test", status: "running" },
{ id: "b", stage: null, status: "new" },
{ id: "c", stage: "pending_test", status: "running" },
{ id: "d", stage: "pending_final_review", status: "running" },
];
const groups = groupByColumn(tasks);
expect(groups.test.map((task) => task.id)).toEqual(["a", "c"]);
expect(groups.review.map((task) => task.id)).toEqual(["d"]);
expect(groups.manager_review.map((task) => task.id)).toEqual(["b"]);
expect(groups.merge).toEqual([]);
expect(Object.keys(groups)).toHaveLength(BOARD_COLUMNS.length);
});
});
describe("labels and tones", () => {
it("tones a stage by how it ended or whether a person must act", () => {
expect(stageTone("completed")).toBe("success");
expect(stageTone("failed")).toBe("danger");
expect(stageTone("cancelled")).toBe("danger");
expect(stageTone("paused")).toBe("warning");
expect(stageTone("pending_user_decision")).toBe("warning");
expect(stageTone("error_review")).toBe("warning");
expect(stageTone("pending_test")).toBe("info");
});
it("labels the four tiers in Persian", () => {
expect(TIER_LABELS).toEqual({
fast: "سریع",
balanced: "متعادل",
strong: "قوی",
unknown: "نامشخص",
});
});
it("labels the five hirable roles in Persian", () => {
expect(Object.keys(ROLE_LABELS).sort()).toEqual(
["developer", "manager", "planner", "reviewer", "tester"].sort(),
);
expect(ROLE_LABELS.manager).toBe("مدیر");
expect(ROLE_LABELS.reviewer).toBe("بازبین");
expect(ROLE_LABELS.tester).toBe("آزمونگر");
});
});