639b0b7f59
Add native IK-style capture processing, Artifact Inventory, explicit promotion and single-result review. Confirm the three live OCR corrections in the eval corpus and preserve extraction/value separation.
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
automationBlockReason,
|
|
buildInventoryPagePlan,
|
|
buildGridModel,
|
|
requiresAdminForAutomation,
|
|
} from "./automationPlanner";
|
|
|
|
describe("automationPlanner", () => {
|
|
it("requires admin whenever this app's own process is not elevated", () => {
|
|
expect(requiresAdminForAutomation({ ok: true, isElevated: false, platform: "win32" })).toBe(true);
|
|
expect(requiresAdminForAutomation({ ok: true, isElevated: true, platform: "win32" })).toBe(false);
|
|
expect(requiresAdminForAutomation({ ok: false, isElevated: false, platform: "win32" })).toBe(false);
|
|
expect(requiresAdminForAutomation(null)).toBe(false);
|
|
});
|
|
|
|
it("returns a user-facing admin block reason when not elevated", () => {
|
|
expect(automationBlockReason({ ok: true, isElevated: false, platform: "win32" })).toContain("Administrator");
|
|
expect(automationBlockReason({ ok: true, isElevated: true, platform: "win32" })).toBe("");
|
|
});
|
|
|
|
it("builds a dense click grid from partial detected centers", () => {
|
|
const grid = buildGridModel({
|
|
rows: 3,
|
|
cols: 4,
|
|
confidence: 96,
|
|
source: "detected",
|
|
centers: [
|
|
{ row: 0, col: 0, x: 100, y: 200 },
|
|
{ row: 0, col: 1, x: 220, y: 200 },
|
|
{ row: 0, col: 3, x: 460, y: 200 },
|
|
{ row: 2, col: 0, x: 100, y: 500 },
|
|
{ row: 2, col: 3, x: 460, y: 500 },
|
|
],
|
|
});
|
|
|
|
expect(grid).not.toBeNull();
|
|
expect(grid?.targets).toHaveLength(12);
|
|
expect(grid?.stepX).toBe(120);
|
|
expect(grid?.stepY).toBe(150);
|
|
expect(grid?.targets.find((target) => target.row === 1 && target.col === 2)).toMatchObject({ x: 340, y: 350 });
|
|
});
|
|
|
|
it("plans overlapping inventory pages for a partial final page", () => {
|
|
const targets = Array.from({ length: 32 }, (_, index) => ({
|
|
row: Math.floor(index / 8),
|
|
col: index % 8,
|
|
x: index * 10,
|
|
y: index * 10,
|
|
}));
|
|
|
|
const firstPage = buildInventoryPagePlan({
|
|
targets,
|
|
cols: 8,
|
|
rows: 4,
|
|
totalTargetCount: 45,
|
|
processedTargets: 0,
|
|
rowsQueued: 0,
|
|
});
|
|
expect(firstPage.pageTargets).toHaveLength(32);
|
|
expect(firstPage.startIndex).toBe(0);
|
|
expect(firstPage.scrollRowsAfterPage).toBe(2);
|
|
|
|
const finalPage = buildInventoryPagePlan({
|
|
targets,
|
|
cols: 8,
|
|
rows: 4,
|
|
totalTargetCount: 45,
|
|
processedTargets: 32,
|
|
rowsQueued: 4,
|
|
});
|
|
expect(finalPage.pageTargets).toHaveLength(13);
|
|
expect(finalPage.startIndex).toBe(16);
|
|
expect(finalPage.pageTargets[0]).toMatchObject({ row: 2, col: 0 });
|
|
expect(finalPage.scrollRowsAfterPage).toBe(0);
|
|
});
|
|
|
|
it("keeps the first page top-aligned when the whole inventory fits inside one visible page", () => {
|
|
const targets = Array.from({ length: 32 }, (_, index) => ({
|
|
row: Math.floor(index / 8),
|
|
col: index % 8,
|
|
x: index * 10,
|
|
y: index * 10,
|
|
}));
|
|
|
|
const singlePage = buildInventoryPagePlan({
|
|
targets,
|
|
cols: 8,
|
|
rows: 4,
|
|
totalTargetCount: 16,
|
|
processedTargets: 0,
|
|
rowsQueued: 0,
|
|
});
|
|
|
|
expect(singlePage.pageTargets).toHaveLength(16);
|
|
expect(singlePage.startIndex).toBe(0);
|
|
expect(singlePage.pageTargets[0]).toMatchObject({ row: 0, col: 0 });
|
|
expect(singlePage.pageTargets[15]).toMatchObject({ row: 1, col: 7 });
|
|
expect(singlePage.scrollRowsAfterPage).toBe(0);
|
|
});
|
|
});
|