import { Schema } from "effect"; import { describe, expect, it } from "vite-plus/test"; import { DiscoveredLocalServer, PreviewEvent, PreviewNavStatus, PreviewSessionSnapshot, } from "./preview.ts"; const decodePreviewEvent = Schema.decodeUnknownSync(PreviewEvent); const decodeSnapshot = Schema.decodeUnknownSync(PreviewSessionSnapshot); const decodeNavStatus = Schema.decodeUnknownSync(PreviewNavStatus); const decodeServer = Schema.decodeUnknownSync(DiscoveredLocalServer); describe("PreviewNavStatus", () => { it("decodes Idle", () => { expect(decodeNavStatus({ _tag: "Idle" })).toEqual({ _tag: "Idle" }); }); it("decodes Loading with title", () => { expect(decodeNavStatus({ _tag: "Loading", url: "http://localhost:5173/", title: "" })).toEqual({ _tag: "Loading", url: "http://localhost:5173/", title: "", }); }); it("decodes LoadFailed with code/description", () => { expect( decodeNavStatus({ _tag: "LoadFailed", url: "https://example.com/", title: "Example", code: -105, description: "ERR_NAME_NOT_RESOLVED", }), ).toEqual({ _tag: "LoadFailed", url: "https://example.com/", title: "Example", code: -105, description: "ERR_NAME_NOT_RESOLVED", }); }); it("rejects empty url", () => { expect(() => decodeNavStatus({ _tag: "Loading", url: "", title: "" })).toThrow(); }); }); describe("PreviewSessionSnapshot", () => { it("round-trips a Success snapshot", () => { const snapshot = decodeSnapshot({ threadId: "thread-1", tabId: "preview-thread-1", navStatus: { _tag: "Success", url: "http://localhost:5173/", title: "Vite App", }, canGoBack: false, canGoForward: false, updatedAt: "2026-01-01T00:00:00.000Z", }); expect(snapshot.tabId).toBe("preview-thread-1"); expect(snapshot.navStatus._tag).toBe("Success"); }); }); describe("PreviewEvent", () => { it("decodes opened", () => { const event = decodePreviewEvent({ type: "opened", threadId: "t", tabId: "preview-t", createdAt: "2026-01-01T00:00:00.000Z", snapshot: { threadId: "t", tabId: "preview-t", navStatus: { _tag: "Idle" }, canGoBack: false, canGoForward: false, updatedAt: "2026-01-01T00:00:00.000Z", }, }); expect(event.type).toBe("opened"); }); it("decodes failed with code/description", () => { const event = decodePreviewEvent({ type: "failed", threadId: "t", tabId: "preview-t", createdAt: "2026-01-01T00:00:00.000Z", url: "https://example.com/", title: "", code: -105, description: "ERR_NAME_NOT_RESOLVED", }); expect(event.type).toBe("failed"); if (event.type === "failed") { expect(event.code).toBe(-105); } }); it("decodes closed without snapshot", () => { const event = decodePreviewEvent({ type: "closed", threadId: "t", tabId: "preview-t", createdAt: "2026-01-01T00:00:00.000Z", }); expect(event.type).toBe("closed"); }); }); describe("DiscoveredLocalServer", () => { it("decodes a server with process metadata", () => { const server = decodeServer({ host: "localhost", port: 5173, url: "http://localhost:5173", processName: "node", pid: 12345, terminal: null, }); expect(server.port).toBe(5173); expect(server.processName).toBe("node"); }); it("decodes a server without process metadata", () => { const server = decodeServer({ host: "localhost", port: 3000, url: "http://localhost:3000", processName: null, pid: null, terminal: null, }); expect(server.processName).toBeNull(); }); it("rejects invalid ports", () => { expect(() => decodeServer({ host: "localhost", port: 0, url: "http://localhost:0", processName: null, pid: null, terminal: null, }), ).toThrow(); expect(() => decodeServer({ host: "localhost", port: 70000, url: "http://localhost:70000", processName: null, pid: null, terminal: null, }), ).toThrow(); }); });