Skip to content

Commit 004d740

Browse files
committed
test(primitives): add comprehensive tests for 11 untested Cortex primitives
Create test files for CortexIconButton, CortexConfigBadge, CortexStartPause, CortexOpenProjectDropdown, CortexVibeToggle, CortexModelSelector, CortexSendButton, CortexSeparator, CortexSmallButton, CortexHeaderItem, and CortexCodeNavHelp. Each test covers rendering, props, interactions (click, hover, mousedown), disabled states, accessibility attributes (role, aria-label, aria-pressed), and custom class/style merging. Uses existing conventions: vitest, @solidjs/testing-library, Tauri API mocks, CortexIcon mock stub. Total: 200 new test cases across 11 files, all 547 tests passing.
1 parent 97a5087 commit 004d740

11 files changed

+1928
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { describe, it, expect, vi, beforeEach } from "vitest";
2+
import { render, fireEvent } from "@solidjs/testing-library";
3+
import { CortexCodeNavHelp } from "../CortexCodeNavHelp";
4+
5+
vi.mock("@tauri-apps/api/core", () => ({
6+
invoke: vi.fn(),
7+
}));
8+
9+
vi.mock("@tauri-apps/api/event", () => ({
10+
listen: vi.fn().mockResolvedValue(() => {}),
11+
emit: vi.fn(),
12+
}));
13+
14+
vi.mock("../CortexIcon", () => ({
15+
CortexIcon: (props: { name: string; size: number; color?: string }) => (
16+
<span data-testid="cortex-icon" data-name={props.name} data-size={props.size} />
17+
),
18+
}));
19+
20+
describe("CortexCodeNavHelp", () => {
21+
beforeEach(() => {
22+
vi.clearAllMocks();
23+
});
24+
25+
describe("rendering", () => {
26+
it("renders as a button element", () => {
27+
const { getByRole } = render(() => <CortexCodeNavHelp />);
28+
const button = getByRole("button");
29+
expect(button).toBeTruthy();
30+
});
31+
32+
it("has type button", () => {
33+
const { getByRole } = render(() => <CortexCodeNavHelp />);
34+
const button = getByRole("button") as HTMLButtonElement;
35+
expect(button.type).toBe("button");
36+
});
37+
38+
it("has 26px height", () => {
39+
const { getByRole } = render(() => <CortexCodeNavHelp />);
40+
const button = getByRole("button") as HTMLElement;
41+
expect(button.style.height).toBe("26px");
42+
});
43+
44+
it("has transparent background", () => {
45+
const { getByRole } = render(() => <CortexCodeNavHelp />);
46+
const button = getByRole("button") as HTMLElement;
47+
expect(button.style.background).toBe("transparent");
48+
});
49+
});
50+
51+
describe("label", () => {
52+
it("renders default label 'Code Navigation Help'", () => {
53+
const { getByText } = render(() => <CortexCodeNavHelp />);
54+
expect(getByText("Code Navigation Help")).toBeTruthy();
55+
});
56+
57+
it("renders custom label when provided", () => {
58+
const { getByText } = render(() => (
59+
<CortexCodeNavHelp label="Go Back" />
60+
));
61+
expect(getByText("Go Back")).toBeTruthy();
62+
});
63+
});
64+
65+
describe("icon", () => {
66+
it("renders chevron-left icon", () => {
67+
const { container } = render(() => <CortexCodeNavHelp />);
68+
const icon = container.querySelector("[data-testid='cortex-icon']");
69+
expect(icon).toBeTruthy();
70+
expect(icon?.getAttribute("data-name")).toBe("chevron-left");
71+
});
72+
73+
it("renders icon with size 16", () => {
74+
const { container } = render(() => <CortexCodeNavHelp />);
75+
const icon = container.querySelector("[data-testid='cortex-icon']");
76+
expect(icon?.getAttribute("data-size")).toBe("16");
77+
});
78+
});
79+
80+
describe("onClick handler", () => {
81+
it("calls onClick when clicked", async () => {
82+
const handleClick = vi.fn();
83+
const { getByRole } = render(() => (
84+
<CortexCodeNavHelp onClick={handleClick} />
85+
));
86+
const button = getByRole("button");
87+
await fireEvent.click(button);
88+
expect(handleClick).toHaveBeenCalledTimes(1);
89+
});
90+
91+
it("passes event to onClick handler", async () => {
92+
const handleClick = vi.fn();
93+
const { getByRole } = render(() => (
94+
<CortexCodeNavHelp onClick={handleClick} />
95+
));
96+
const button = getByRole("button");
97+
await fireEvent.click(button);
98+
expect(handleClick).toHaveBeenCalledWith(expect.any(MouseEvent));
99+
});
100+
});
101+
102+
describe("cursor", () => {
103+
it("has pointer cursor when onClick is provided", () => {
104+
const handleClick = vi.fn();
105+
const { getByRole } = render(() => (
106+
<CortexCodeNavHelp onClick={handleClick} />
107+
));
108+
const button = getByRole("button") as HTMLElement;
109+
expect(button.style.cursor).toBe("pointer");
110+
});
111+
112+
it("has default cursor when onClick is not provided", () => {
113+
const { getByRole } = render(() => <CortexCodeNavHelp />);
114+
const button = getByRole("button") as HTMLElement;
115+
expect(button.style.cursor).toBe("default");
116+
});
117+
});
118+
119+
describe("custom class and style", () => {
120+
it("applies custom class", () => {
121+
const { getByRole } = render(() => (
122+
<CortexCodeNavHelp class="custom-nav-help" />
123+
));
124+
const button = getByRole("button");
125+
expect(button.classList.contains("custom-nav-help")).toBe(true);
126+
});
127+
128+
it("merges custom style with base styles", () => {
129+
const { getByRole } = render(() => (
130+
<CortexCodeNavHelp style={{ "margin-top": "10px" }} />
131+
));
132+
const button = getByRole("button") as HTMLElement;
133+
expect(button.style.marginTop).toBe("10px");
134+
});
135+
});
136+
});
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import { describe, it, expect, vi, beforeEach } from "vitest";
2+
import { render, fireEvent } from "@solidjs/testing-library";
3+
import { CortexConfigBadge } from "../CortexConfigBadge";
4+
5+
vi.mock("@tauri-apps/api/core", () => ({
6+
invoke: vi.fn(),
7+
}));
8+
9+
vi.mock("@tauri-apps/api/event", () => ({
10+
listen: vi.fn().mockResolvedValue(() => {}),
11+
emit: vi.fn(),
12+
}));
13+
14+
vi.mock("../CortexIcon", () => ({
15+
CortexIcon: (props: { name: string; size: number }) => (
16+
<span data-testid="cortex-icon" data-name={props.name} data-size={props.size} />
17+
),
18+
}));
19+
20+
describe("CortexConfigBadge", () => {
21+
beforeEach(() => {
22+
vi.clearAllMocks();
23+
});
24+
25+
describe("rendering", () => {
26+
it("renders as a button element", () => {
27+
const { getByRole } = render(() => <CortexConfigBadge />);
28+
const button = getByRole("button");
29+
expect(button).toBeTruthy();
30+
});
31+
32+
it("renders gear icon", () => {
33+
const { container } = render(() => <CortexConfigBadge />);
34+
const icons = container.querySelectorAll("[data-testid='cortex-icon']");
35+
const gearIcon = Array.from(icons).find(
36+
(icon) => icon.getAttribute("data-name") === "gear"
37+
);
38+
expect(gearIcon).toBeTruthy();
39+
});
40+
41+
it("has type button", () => {
42+
const { getByRole } = render(() => <CortexConfigBadge />);
43+
const button = getByRole("button") as HTMLButtonElement;
44+
expect(button.type).toBe("button");
45+
});
46+
});
47+
48+
describe("label", () => {
49+
it("renders label when provided", () => {
50+
const { getByText } = render(() => <CortexConfigBadge label="Settings" />);
51+
expect(getByText("Settings")).toBeTruthy();
52+
});
53+
54+
it("does not render label text when label is not provided", () => {
55+
const { container } = render(() => <CortexConfigBadge />);
56+
const button = container.querySelector("button");
57+
const textContent = button?.textContent ?? "";
58+
const iconTexts = Array.from(
59+
button?.querySelectorAll("[data-testid='cortex-icon']") ?? []
60+
).map((el) => el.textContent);
61+
const nonIconText = textContent.replace(iconTexts.join(""), "").trim();
62+
expect(nonIconText).toBe("");
63+
});
64+
});
65+
66+
describe("open/close state", () => {
67+
it("renders chevron-down when closed", () => {
68+
const { container } = render(() => <CortexConfigBadge isOpen={false} />);
69+
const icons = container.querySelectorAll("[data-testid='cortex-icon']");
70+
const chevronIcon = Array.from(icons).find(
71+
(icon) => icon.getAttribute("data-name") === "chevron-down"
72+
);
73+
expect(chevronIcon).toBeTruthy();
74+
});
75+
76+
it("renders chevron-up when open", () => {
77+
const { container } = render(() => <CortexConfigBadge isOpen={true} />);
78+
const icons = container.querySelectorAll("[data-testid='cortex-icon']");
79+
const chevronIcon = Array.from(icons).find(
80+
(icon) => icon.getAttribute("data-name") === "chevron-up"
81+
);
82+
expect(chevronIcon).toBeTruthy();
83+
});
84+
85+
it("renders children when isOpen is true", () => {
86+
const { getByText } = render(() => (
87+
<CortexConfigBadge isOpen={true}>
88+
<div>Dropdown Content</div>
89+
</CortexConfigBadge>
90+
));
91+
expect(getByText("Dropdown Content")).toBeTruthy();
92+
});
93+
94+
it("does not render children when isOpen is false", () => {
95+
const { queryByText } = render(() => (
96+
<CortexConfigBadge isOpen={false}>
97+
<div>Dropdown Content</div>
98+
</CortexConfigBadge>
99+
));
100+
expect(queryByText("Dropdown Content")).toBeNull();
101+
});
102+
});
103+
104+
describe("onClick handler", () => {
105+
it("calls onClick when clicked", async () => {
106+
const handleClick = vi.fn();
107+
const { getByRole } = render(() => (
108+
<CortexConfigBadge onClick={handleClick} />
109+
));
110+
const button = getByRole("button");
111+
await fireEvent.click(button);
112+
expect(handleClick).toHaveBeenCalledTimes(1);
113+
});
114+
115+
it("passes event to onClick handler", async () => {
116+
const handleClick = vi.fn();
117+
const { getByRole } = render(() => (
118+
<CortexConfigBadge onClick={handleClick} />
119+
));
120+
const button = getByRole("button");
121+
await fireEvent.click(button);
122+
expect(handleClick).toHaveBeenCalledWith(expect.any(MouseEvent));
123+
});
124+
});
125+
126+
describe("variant states", () => {
127+
it("has transparent background in default variant", () => {
128+
const { getByRole } = render(() => <CortexConfigBadge variant="default" />);
129+
const button = getByRole("button") as HTMLElement;
130+
expect(button.style.background).toBe("transparent");
131+
});
132+
133+
it("has hover background in hover variant", () => {
134+
const { getByRole } = render(() => <CortexConfigBadge variant="hover" />);
135+
const button = getByRole("button") as HTMLElement;
136+
expect(button.style.background).toContain("cortex-bg-hover");
137+
});
138+
139+
it("has active background in active variant", () => {
140+
const { getByRole } = render(() => <CortexConfigBadge variant="active" />);
141+
const button = getByRole("button") as HTMLElement;
142+
expect(button.style.background).toContain("cortex-bg-secondary");
143+
});
144+
});
145+
146+
describe("hover states", () => {
147+
it("changes background on mouse enter", () => {
148+
const { getByRole } = render(() => <CortexConfigBadge />);
149+
const button = getByRole("button") as HTMLElement;
150+
expect(button.style.background).toBe("transparent");
151+
const mouseEnterEvent = new MouseEvent("mouseenter", { bubbles: true });
152+
button.dispatchEvent(mouseEnterEvent);
153+
expect(button.style.background).toContain("cortex-bg-hover");
154+
});
155+
156+
it("restores background on mouse leave", () => {
157+
const { getByRole } = render(() => <CortexConfigBadge />);
158+
const button = getByRole("button") as HTMLElement;
159+
const mouseEnterEvent = new MouseEvent("mouseenter", { bubbles: true });
160+
const mouseLeaveEvent = new MouseEvent("mouseleave", { bubbles: true });
161+
button.dispatchEvent(mouseEnterEvent);
162+
button.dispatchEvent(mouseLeaveEvent);
163+
expect(button.style.background).toBe("transparent");
164+
});
165+
166+
it("applies border-radius on hover", () => {
167+
const { getByRole } = render(() => <CortexConfigBadge />);
168+
const button = getByRole("button") as HTMLElement;
169+
expect(button.style.borderRadius).toBe("0px");
170+
const mouseEnterEvent = new MouseEvent("mouseenter", { bubbles: true });
171+
button.dispatchEvent(mouseEnterEvent);
172+
expect(button.style.borderRadius).toBe("4px");
173+
});
174+
});
175+
176+
describe("custom class and style", () => {
177+
it("applies custom class", () => {
178+
const { getByRole } = render(() => (
179+
<CortexConfigBadge class="custom-badge" />
180+
));
181+
const button = getByRole("button");
182+
expect(button.classList.contains("custom-badge")).toBe(true);
183+
});
184+
185+
it("merges custom style with base styles", () => {
186+
const { getByRole } = render(() => (
187+
<CortexConfigBadge style={{ "margin-top": "10px" }} />
188+
));
189+
const button = getByRole("button") as HTMLElement;
190+
expect(button.style.marginTop).toBe("10px");
191+
});
192+
});
193+
});

0 commit comments

Comments
 (0)