@hilum/ui 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,388 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { render, screen, fireEvent } from "@testing-library/react";
3
- import {
4
- Breadcrumb,
5
- BreadcrumbList,
6
- BreadcrumbItem,
7
- BreadcrumbLink,
8
- BreadcrumbPage,
9
- BreadcrumbSeparator,
10
- BreadcrumbEllipsis,
11
- } from "../breadcrumb";
12
- import { SectionHeading } from "../section-heading";
13
- import { PageHeading } from "../page-heading";
14
- import { DescriptionList } from "../description-list";
15
- import { PropertyRow } from "../property-row";
16
- import { StackedList, StackedListItem } from "../stacked-list";
17
- import { GridList, GridListCard, GridListAccentCard } from "../grid-list";
18
- import { ActivityFeed } from "../activity-feed";
19
- import { CardHeading } from "../card-heading";
20
- import { ActionPanel } from "../action-panel";
21
- import { ButtonGroup, ButtonGroupItem } from "../button-group";
22
-
23
- /* ------------------------------------------------------------------ */
24
- /* Breadcrumb */
25
- /* ------------------------------------------------------------------ */
26
-
27
- describe("Breadcrumb", () => {
28
- it('renders nav with aria-label="breadcrumb"', () => {
29
- render(<Breadcrumb />);
30
- expect(screen.getByRole("navigation", { name: "breadcrumb" })).toBeInTheDocument();
31
- });
32
-
33
- it("renders full breadcrumb trail", () => {
34
- render(
35
- <Breadcrumb>
36
- <BreadcrumbList>
37
- <BreadcrumbItem>
38
- <BreadcrumbLink href="/">Home</BreadcrumbLink>
39
- </BreadcrumbItem>
40
- <BreadcrumbSeparator />
41
- <BreadcrumbItem>
42
- <BreadcrumbPage>Settings</BreadcrumbPage>
43
- </BreadcrumbItem>
44
- </BreadcrumbList>
45
- </Breadcrumb>,
46
- );
47
- expect(screen.getByRole("link", { name: "Home" })).toBeInTheDocument();
48
- expect(screen.getByText("Settings")).toBeInTheDocument();
49
- });
50
-
51
- it("renders BreadcrumbEllipsis", () => {
52
- const { container } = render(<BreadcrumbEllipsis />);
53
- expect(container.querySelector('[role="presentation"]')).toBeInTheDocument();
54
- });
55
- });
56
-
57
- /* ------------------------------------------------------------------ */
58
- /* SectionHeading */
59
- /* ------------------------------------------------------------------ */
60
-
61
- describe("SectionHeading", () => {
62
- it("renders title", () => {
63
- render(<SectionHeading title="Team Members" />);
64
- expect(screen.getByText("Team Members")).toBeInTheDocument();
65
- });
66
-
67
- it("renders description", () => {
68
- render(<SectionHeading title="Title" description="Manage your team." />);
69
- expect(screen.getByText("Manage your team.")).toBeInTheDocument();
70
- });
71
-
72
- it("renders actions", () => {
73
- render(<SectionHeading title="Title" actions={[{ label: "Add", onClick: () => {} }]} />);
74
- expect(screen.getByRole("button", { name: "Add" })).toBeInTheDocument();
75
- });
76
-
77
- it("renders action with href as link", () => {
78
- render(<SectionHeading title="Title" actions={[{ label: "View", href: "/all" }]} />);
79
- expect(screen.getByRole("link", { name: "View" })).toHaveAttribute("href", "/all");
80
- });
81
- });
82
-
83
- /* ------------------------------------------------------------------ */
84
- /* PageHeading */
85
- /* ------------------------------------------------------------------ */
86
-
87
- describe("PageHeading", () => {
88
- it("renders title as h1", () => {
89
- render(<PageHeading title="Dashboard" />);
90
- expect(screen.getByRole("heading", { name: "Dashboard", level: 1 })).toBeInTheDocument();
91
- });
92
-
93
- it("renders description", () => {
94
- render(<PageHeading title="Users" description="Manage all users." />);
95
- expect(screen.getByText("Manage all users.")).toBeInTheDocument();
96
- });
97
-
98
- it("renders breadcrumbs", () => {
99
- render(
100
- <PageHeading
101
- title="Configuration"
102
- breadcrumbs={[{ label: "Home", href: "/" }, { label: "Config" }]}
103
- />,
104
- );
105
- expect(screen.getByRole("link", { name: "Home" })).toBeInTheDocument();
106
- expect(screen.getByText("Config")).toBeInTheDocument();
107
- });
108
-
109
- it("renders badge as string", () => {
110
- render(<PageHeading title="Title" badge="Beta" />);
111
- expect(screen.getByText("Beta")).toBeInTheDocument();
112
- });
113
-
114
- it("renders badge as object", () => {
115
- render(<PageHeading title="Title" badge={{ label: "New", variant: "secondary" }} />);
116
- expect(screen.getByText("New")).toBeInTheDocument();
117
- });
118
-
119
- it("renders actions", () => {
120
- render(<PageHeading title="Title" actions={[{ label: "Export", primary: true }]} />);
121
- expect(screen.getByRole("button", { name: "Export" })).toBeInTheDocument();
122
- });
123
- });
124
-
125
- /* ------------------------------------------------------------------ */
126
- /* DescriptionList */
127
- /* ------------------------------------------------------------------ */
128
-
129
- describe("DescriptionList", () => {
130
- const items = [
131
- { term: "Name", details: "Alice" },
132
- { term: "Role", details: "Admin" },
133
- ];
134
-
135
- it("renders all terms and details", () => {
136
- render(<DescriptionList items={items} />);
137
- expect(screen.getByText("Name")).toBeInTheDocument();
138
- expect(screen.getByText("Alice")).toBeInTheDocument();
139
- expect(screen.getByText("Role")).toBeInTheDocument();
140
- expect(screen.getByText("Admin")).toBeInTheDocument();
141
- });
142
-
143
- it("renders title and description when provided", () => {
144
- render(<DescriptionList items={items} title="Details" description="User info" />);
145
- expect(screen.getByText("Details")).toBeInTheDocument();
146
- expect(screen.getByText("User info")).toBeInTheDocument();
147
- });
148
-
149
- it("renders 2-column layout", () => {
150
- render(<DescriptionList items={items} columns={2} />);
151
- expect(screen.getByText("Alice")).toBeInTheDocument();
152
- });
153
-
154
- it("renders action alongside detail", () => {
155
- render(
156
- <DescriptionList
157
- items={[{ term: "Email", details: "alice@test.com", action: <button>Edit</button> }]}
158
- />,
159
- );
160
- expect(screen.getByRole("button", { name: "Edit" })).toBeInTheDocument();
161
- });
162
- });
163
-
164
- /* ------------------------------------------------------------------ */
165
- /* PropertyRow */
166
- /* ------------------------------------------------------------------ */
167
-
168
- describe("PropertyRow", () => {
169
- it("renders label and children", () => {
170
- render(
171
- <PropertyRow label="Width">
172
- <input type="number" aria-label="width-input" />
173
- </PropertyRow>,
174
- );
175
- expect(screen.getByText("Width")).toBeInTheDocument();
176
- expect(screen.getByLabelText("width-input")).toBeInTheDocument();
177
- });
178
-
179
- it("renders without label", () => {
180
- render(
181
- <PropertyRow>
182
- <span>Controls</span>
183
- </PropertyRow>,
184
- );
185
- expect(screen.getByText("Controls")).toBeInTheDocument();
186
- });
187
- });
188
-
189
- /* ------------------------------------------------------------------ */
190
- /* StackedList */
191
- /* ------------------------------------------------------------------ */
192
-
193
- describe("StackedList", () => {
194
- it("renders as a list", () => {
195
- render(
196
- <StackedList>
197
- <StackedListItem>Item 1</StackedListItem>
198
- <StackedListItem>Item 2</StackedListItem>
199
- </StackedList>,
200
- );
201
- expect(screen.getByRole("list")).toBeInTheDocument();
202
- expect(screen.getByText("Item 1")).toBeInTheDocument();
203
- expect(screen.getByText("Item 2")).toBeInTheDocument();
204
- });
205
-
206
- it("renders item with href as link", () => {
207
- render(
208
- <StackedList>
209
- <StackedListItem href="/page">Go to page</StackedListItem>
210
- </StackedList>,
211
- );
212
- expect(screen.getByRole("link", { name: "Go to page" })).toBeInTheDocument();
213
- });
214
-
215
- it("renders item with onClick as button", () => {
216
- render(
217
- <StackedList>
218
- <StackedListItem onClick={() => {}}>Clickable</StackedListItem>
219
- </StackedList>,
220
- );
221
- expect(screen.getByRole("button", { name: "Clickable" })).toBeInTheDocument();
222
- });
223
- });
224
-
225
- /* ------------------------------------------------------------------ */
226
- /* GridList */
227
- /* ------------------------------------------------------------------ */
228
-
229
- describe("GridList", () => {
230
- it("renders as a list", () => {
231
- render(
232
- <GridList>
233
- <GridListCard title="Card A" />
234
- <GridListCard title="Card B" />
235
- </GridList>,
236
- );
237
- expect(screen.getByRole("list")).toBeInTheDocument();
238
- expect(screen.getByText("Card A")).toBeInTheDocument();
239
- expect(screen.getByText("Card B")).toBeInTheDocument();
240
- });
241
-
242
- it("GridListCard renders description", () => {
243
- render(
244
- <GridList>
245
- <GridListCard title="Item" description="Desc text" />
246
- </GridList>,
247
- );
248
- expect(screen.getByText("Desc text")).toBeInTheDocument();
249
- });
250
-
251
- it("GridListCard renders as link when href provided", () => {
252
- render(
253
- <GridList>
254
- <GridListCard title="Click" href="/target" />
255
- </GridList>,
256
- );
257
- expect(screen.getByRole("link")).toHaveAttribute("href", "/target");
258
- });
259
-
260
- it("GridListAccentCard renders title", () => {
261
- render(
262
- <GridList>
263
- <GridListAccentCard title="Project Alpha" initials="PA" />
264
- </GridList>,
265
- );
266
- expect(screen.getByText("Project Alpha")).toBeInTheDocument();
267
- });
268
-
269
- it("GridListAccentCard renders as link when href provided", () => {
270
- render(
271
- <GridList>
272
- <GridListAccentCard title="Project" href="/project" />
273
- </GridList>,
274
- );
275
- expect(screen.getByRole("link")).toHaveAttribute("href", "/project");
276
- });
277
- });
278
-
279
- /* ------------------------------------------------------------------ */
280
- /* ActivityFeed */
281
- /* ------------------------------------------------------------------ */
282
-
283
- describe("ActivityFeed", () => {
284
- it("renders all events", () => {
285
- render(
286
- <ActivityFeed
287
- events={[
288
- { id: 1, content: "User joined", date: "Today" },
289
- { id: 2, content: "File uploaded", date: "Yesterday" },
290
- ]}
291
- />,
292
- );
293
- expect(screen.getByText("User joined")).toBeInTheDocument();
294
- expect(screen.getByText("File uploaded")).toBeInTheDocument();
295
- });
296
-
297
- it("renders event dates", () => {
298
- render(<ActivityFeed events={[{ content: "Action", date: "Jan 1, 2026" }]} />);
299
- expect(screen.getByText("Jan 1, 2026")).toBeInTheDocument();
300
- });
301
- });
302
-
303
- /* ------------------------------------------------------------------ */
304
- /* CardHeading */
305
- /* ------------------------------------------------------------------ */
306
-
307
- describe("CardHeading", () => {
308
- it("renders title", () => {
309
- render(<CardHeading title="Team Settings" />);
310
- expect(screen.getByText("Team Settings")).toBeInTheDocument();
311
- });
312
-
313
- it("renders description", () => {
314
- render(<CardHeading title="Title" description="Subtitle here" />);
315
- expect(screen.getByText("Subtitle here")).toBeInTheDocument();
316
- });
317
-
318
- it("renders actions", () => {
319
- render(<CardHeading title="Title" actions={[{ label: "Save" }]} />);
320
- expect(screen.getByRole("button", { name: "Save" })).toBeInTheDocument();
321
- });
322
- });
323
-
324
- /* ------------------------------------------------------------------ */
325
- /* ActionPanel */
326
- /* ------------------------------------------------------------------ */
327
-
328
- describe("ActionPanel", () => {
329
- it("renders title", () => {
330
- render(<ActionPanel title="Danger Zone" />);
331
- expect(screen.getByText("Danger Zone")).toBeInTheDocument();
332
- });
333
-
334
- it("renders description", () => {
335
- render(<ActionPanel title="T" description="Delete this account." />);
336
- expect(screen.getByText("Delete this account.")).toBeInTheDocument();
337
- });
338
-
339
- it("renders action button", () => {
340
- render(<ActionPanel title="T" action={{ label: "Delete", variant: "destructive" }} />);
341
- expect(screen.getByRole("button", { name: "Delete" })).toBeInTheDocument();
342
- });
343
-
344
- it("renders inline layout without error", () => {
345
- render(<ActionPanel title="Info" layout="inline" action={{ label: "Go" }} />);
346
- expect(screen.getByText("Info")).toBeInTheDocument();
347
- });
348
-
349
- it("renders muted variant without error", () => {
350
- render(<ActionPanel title="Note" variant="muted" />);
351
- expect(screen.getByText("Note")).toBeInTheDocument();
352
- });
353
-
354
- it("renders link", () => {
355
- render(<ActionPanel title="T" link={{ label: "Learn more", href: "/docs" }} />);
356
- expect(screen.getByText("Learn more")).toBeInTheDocument();
357
- });
358
- });
359
-
360
- /* ------------------------------------------------------------------ */
361
- /* ButtonGroup */
362
- /* ------------------------------------------------------------------ */
363
-
364
- describe("ButtonGroup", () => {
365
- it("renders items", () => {
366
- render(
367
- <ButtonGroup>
368
- <ButtonGroupItem>Day</ButtonGroupItem>
369
- <ButtonGroupItem>Week</ButtonGroupItem>
370
- <ButtonGroupItem active>Month</ButtonGroupItem>
371
- </ButtonGroup>,
372
- );
373
- expect(screen.getByRole("button", { name: "Day" })).toBeInTheDocument();
374
- expect(screen.getByRole("button", { name: "Week" })).toBeInTheDocument();
375
- expect(screen.getByRole("button", { name: "Month" })).toBeInTheDocument();
376
- });
377
-
378
- it("calls onClick on item click", () => {
379
- const onClick = vi.fn();
380
- render(
381
- <ButtonGroup>
382
- <ButtonGroupItem onClick={onClick}>Click me</ButtonGroupItem>
383
- </ButtonGroup>,
384
- );
385
- fireEvent.click(screen.getByRole("button", { name: "Click me" }));
386
- expect(onClick).toHaveBeenCalledTimes(1);
387
- });
388
- });
@@ -1,90 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { render, screen } from "@testing-library/react";
3
- import { userEvent } from "@testing-library/user-event";
4
- import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "../tooltip";
5
- import { Progress } from "../progress";
6
- import { Switch } from "../switch";
7
- import { Slider } from "../slider";
8
-
9
- /**
10
- * Tests for Radix overlay primitives. These focus on:
11
- * 1. Trigger elements render and are accessible
12
- * 2. Content appears on interaction
13
- * 3. No render crashes
14
- */
15
-
16
- /* ------------------------------------------------------------------ */
17
- /* Tooltip */
18
- /* ------------------------------------------------------------------ */
19
-
20
- describe("Tooltip", () => {
21
- it("renders the trigger element", () => {
22
- render(
23
- <TooltipProvider>
24
- <Tooltip>
25
- <TooltipTrigger asChild>
26
- <button>Hover me</button>
27
- </TooltipTrigger>
28
- <TooltipContent>Helpful hint</TooltipContent>
29
- </Tooltip>
30
- </TooltipProvider>,
31
- );
32
- expect(screen.getByRole("button", { name: "Hover me" })).toBeInTheDocument();
33
- });
34
-
35
- it("shows tooltip content on hover", async () => {
36
- const user = userEvent.setup();
37
- render(
38
- <TooltipProvider>
39
- <Tooltip>
40
- <TooltipTrigger asChild>
41
- <button>Trigger</button>
42
- </TooltipTrigger>
43
- <TooltipContent>Tooltip text</TooltipContent>
44
- </Tooltip>
45
- </TooltipProvider>,
46
- );
47
- await user.hover(screen.getByRole("button", { name: "Trigger" }));
48
- // Use role="tooltip" to target the accessible tooltip element specifically
49
- expect(await screen.findByRole("tooltip", { name: "Tooltip text" })).toBeInTheDocument();
50
- });
51
- });
52
-
53
- /* ------------------------------------------------------------------ */
54
- /* Switch — additional a11y checks */
55
- /* ------------------------------------------------------------------ */
56
-
57
- describe("Switch a11y", () => {
58
- it("has a role of switch", () => {
59
- render(<Switch aria-label="Enable notifications" />);
60
- expect(screen.getByRole("switch", { name: "Enable notifications" })).toBeInTheDocument();
61
- });
62
- });
63
-
64
- /* ------------------------------------------------------------------ */
65
- /* Slider — additional a11y checks */
66
- /* ------------------------------------------------------------------ */
67
-
68
- describe("Slider a11y", () => {
69
- it("has proper ARIA attributes", () => {
70
- render(<Slider defaultValue={[30]} min={0} max={100} aria-label="Volume" />);
71
- const slider = screen.getByRole("slider");
72
- expect(slider).toHaveAttribute("aria-valuemin", "0");
73
- expect(slider).toHaveAttribute("aria-valuemax", "100");
74
- expect(slider).toHaveAttribute("aria-valuenow", "30");
75
- });
76
- });
77
-
78
- /* ------------------------------------------------------------------ */
79
- /* Progress — additional a11y checks */
80
- /* ------------------------------------------------------------------ */
81
-
82
- describe("Progress a11y", () => {
83
- it("has proper ARIA range attributes", () => {
84
- render(<Progress value={45} />);
85
- const bar = screen.getByRole("progressbar");
86
- expect(bar).toHaveAttribute("aria-valuemin", "0");
87
- expect(bar).toHaveAttribute("aria-valuemax", "100");
88
- expect(bar).toHaveAttribute("aria-valuenow", "45");
89
- });
90
- });