Skip to content

Commit 1a57eab

Browse files
authored
add unit tests for getLocalDevPath and findPluginEntry
test(auto-update-checker): add unit tests for getLocalDevPath and findPluginEntry
2 parents ae4ae82 + 598c500 commit 1a57eab

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2+
3+
// ─── Fixtures ─────────────────────────────────────────────────────────────────
4+
5+
const { fsMock } = vi.hoisted(() => ({
6+
fsMock: {
7+
existsSync: vi.fn(),
8+
readFileSync: vi.fn(),
9+
writeFileSync: vi.fn(),
10+
statSync: vi.fn(),
11+
},
12+
}));
13+
14+
vi.mock("node:fs", () => fsMock);
15+
16+
// ─── Tests ────────────────────────────────────────────────────────────────────
17+
18+
describe("isLocalDevMode / getLocalDevPath", () => {
19+
beforeEach(() => {
20+
vi.resetAllMocks();
21+
fsMock.existsSync.mockReturnValue(false);
22+
});
23+
24+
afterEach(() => {
25+
vi.restoreAllMocks();
26+
});
27+
28+
it("returns false when no config files exist", async () => {
29+
const { isLocalDevMode } = await import("./checker");
30+
expect(isLocalDevMode("/some/project")).toBe(false);
31+
});
32+
33+
it("returns null from getLocalDevPath when no config exists", async () => {
34+
const { getLocalDevPath } = await import("./checker");
35+
expect(getLocalDevPath("/some/project")).toBeNull();
36+
});
37+
38+
it("returns null when config has no matching file:// plugin entry", async () => {
39+
const { getLocalDevPath } = await import("./checker");
40+
fsMock.existsSync.mockImplementation((p: string) =>
41+
p.endsWith("opencode.json"),
42+
);
43+
fsMock.readFileSync.mockReturnValue(
44+
JSON.stringify({ plugin: ["some-other-plugin@1.0.0"] }),
45+
);
46+
expect(getLocalDevPath("/project")).toBeNull();
47+
});
48+
49+
it("returns path when config contains a file:// entry for the package", async () => {
50+
const { getLocalDevPath } = await import("./checker");
51+
fsMock.existsSync.mockImplementation((p: string) =>
52+
p.endsWith("opencode.json"),
53+
);
54+
fsMock.readFileSync.mockReturnValue(
55+
JSON.stringify({
56+
plugin: ["file:///home/user/opencode-antigravity-auth/dist/plugin.js"],
57+
}),
58+
);
59+
const result = getLocalDevPath("/project");
60+
expect(result).toContain("opencode-antigravity-auth");
61+
});
62+
63+
it("handles JSONC config with comments and trailing commas", async () => {
64+
const { getLocalDevPath } = await import("./checker");
65+
fsMock.existsSync.mockImplementation((p: string) =>
66+
p.endsWith("opencode.jsonc"),
67+
);
68+
fsMock.readFileSync.mockReturnValue(
69+
`{
70+
// dev plugin
71+
"plugin": [
72+
"file:///home/user/opencode-antigravity-auth/dist/plugin.js",
73+
]
74+
}`,
75+
);
76+
const result = getLocalDevPath("/project");
77+
expect(result).toContain("opencode-antigravity-auth");
78+
});
79+
80+
it("returns null and does not throw when config file is malformed JSON", async () => {
81+
const { getLocalDevPath } = await import("./checker");
82+
fsMock.existsSync.mockReturnValue(true);
83+
fsMock.readFileSync.mockReturnValue("{ not valid json !!!}");
84+
expect(() => getLocalDevPath("/project")).not.toThrow();
85+
expect(getLocalDevPath("/project")).toBeNull();
86+
});
87+
});
88+
89+
describe("findPluginEntry", () => {
90+
beforeEach(() => {
91+
vi.resetAllMocks();
92+
fsMock.existsSync.mockReturnValue(false);
93+
});
94+
95+
it("returns null when no config files exist", async () => {
96+
const { findPluginEntry } = await import("./checker");
97+
expect(findPluginEntry("/project")).toBeNull();
98+
});
99+
100+
it("returns entry with isPinned=false for bare package name", async () => {
101+
const { findPluginEntry } = await import("./checker");
102+
fsMock.existsSync.mockImplementation((p: string) => p.endsWith("opencode.json"));
103+
fsMock.readFileSync.mockReturnValue(
104+
JSON.stringify({ plugin: ["opencode-antigravity-auth"] }),
105+
);
106+
const result = findPluginEntry("/project");
107+
expect(result).not.toBeNull();
108+
expect(result!.isPinned).toBe(false);
109+
expect(result!.pinnedVersion).toBeNull();
110+
});
111+
112+
it("returns entry with isPinned=true for versioned package", async () => {
113+
const { findPluginEntry } = await import("./checker");
114+
fsMock.existsSync.mockImplementation((p: string) => p.endsWith("opencode.json"));
115+
fsMock.readFileSync.mockReturnValue(
116+
JSON.stringify({ plugin: ["opencode-antigravity-auth@1.5.0"] }),
117+
);
118+
const result = findPluginEntry("/project");
119+
expect(result).not.toBeNull();
120+
expect(result!.isPinned).toBe(true);
121+
expect(result!.pinnedVersion).toBe("1.5.0");
122+
});
123+
124+
it("returns isPinned=false for @latest entry", async () => {
125+
const { findPluginEntry } = await import("./checker");
126+
fsMock.existsSync.mockImplementation((p: string) => p.endsWith("opencode.json"));
127+
fsMock.readFileSync.mockReturnValue(
128+
JSON.stringify({ plugin: ["opencode-antigravity-auth@latest"] }),
129+
);
130+
const result = findPluginEntry("/project");
131+
expect(result!.isPinned).toBe(false);
132+
expect(result!.pinnedVersion).toBeNull();
133+
});
134+
});

0 commit comments

Comments
 (0)