import { describe, expect, it } from "vite-plus/test"; import { isPickedElementPayload, isPreviewAnnotationPayload } from "./PickedElementPayload.ts"; function validPayload(overrides?: Record<string, unknown>): Record<string, unknown> { return { pageUrl: "https://example.com/", pageTitle: "Example", tagName: "button", selector: "button.submit", htmlPreview: "<button>Save</button>", componentName: "SubmitButton", source: { functionName: "SubmitButton", fileName: "/repo/src/Button.tsx", lineNumber: 12, columnNumber: 5, }, stack: [ { functionName: "SubmitButton", fileName: "/repo/src/Button.tsx", lineNumber: 12, columnNumber: 5, }, ], styles: ".submit { color: white; }", pickedAt: "2026-05-03T18:00:00.000Z", ...overrides, };} describe("isPickedElementPayload", () => { it("accepts a complete, well-typed payload", () => { expect(isPickedElementPayload(validPayload())).toBe(true); }); it("accepts nullable string fields when null", () => { expect( isPickedElementPayload( validPayload({ pageTitle: null, selector: null, componentName: null, source: null }), ), ).toBe(true); }); it("accepts an empty stack array", () => { expect(isPickedElementPayload(validPayload({ stack: [] }))).toBe(true); }); it("accepts stack frames with null fields", () => { expect( isPickedElementPayload( validPayload({ stack: [ { functionName: null, fileName: null, lineNumber: null, columnNumber: null, }, ], }), ), ).toBe(true); }); it("rejects null and primitive inputs", () => { expect(isPickedElementPayload(null)).toBe(false); expect(isPickedElementPayload(undefined)).toBe(false); expect(isPickedElementPayload("string")).toBe(false); expect(isPickedElementPayload(42)).toBe(false); expect(isPickedElementPayload([])).toBe(false); }); it.each<[string, Record<string, unknown>]>([ ["missing pageUrl", validPayload({ pageUrl: undefined })], ["wrong-type pageUrl", validPayload({ pageUrl: 123 })], ["missing tagName", validPayload({ tagName: undefined })], ["missing htmlPreview", validPayload({ htmlPreview: undefined })], ["missing styles", validPayload({ styles: undefined })], ["missing pickedAt", validPayload({ pickedAt: undefined })], ["wrong-type pageTitle", validPayload({ pageTitle: 99 })], ["wrong-type selector", validPayload({ selector: 99 })], ["wrong-type componentName", validPayload({ componentName: 99 })], ])("rejects payloads with %s", (_label, value) => { expect(isPickedElementPayload(value)).toBe(false); }); it("rejects malformed source frames", () => { expect( isPickedElementPayload( validPayload({ source: { functionName: 0, fileName: null, lineNumber: null, columnNumber: null, }, }), ), ).toBe(false); }); it("rejects non-finite numeric line/column numbers", () => { expect( isPickedElementPayload( validPayload({ source: { functionName: null, fileName: null, lineNumber: Number.POSITIVE_INFINITY, columnNumber: null, }, }), ), ).toBe(false); expect( isPickedElementPayload( validPayload({ source: { functionName: null, fileName: null, lineNumber: Number.NaN, columnNumber: null, }, }), ), ).toBe(false); }); it("rejects malformed stack arrays", () => { expect(isPickedElementPayload(validPayload({ stack: "not-an-array" }))).toBe(false); expect(isPickedElementPayload(validPayload({ stack: [{ bogus: true }] }))).toBe(false); });}); function validAnnotation(overrides?: Record<string, unknown>): Record<string, unknown> { return { id: "annotation_1", pageUrl: "https://example.com/", pageTitle: "Example", comment: "Make this clearer", elements: [ { id: "element_1", element: validPayload(), rect: { x: 10, y: 20, width: 100, height: 40 }, }, ], regions: [{ id: "region_1", rect: { x: 5, y: 6, width: 20, height: 30 } }], strokes: [ { id: "stroke_1", color: "#7c3aed", width: 4, points: [ { x: 10, y: 10 }, { x: 20, y: 20 }, ], bounds: { x: 6, y: 6, width: 18, height: 18 }, }, ], styleChanges: [ { targetId: "element_1", selector: "button.submit", property: "opacity", previousValue: "1", value: "0.5", }, ], screenshot: null, createdAt: "2026-06-11T00:00:00.000Z", ...overrides, };} describe("isPreviewAnnotationPayload", () => { it("accepts a structured annotation draft before screenshot capture", () => { expect(isPreviewAnnotationPayload(validAnnotation())).toBe(true); }); it("rejects screenshots supplied by the guest preload", () => { expect(isPreviewAnnotationPayload(validAnnotation({ screenshot: { dataUrl: "bad" } }))).toBe( false, ); }); it("rejects malformed geometry and nested element payloads", () => { expect( isPreviewAnnotationPayload( validAnnotation({ regions: [{ id: "region_1", rect: { x: 0, y: 0, width: "wide" } }] }), ), ).toBe(false); expect( isPreviewAnnotationPayload( validAnnotation({ elements: [{ id: "element_1", element: {}, rect: {} }] }), ), ).toBe(false); });});
import { describe, expect, it } from "vite-plus/test";
import { isPickedElementPayload, isPreviewAnnotationPayload } from "./PickedElementPayload.ts";
function validPayload(overrides?: Record<string, unknown>): Record<string, unknown> {
return {
pageUrl: "https://example.com/",
pageTitle: "Example",
tagName: "button",
selector: "button.submit",
htmlPreview: "<button>Save</button>",
componentName: "SubmitButton",
source: {
functionName: "SubmitButton",
fileName: "/repo/src/Button.tsx",
lineNumber: 12,
columnNumber: 5,
},
stack: [
{
functionName: "SubmitButton",
fileName: "/repo/src/Button.tsx",
lineNumber: 12,
columnNumber: 5,
},
],
styles: ".submit { color: white; }",
pickedAt: "2026-05-03T18:00:00.000Z",
...overrides,
};
}
describe("isPickedElementPayload", () => {
it("accepts a complete, well-typed payload", () => {
expect(isPickedElementPayload(validPayload())).toBe(true);
});
it("accepts nullable string fields when null", () => {
expect(
isPickedElementPayload(
validPayload({ pageTitle: null, selector: null, componentName: null, source: null }),
),
).toBe(true);
});
it("accepts an empty stack array", () => {
expect(isPickedElementPayload(validPayload({ stack: [] }))).toBe(true);
});
it("accepts stack frames with null fields", () => {
expect(
isPickedElementPayload(
validPayload({
stack: [
{
functionName: null,
fileName: null,
lineNumber: null,
columnNumber: null,
},
],
}),
),
).toBe(true);
});
it("rejects null and primitive inputs", () => {
expect(isPickedElementPayload(null)).toBe(false);
expect(isPickedElementPayload(undefined)).toBe(false);
expect(isPickedElementPayload("string")).toBe(false);
expect(isPickedElementPayload(42)).toBe(false);
expect(isPickedElementPayload([])).toBe(false);
});
it.each<[string, Record<string, unknown>]>([
["missing pageUrl", validPayload({ pageUrl: undefined })],
["wrong-type pageUrl", validPayload({ pageUrl: 123 })],
["missing tagName", validPayload({ tagName: undefined })],
["missing htmlPreview", validPayload({ htmlPreview: undefined })],
["missing styles", validPayload({ styles: undefined })],
["missing pickedAt", validPayload({ pickedAt: undefined })],
["wrong-type pageTitle", validPayload({ pageTitle: 99 })],
["wrong-type selector", validPayload({ selector: 99 })],
["wrong-type componentName", validPayload({ componentName: 99 })],
])("rejects payloads with %s", (_label, value) => {
expect(isPickedElementPayload(value)).toBe(false);
});
it("rejects malformed source frames", () => {
expect(
isPickedElementPayload(
validPayload({
source: {
functionName: 0,
fileName: null,
lineNumber: null,
columnNumber: null,
},
}),
),
).toBe(false);
});
it("rejects non-finite numeric line/column numbers", () => {
expect(
isPickedElementPayload(
validPayload({
source: {
functionName: null,
fileName: null,
lineNumber: Number.POSITIVE_INFINITY,
columnNumber: null,
},
}),
),
).toBe(false);
expect(
isPickedElementPayload(
validPayload({
source: {
functionName: null,
fileName: null,
lineNumber: Number.NaN,
columnNumber: null,
},
}),
),
).toBe(false);
});
it("rejects malformed stack arrays", () => {
expect(isPickedElementPayload(validPayload({ stack: "not-an-array" }))).toBe(false);
expect(isPickedElementPayload(validPayload({ stack: [{ bogus: true }] }))).toBe(false);
});
});
function validAnnotation(overrides?: Record<string, unknown>): Record<string, unknown> {
return {
id: "annotation_1",
pageUrl: "https://example.com/",
pageTitle: "Example",
comment: "Make this clearer",
elements: [
{
id: "element_1",
element: validPayload(),
rect: { x: 10, y: 20, width: 100, height: 40 },
},
],
regions: [{ id: "region_1", rect: { x: 5, y: 6, width: 20, height: 30 } }],
strokes: [
{
id: "stroke_1",
color: "#7c3aed",
width: 4,
points: [
{ x: 10, y: 10 },
{ x: 20, y: 20 },
],
bounds: { x: 6, y: 6, width: 18, height: 18 },
},
],
styleChanges: [
{
targetId: "element_1",
selector: "button.submit",
property: "opacity",
previousValue: "1",
value: "0.5",
},
],
screenshot: null,
createdAt: "2026-06-11T00:00:00.000Z",
...overrides,
};
}
describe("isPreviewAnnotationPayload", () => {
it("accepts a structured annotation draft before screenshot capture", () => {
expect(isPreviewAnnotationPayload(validAnnotation())).toBe(true);
});
it("rejects screenshots supplied by the guest preload", () => {
expect(isPreviewAnnotationPayload(validAnnotation({ screenshot: { dataUrl: "bad" } }))).toBe(
false,
);
});
it("rejects malformed geometry and nested element payloads", () => {
expect(
isPreviewAnnotationPayload(
validAnnotation({ regions: [{ id: "region_1", rect: { x: 0, y: 0, width: "wide" } }] }),
),
).toBe(false);
expect(
isPreviewAnnotationPayload(
validAnnotation({ elements: [{ id: "element_1", element: {}, rect: {} }] }),
),
).toBe(false);
});
});