1import { Schema } from "effect";
2import { describe, expect, it } from "vite-plus/test";
3
4import { EnvironmentId, ThreadId } from "./baseSchemas.ts";
5import {
6 PreviewAutomationHost,
7 PreviewAutomationInvalidSelectorError,
8 PreviewAutomationStatus,
9} from "./previewAutomation.ts";
10import { ProviderInstanceId } from "./providerInstance.ts";
11
12const decodeAutomationHost = Schema.decodeUnknownSync(PreviewAutomationHost);
13const decodeAutomationStatus = Schema.decodeUnknownSync(PreviewAutomationStatus);
14
15describe("PreviewAutomationHost", () => {
16 it("accepts legacy hosts and current operation advertisements", () => {
17 expect(decodeAutomationHost({ clientId: "legacy", environmentId: "environment-1" })).toEqual({
18 clientId: "legacy",
19 environmentId: "environment-1",
20 });
21 expect(
22 decodeAutomationHost({
23 clientId: "current",
24 environmentId: "environment-1",
25 supportedOperations: ["status", "resize"],
26 }).supportedOperations,
27 ).toEqual(["status", "resize"]);
28 });
29});
30
31describe("PreviewAutomationStatus", () => {
32 it("accepts old hosts without viewport data and exposes it from current hosts", () => {
33 const base = {
34 available: true,
35 visible: false,
36 tabId: "preview-t",
37 url: "https://example.com",
38 title: "Example",
39 loading: false,
40 };
41 expect(decodeAutomationStatus(base)).toEqual(base);
42 expect(
43 decodeAutomationStatus({
44 ...base,
45 viewportSetting: { _tag: "preset", presetId: "pixel-8", width: 412, height: 915 },
46 viewport: { width: 412, height: 915 },
47 }).viewport,
48 ).toEqual({ width: 412, height: 915 });
49 });
50});
51
52describe("PreviewAutomationInvalidSelectorError", () => {
53 const invalidSelector = (selectorKind: "locator" | "selector") =>
54 new PreviewAutomationInvalidSelectorError({
55 operation: "click",
56 environmentId: EnvironmentId.make("environment-1"),
57 threadId: ThreadId.make("thread-1"),
58 providerSessionId: "session-1",
59 providerInstanceId: ProviderInstanceId.make("claude"),
60 clientId: "desktop",
61 connectionId: "connection-1",
62 requestId: "request-1",
63 timeoutMs: 15_000,
64 remoteTag: "Error",
65 remoteMessageLength: 0,
66 cause: null,
67 selectorKind,
68 selectorLength: 42,
69 });
70
71 it("tells agents which locator forms are accepted and where CSS goes", () => {
72 const { message } = invalidSelector("locator");
73 expect(message).toContain("aria-ref=");
74 expect(message).toMatch(/role/);
75 expect(message).toMatch(/text/);
76 expect(message).toMatch(/CSS[^.]*\bselector\b/);
77 });
78
79 it("points an invalid CSS selector at the locator alternative", () => {
80 const { message } = invalidSelector("selector");
81 expect(message).toMatch(/CSS/);
82 expect(message).toMatch(/\blocator\b/);
83 expect(message).toContain("aria-ref=");
84 });
85});