mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
Minor bug fix
This commit is contained in:
+33
-1
@@ -48,6 +48,12 @@ const mocks = vi.hoisted(() => ({
|
||||
meter: vi.fn(),
|
||||
}));
|
||||
|
||||
// The second (file-producing) policy's timing, flippable per test to prove classification's local
|
||||
// pass is independent of when the rewriter runs.
|
||||
const securityRunOn = vi.hoisted(() => ({
|
||||
value: "upload" as "upload" | "export",
|
||||
}));
|
||||
|
||||
vi.mock("@app/hooks/useAiEngineEnabled", () => ({
|
||||
useAiEngineEnabled: () => true,
|
||||
}));
|
||||
@@ -86,7 +92,7 @@ vi.mock("@app/hooks/usePolicies", () => ({
|
||||
runsOnEditor: true,
|
||||
status: "active",
|
||||
backendId: "backend-security",
|
||||
runOn: "upload",
|
||||
runOn: securityRunOn.value,
|
||||
order: 1,
|
||||
outputMode: "new_version",
|
||||
outputName: "",
|
||||
@@ -176,6 +182,7 @@ beforeEach(() => {
|
||||
mocks.backendOutCounter = 0;
|
||||
mocks.dispatchInFlight = 0;
|
||||
mocks.maxDispatchInFlight = 0;
|
||||
securityRunOn.value = "upload";
|
||||
|
||||
mocks.workspace = Array.from({ length: FILE_COUNT }, (_, i) => ({
|
||||
id: `file-${i}`,
|
||||
@@ -356,4 +363,29 @@ describe("policy auto-run — 61-file batch through a Security → Classificatio
|
||||
expect(mocks.consumeSilentCalls).toBe(0);
|
||||
expect(mocks.persistCalls).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("classifies uploads even when the other editor policy runs on export, not upload", async () => {
|
||||
// Repro: with a file-producing policy set to export, the auto-run engine dispatches nothing on
|
||||
// upload - but classification's local pass is independent and must still run on every upload.
|
||||
securityRunOn.value = "export";
|
||||
|
||||
renderHook(() => Harness());
|
||||
await act(async () => {
|
||||
await vi.waitFor(
|
||||
() => {
|
||||
const classification = latestRuns.filter(
|
||||
(r) => r.categoryId === "classification" && r.imported,
|
||||
);
|
||||
expect(classification).toHaveLength(FILE_COUNT);
|
||||
},
|
||||
{ timeout: 8000, interval: 20 },
|
||||
);
|
||||
});
|
||||
|
||||
// The export policy did not run on upload; nothing versioned in place.
|
||||
expect(latestRuns.filter((r) => r.categoryId === "security")).toHaveLength(
|
||||
0,
|
||||
);
|
||||
expect(mocks.consumeSilentCalls).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,6 +60,43 @@ describe("policyStorage", () => {
|
||||
expect(p.routing.configured).toBe(false);
|
||||
});
|
||||
|
||||
it("migrates a pre-runsOnEditor row narrowed to non-editor sources off the editor", () => {
|
||||
// Stored before runsOnEditor existed: no such field, sources exclude the editor.
|
||||
localStorage.setItem(
|
||||
"stirling-policies-state",
|
||||
JSON.stringify({
|
||||
security: { configured: true, status: "active", sources: ["s3"] },
|
||||
}),
|
||||
);
|
||||
// Without the migration the default (true) would wrongly win.
|
||||
expect(loadPolicies().security.runsOnEditor).toBe(false);
|
||||
});
|
||||
|
||||
it("migrates a pre-runsOnEditor row listing the editor onto the editor", () => {
|
||||
localStorage.setItem(
|
||||
"stirling-policies-state",
|
||||
JSON.stringify({
|
||||
security: { configured: true, status: "active", sources: ["editor"] },
|
||||
}),
|
||||
);
|
||||
expect(loadPolicies().security.runsOnEditor).toBe(true);
|
||||
});
|
||||
|
||||
it("leaves an explicit runsOnEditor untouched", () => {
|
||||
localStorage.setItem(
|
||||
"stirling-policies-state",
|
||||
JSON.stringify({
|
||||
security: {
|
||||
configured: true,
|
||||
status: "active",
|
||||
sources: ["editor"],
|
||||
runsOnEditor: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(loadPolicies().security.runsOnEditor).toBe(false);
|
||||
});
|
||||
|
||||
it("fires a change event on update", () => {
|
||||
const cb = vi.fn();
|
||||
const off = onPoliciesChange(cb);
|
||||
|
||||
@@ -55,7 +55,14 @@ export function loadPolicies(): PoliciesByCategory {
|
||||
// category gets a default rather than being undefined.
|
||||
const out: PoliciesByCategory = {};
|
||||
loadPolicyCatalog().categories.forEach((cat, index) => {
|
||||
const merged = { ...defaultState(cat.id), ...(parsed[cat.id] ?? {}) };
|
||||
const stored = parsed[cat.id];
|
||||
const merged = { ...defaultState(cat.id), ...(stored ?? {}) };
|
||||
// Migration: a row stored before runsOnEditor existed has no such field, so the default (true)
|
||||
// would put a tile narrowed to non-editor sources on the editor until the first reconcile lands.
|
||||
// Derive it from the legacy signal (the editor in its sources), mirroring the decode rule.
|
||||
if (stored && stored.runsOnEditor === undefined) {
|
||||
merged.runsOnEditor = (stored.sources ?? []).includes("editor");
|
||||
}
|
||||
// Migration: clear the obsolete persisted reviewer email so it re-defaults
|
||||
// to the real signed-in user.
|
||||
if (merged.reviewerEmail === STALE_REVIEWER_EMAIL)
|
||||
|
||||
Reference in New Issue
Block a user