|
|
import { describe, expect, it } from "vitest";
|
|
|
import { RpaError } from "@/modules/rpa/errors";
|
|
|
import { RPAContext, resolveRPAContext } from "@/workers/rpa/kernel/context";
|
|
|
import {
|
|
|
assertRPAContext,
|
|
|
ensureArray,
|
|
|
isRPAContext,
|
|
|
snapshotContextContract,
|
|
|
} from "@/workers/rpa/kernel/context-validator";
|
|
|
|
|
|
function mockPage(): object {
|
|
|
return {
|
|
|
locator: () => ({
|
|
|
filter: () => ({ nth: () => ({}) }),
|
|
|
first: () => ({}),
|
|
|
}),
|
|
|
waitForTimeout: async () => undefined,
|
|
|
url: () => "https://example.com",
|
|
|
};
|
|
|
}
|
|
|
|
|
|
describe("context-validator", () => {
|
|
|
it("ensureArray:undefined → []", () => {
|
|
|
expect(ensureArray(undefined)).toEqual([]);
|
|
|
expect(ensureArray(null)).toEqual([]);
|
|
|
expect(ensureArray([1])).toEqual([1]);
|
|
|
});
|
|
|
|
|
|
it("resolveRPAContext:已是 context 时不再包一层", () => {
|
|
|
const page = mockPage();
|
|
|
const ctx = new RPAContext(page as never);
|
|
|
const resolved = resolveRPAContext(ctx);
|
|
|
expect(resolved).toBe(ctx);
|
|
|
expect(isRPAContext(resolved)).toBe(true);
|
|
|
});
|
|
|
|
|
|
it("fromSession 误传 context 不再导致 page.locator 断裂", () => {
|
|
|
const page = mockPage();
|
|
|
const ctx = new RPAContext(page as never);
|
|
|
const wrapped = RPAContext.fromSession(ctx);
|
|
|
expect(wrapped).toBe(ctx);
|
|
|
expect(snapshotContextContract(wrapped).hasPage).toBe(true);
|
|
|
});
|
|
|
|
|
|
it("assertRPAContext:缺 state 时 fail-fast", () => {
|
|
|
const page = mockPage();
|
|
|
const broken = {
|
|
|
page,
|
|
|
selectors: {},
|
|
|
exec: {},
|
|
|
runtime: {},
|
|
|
getWidgetScrollAt: () => 0,
|
|
|
setWidgetScrollAt: () => undefined,
|
|
|
};
|
|
|
expect(() => assertRPAContext(broken)).toThrow(RpaError);
|
|
|
});
|
|
|
});
|