1import * as Schema from "effect/Schema";
2import { describe, expect, it } from "vite-plus/test";
3
4import { T3ProjectFile, type T3ProjectFile as T3ProjectFileType } from "./t3ProjectFile.ts";
5
6const decode = Schema.decodeUnknownSync(T3ProjectFile as never) as (
7 input: unknown,
8) => T3ProjectFileType;
9
10describe("T3ProjectFile", () => {
11 it("decodes a full project file", () => {
12 const decoded = decode({
13 $schema: "https://t3.codes/schema/t3.json",
14 iconPath: "assets/logo.svg",
15 scripts: [
16 {
17 name: "Dev",
18 command: "pnpm dev",
19 icon: "play",
20 runOnWorktreeCreate: false,
21 previewUrl: "http://localhost:3000",
22 autoOpenPreview: true,
23 },
24 { name: "Test", command: "pnpm test" },
25 { name: "Setup", command: "pnpm i", runOnWorktreeCreate: true, async: false },
26 ],
27 });
28
29 expect(decoded.iconPath).toBe("assets/logo.svg");
30 expect(decoded.scripts).toHaveLength(3);
31 expect(decoded.scripts?.[1]).toEqual({ name: "Test", command: "pnpm test" });
32 expect(decoded.scripts?.[2]?.async).toBe(false);
33 });
34
35 it("decodes an empty object and ignores unknown fields", () => {
36 expect(decode({})).toEqual({});
37 expect(decode({ futureField: true })).toEqual({});
38 });
39
40 it("trims icon paths and script fields", () => {
41 const decoded = decode({
42 iconPath: " assets/logo.svg ",
43 scripts: [{ name: " Dev ", command: " pnpm dev " }],
44 });
45
46 expect(decoded.iconPath).toBe("assets/logo.svg");
47 expect(decoded.scripts?.[0]).toEqual({ name: "Dev", command: "pnpm dev" });
48 });
49
50 it("rejects scripts without a command", () => {
51 expect(() => decode({ scripts: [{ name: "Dev" }] })).toThrow();
52 });
53
54 it("rejects unknown script icons", () => {
55 expect(() =>
56 decode({ scripts: [{ name: "Dev", command: "pnpm dev", icon: "rocket" }] }),
57 ).toThrow();
58 });
59
60 it("decodes defaultThreadEnvMode and rejects unknown modes", () => {
61 expect(decode({ defaultThreadEnvMode: "worktree" }).defaultThreadEnvMode).toBe("worktree");
62 expect(decode({ defaultThreadEnvMode: "local" }).defaultThreadEnvMode).toBe("local");
63 expect(() => decode({ defaultThreadEnvMode: "remote" })).toThrow();
64 });
65
66 it("decodes worktreeSubmodules and rejects unknown modes", () => {
67 expect(decode({ worktreeSubmodules: "none" }).worktreeSubmodules).toBe("none");
68 expect(decode({ worktreeSubmodules: "top-level" }).worktreeSubmodules).toBe("top-level");
69 expect(() => decode({ worktreeSubmodules: "shallow" })).toThrow();
70 });
71});