Skip to content

Commit d8f0bce

Browse files
committed
test: add tests to paths.js in electron and filters logic in testing-view
1 parent a0a2c1b commit d8f0bce

14 files changed

Lines changed: 880 additions & 0 deletions
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import path from "path";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
3+
import { ELECTRON_APP_ROOT } from "./helpers.js";
4+
5+
vi.mock("electron", () => ({
6+
app: {
7+
isPackaged: false,
8+
getAppPath: vi.fn().mockReturnValue("/mock/packaged/app"),
9+
getPath: vi.fn().mockReturnValue("/mock/userData"),
10+
},
11+
}));
12+
13+
const { app } = await import("electron");
14+
const { getAppPath } = await import("../paths.js");
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
app.isPackaged = false;
19+
});
20+
21+
describe("getAppPath", () => {
22+
it("dev: returns the electron-app root (2 levels up from src/utils)", () => {
23+
expect(path.normalize(getAppPath())).toBe(
24+
path.normalize(ELECTRON_APP_ROOT),
25+
);
26+
});
27+
28+
it("prod: returns app.getAppPath()", () => {
29+
app.isPackaged = true;
30+
app.getAppPath.mockReturnValue("/prod/app");
31+
32+
expect(getAppPath()).toBe("/prod/app");
33+
});
34+
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import path from "path";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
3+
import { ELECTRON_APP_ROOT, mockArch, mockPlatform } from "./helpers.js";
4+
5+
vi.mock("electron", () => ({
6+
app: {
7+
isPackaged: false,
8+
getAppPath: vi.fn().mockReturnValue("/mock/packaged/app"),
9+
getPath: vi.fn().mockReturnValue("/mock/userData"),
10+
},
11+
}));
12+
13+
const { app } = await import("electron");
14+
const { getBinaryPath } = await import("../paths.js");
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
app.isPackaged = false;
19+
mockPlatform("linux");
20+
mockArch("x64");
21+
process.resourcesPath = "/mock/resources";
22+
});
23+
24+
describe("getBinaryPath", () => {
25+
it("dev win32/x64: appends .exe and maps to windows-amd64", () => {
26+
mockPlatform("win32");
27+
mockArch("x64");
28+
29+
expect(getBinaryPath("backend")).toBe(
30+
path.join(ELECTRON_APP_ROOT, "binaries", "backend-windows-amd64.exe"),
31+
);
32+
});
33+
34+
it("dev darwin/arm64: no .exe extension, maps to darwin-arm64", () => {
35+
mockPlatform("darwin");
36+
mockArch("arm64");
37+
38+
expect(getBinaryPath("backend")).toBe(
39+
path.join(ELECTRON_APP_ROOT, "binaries", "backend-darwin-arm64"),
40+
);
41+
});
42+
43+
it("dev linux/x64: no .exe extension, maps to linux-amd64", () => {
44+
expect(getBinaryPath("backend")).toBe(
45+
path.join(ELECTRON_APP_ROOT, "binaries", "backend-linux-amd64"),
46+
);
47+
});
48+
49+
it("prod: uses process.resourcesPath instead of app root", () => {
50+
app.isPackaged = true;
51+
52+
expect(getBinaryPath("backend")).toBe(
53+
path.join("/mock/resources", "binaries", "backend-linux-amd64"),
54+
);
55+
});
56+
57+
it("unknown platform: falls back to raw platform name", () => {
58+
mockPlatform("freebsd");
59+
60+
expect(getBinaryPath("backend")).toContain("backend-freebsd-");
61+
});
62+
63+
it("unknown arch: falls back to raw arch name", () => {
64+
mockArch("mips");
65+
66+
expect(getBinaryPath("backend")).toContain("-mips");
67+
});
68+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import path from "path";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
3+
import { ELECTRON_APP_ROOT } from "./helpers.js";
4+
5+
vi.mock("electron", () => ({
6+
app: {
7+
isPackaged: false,
8+
getAppPath: vi.fn().mockReturnValue("/mock/packaged/app"),
9+
getPath: vi.fn().mockReturnValue("/mock/userData"),
10+
},
11+
}));
12+
13+
const { app } = await import("electron");
14+
const { getTemplatePath } = await import("../paths.js");
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
app.isPackaged = false;
19+
process.resourcesPath = "/mock/resources";
20+
});
21+
22+
describe("getTemplatePath", () => {
23+
it("dev: returns dev-config.toml in backend/cmd/", () => {
24+
expect(getTemplatePath()).toBe(
25+
path.join(ELECTRON_APP_ROOT, "..", "backend", "cmd", "dev-config.toml"),
26+
);
27+
});
28+
29+
it("prod: returns config.toml under process.resourcesPath", () => {
30+
app.isPackaged = true;
31+
32+
expect(getTemplatePath()).toBe(
33+
path.join("/mock/resources", "config.toml"),
34+
);
35+
});
36+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import path from "path";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
3+
import { ELECTRON_APP_ROOT } from "./helpers.js";
4+
5+
vi.mock("electron", () => ({
6+
app: {
7+
isPackaged: false,
8+
getAppPath: vi.fn().mockReturnValue("/mock/packaged/app"),
9+
getPath: vi.fn().mockReturnValue("/mock/userData"),
10+
},
11+
}));
12+
13+
const { app } = await import("electron");
14+
const { getUserConfigPath } = await import("../paths.js");
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
app.isPackaged = false;
19+
});
20+
21+
describe("getUserConfigPath", () => {
22+
it("dev: returns config.toml in electron-app root", () => {
23+
expect(getUserConfigPath()).toBe(
24+
path.join(ELECTRON_APP_ROOT, "config.toml"),
25+
);
26+
});
27+
28+
it("prod: returns config.toml under userData/configs/", () => {
29+
app.isPackaged = true;
30+
app.getPath.mockReturnValue("/mock/userData");
31+
32+
expect(getUserConfigPath()).toBe(
33+
path.join("/mock/userData", "configs", "config.toml"),
34+
);
35+
expect(app.getPath).toHaveBeenCalledWith("userData");
36+
});
37+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import path from "path";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
3+
import { ELECTRON_APP_ROOT } from "./helpers.js";
4+
5+
vi.mock("electron", () => ({
6+
app: {
7+
isPackaged: false,
8+
getAppPath: vi.fn().mockReturnValue("/mock/packaged/app"),
9+
getPath: vi.fn().mockReturnValue("/mock/userData"),
10+
},
11+
}));
12+
13+
const { app } = await import("electron");
14+
const { getVersionFilePath } = await import("../paths.js");
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
app.isPackaged = false;
19+
});
20+
21+
describe("getVersionFilePath", () => {
22+
it("dev: returns version.toml in electron-app root", () => {
23+
expect(getVersionFilePath()).toBe(
24+
path.join(ELECTRON_APP_ROOT, "version.toml"),
25+
);
26+
});
27+
28+
it("prod: returns version.toml directly under userData/", () => {
29+
app.isPackaged = true;
30+
app.getPath.mockReturnValue("/mock/userData");
31+
32+
expect(getVersionFilePath()).toBe(
33+
path.join("/mock/userData", "version.toml"),
34+
);
35+
expect(app.getPath).toHaveBeenCalledWith("userData");
36+
});
37+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { dirname } from "path";
2+
import path from "path";
3+
import { fileURLToPath } from "url";
4+
5+
// electron-app root is 3 levels up from this file:
6+
// electron-app/src/utils/__tests__/helpers.js -> ../../../ = electron-app/
7+
export const ELECTRON_APP_ROOT = path.resolve(
8+
dirname(fileURLToPath(import.meta.url)),
9+
"..",
10+
"..",
11+
"..",
12+
);
13+
14+
export function mockPlatform(platform) {
15+
Object.defineProperty(process, "platform", {
16+
value: platform,
17+
configurable: true,
18+
});
19+
}
20+
21+
export function mockArch(arch) {
22+
Object.defineProperty(process, "arch", {
23+
value: arch,
24+
configurable: true,
25+
});
26+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { beforeEach, describe, expect, it } from "vitest";
2+
import { createTestStore, seedStore } from "./helpers";
3+
4+
let store: ReturnType<typeof createTestStore>;
5+
6+
beforeEach(() => {
7+
store = createTestStore();
8+
seedStore(store);
9+
});
10+
11+
// ─── selectAllFilters ─────────────────────────────────────────────────────────
12+
13+
describe("selectAllFilters", () => {
14+
it("restores all command IDs after a clear", () => {
15+
store.getState().clearFilters("commands");
16+
store.getState().selectAllFilters("commands");
17+
18+
expect(store.getState().getActiveFilters("commands")).toStrictEqual({
19+
BCU: [1, 2],
20+
PCU: [3],
21+
});
22+
});
23+
24+
it("restores all telemetry IDs after a clear", () => {
25+
store.getState().clearFilters("telemetry");
26+
store.getState().selectAllFilters("telemetry");
27+
28+
expect(store.getState().getActiveFilters("telemetry")).toStrictEqual({
29+
BCU: [10, 20],
30+
PCU: [30],
31+
});
32+
});
33+
34+
it("does not affect the other scope", () => {
35+
store.getState().clearFilters("commands");
36+
const telemetryBefore = store.getState().getActiveFilters("telemetry");
37+
38+
store.getState().selectAllFilters("commands");
39+
40+
expect(store.getState().getActiveFilters("telemetry")).toStrictEqual(
41+
telemetryBefore,
42+
);
43+
});
44+
});
45+
46+
// ─── clearFilters ─────────────────────────────────────────────────────────────
47+
48+
describe("clearFilters", () => {
49+
it("empties all command category arrays", () => {
50+
store.getState().clearFilters("commands");
51+
52+
expect(store.getState().getActiveFilters("commands")).toStrictEqual({
53+
BCU: [],
54+
PCU: [],
55+
});
56+
});
57+
58+
it("empties all telemetry category arrays", () => {
59+
store.getState().clearFilters("telemetry");
60+
61+
expect(store.getState().getActiveFilters("telemetry")).toStrictEqual({
62+
BCU: [],
63+
PCU: [],
64+
});
65+
});
66+
67+
it("does not affect the other scope", () => {
68+
const commandsBefore = store.getState().getActiveFilters("commands");
69+
store.getState().clearFilters("telemetry");
70+
71+
expect(store.getState().getActiveFilters("commands")).toStrictEqual(
72+
commandsBefore,
73+
);
74+
});
75+
});
76+
77+
// ─── toggleItemFilter ─────────────────────────────────────────────────────────
78+
79+
describe("toggleItemFilter", () => {
80+
it("removes an ID that is currently selected", () => {
81+
store.getState().toggleItemFilter("commands", "BCU", 1);
82+
83+
expect(
84+
store.getState().getActiveFilters("commands")?.["BCU"],
85+
).not.toContain(1);
86+
});
87+
88+
it("adds an ID that is not currently selected", () => {
89+
store.getState().clearFilters("commands");
90+
store.getState().toggleItemFilter("commands", "BCU", 1);
91+
92+
expect(
93+
store.getState().getActiveFilters("commands")?.["BCU"],
94+
).toContain(1);
95+
});
96+
97+
it("does not affect other categories", () => {
98+
const pcuBefore = store.getState().getActiveFilters("commands")?.["PCU"];
99+
store.getState().toggleItemFilter("commands", "BCU", 1);
100+
101+
expect(store.getState().getActiveFilters("commands")?.["PCU"]).toStrictEqual(
102+
pcuBefore,
103+
);
104+
});
105+
106+
it("does not affect the other scope", () => {
107+
const telemetryBefore = store.getState().getActiveFilters("telemetry");
108+
store.getState().toggleItemFilter("commands", "BCU", 1);
109+
110+
expect(store.getState().getActiveFilters("telemetry")).toStrictEqual(
111+
telemetryBefore,
112+
);
113+
});
114+
});
115+
116+
// ─── toggleCategoryFilter ─────────────────────────────────────────────────────
117+
118+
describe("toggleCategoryFilter", () => {
119+
it("checked=true selects all IDs in the commands category", () => {
120+
store.getState().clearFilters("commands");
121+
store.getState().toggleCategoryFilter("commands", "BCU", true);
122+
123+
expect(
124+
store.getState().getActiveFilters("commands")?.["BCU"],
125+
).toStrictEqual([1, 2]);
126+
});
127+
128+
it("checked=true selects all IDs in the telemetry category", () => {
129+
store.getState().clearFilters("telemetry");
130+
store.getState().toggleCategoryFilter("telemetry", "BCU", true);
131+
132+
expect(
133+
store.getState().getActiveFilters("telemetry")?.["BCU"],
134+
).toStrictEqual([10, 20]);
135+
});
136+
137+
it("checked=false clears all IDs in the category", () => {
138+
store.getState().toggleCategoryFilter("commands", "BCU", false);
139+
140+
expect(
141+
store.getState().getActiveFilters("commands")?.["BCU"],
142+
).toStrictEqual([]);
143+
});
144+
145+
it("does not affect other categories", () => {
146+
const pcuBefore = store.getState().getActiveFilters("commands")?.["PCU"];
147+
store.getState().toggleCategoryFilter("commands", "BCU", false);
148+
149+
expect(store.getState().getActiveFilters("commands")?.["PCU"]).toStrictEqual(
150+
pcuBefore,
151+
);
152+
});
153+
});

0 commit comments

Comments
 (0)