@simplysm/solid 13.0.70 → 13.0.72
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.
- package/README.md +1 -1
- package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.js +3 -6
- package/dist/components/data/sheet/DataSheet.js.map +1 -1
- package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
- package/dist/components/disclosure/Dropdown.d.ts +6 -4
- package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
- package/dist/components/disclosure/Dropdown.js +24 -8
- package/dist/components/disclosure/Dropdown.js.map +2 -2
- package/dist/components/disclosure/dialogZIndex.d.ts +2 -0
- package/dist/components/disclosure/dialogZIndex.d.ts.map +1 -1
- package/dist/components/disclosure/dialogZIndex.js +4 -0
- package/dist/components/disclosure/dialogZIndex.js.map +1 -1
- package/dist/components/features/crud-detail/CrudDetail.d.ts.map +1 -1
- package/dist/components/features/crud-detail/CrudDetail.js +16 -7
- package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
- package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
- package/dist/components/features/crud-sheet/CrudSheet.js +14 -5
- package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
- package/dist/components/features/crudRegistry.d.ts +16 -0
- package/dist/components/features/crudRegistry.d.ts.map +1 -0
- package/dist/components/features/crudRegistry.js +37 -0
- package/dist/components/features/crudRegistry.js.map +6 -0
- package/dist/components/features/permission-table/PermissionTable.d.ts.map +1 -1
- package/dist/components/features/permission-table/PermissionTable.js +71 -86
- package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
- package/dist/components/features/shared-data/SharedDataSelect.js +2 -4
- package/dist/components/features/shared-data/SharedDataSelect.js.map +2 -2
- package/dist/components/features/shared-data/SharedDataSelectList.d.ts +2 -4
- package/dist/components/features/shared-data/SharedDataSelectList.d.ts.map +1 -1
- package/dist/components/features/shared-data/SharedDataSelectList.js +11 -46
- package/dist/components/features/shared-data/SharedDataSelectList.js.map +2 -2
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +1 -1
- package/dist/components/form-control/select/Select.js.map +1 -1
- package/dist/helpers/createAppStructure.d.ts.map +1 -1
- package/dist/helpers/createAppStructure.js +3 -2
- package/dist/helpers/createAppStructure.js.map +1 -1
- package/dist/helpers/createHmrSafeContext.d.ts +3 -0
- package/dist/helpers/createHmrSafeContext.d.ts.map +1 -0
- package/dist/helpers/createHmrSafeContext.js +10 -0
- package/dist/helpers/createHmrSafeContext.js.map +6 -0
- package/dist/hooks/createSelectionGroup.d.ts.map +1 -1
- package/dist/hooks/createSelectionGroup.js +3 -2
- package/dist/hooks/createSelectionGroup.js.map +2 -2
- package/package.json +6 -5
- package/src/components/data/sheet/DataSheet.styles.ts +1 -1
- package/src/components/data/sheet/DataSheet.tsx +3 -4
- package/src/components/disclosure/Dropdown.tsx +31 -17
- package/src/components/disclosure/dialogZIndex.ts +5 -0
- package/src/components/features/crud-detail/CrudDetail.tsx +16 -5
- package/src/components/features/crud-sheet/CrudSheet.tsx +13 -3
- package/src/components/features/crudRegistry.ts +60 -0
- package/src/components/features/permission-table/PermissionTable.tsx +49 -46
- package/src/components/features/shared-data/SharedDataSelect.tsx +2 -2
- package/src/components/features/shared-data/SharedDataSelectList.tsx +11 -36
- package/src/components/form-control/select/Select.tsx +1 -5
- package/src/helpers/createAppStructure.ts +3 -2
- package/src/helpers/createHmrSafeContext.ts +8 -0
- package/src/hooks/createSelectionGroup.tsx +4 -2
- package/tests/components/data/List.spec.tsx +52 -52
- package/tests/components/data/Pagination.spec.tsx +43 -43
- package/tests/components/data/Table.spec.tsx +4 -4
- package/tests/components/data/kanban/Kanban.selection.spec.tsx +21 -21
- package/tests/components/data/sheet/DataSheet.spec.tsx +50 -50
- package/tests/components/disclosure/Collapse.spec.tsx +24 -24
- package/tests/components/disclosure/Dialog.spec.tsx +33 -33
- package/tests/components/disclosure/DialogProvider.spec.tsx +9 -9
- package/tests/components/disclosure/Dropdown.spec.tsx +134 -14
- package/tests/components/disclosure/Tabs.spec.tsx +21 -21
- package/tests/components/disclosure/dialogZIndex.spec.ts +45 -0
- package/tests/components/display/Alert.spec.tsx +4 -4
- package/tests/components/display/Barcode.spec.tsx +7 -7
- package/tests/components/display/Card.spec.tsx +3 -3
- package/tests/components/display/Link.spec.tsx +5 -5
- package/tests/components/display/Tag.spec.tsx +4 -4
- package/tests/components/features/address/AddressSearch.spec.tsx +3 -3
- package/tests/components/features/crudRegistry.spec.ts +119 -0
- package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +8 -8
- package/tests/components/features/permission-table/PermissionTable.spec.tsx +43 -43
- package/tests/components/features/shared-data/SharedDataSelectList.spec.tsx +2 -17
- package/tests/components/feedback/busy/BusyContainer.spec.tsx +7 -7
- package/tests/components/feedback/notification/NotificationBell.spec.tsx +9 -9
- package/tests/components/feedback/print/Print.spec.tsx +4 -4
- package/tests/components/form-control/Button.spec.tsx +18 -18
- package/tests/components/form-control/checkbox/Checkbox.spec.tsx +20 -20
- package/tests/components/form-control/checkbox/CheckboxGroup.spec.tsx +12 -12
- package/tests/components/form-control/checkbox/Radio.spec.tsx +21 -21
- package/tests/components/form-control/checkbox/RadioGroup.spec.tsx +12 -12
- package/tests/components/form-control/color-picker/ColorPicker.spec.tsx +10 -10
- package/tests/components/form-control/combobox/Combobox.spec.tsx +16 -16
- package/tests/components/form-control/combobox/ComboboxItem.spec.tsx +7 -7
- package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +24 -24
- package/tests/components/form-control/field/DatePicker.spec.tsx +50 -50
- package/tests/components/form-control/field/DateTimePicker.spec.tsx +47 -47
- package/tests/components/form-control/field/NumberInput.spec.tsx +54 -54
- package/tests/components/form-control/field/TextInput.spec.tsx +49 -49
- package/tests/components/form-control/field/Textarea.spec.tsx +33 -33
- package/tests/components/form-control/field/TimePicker.spec.tsx +42 -42
- package/tests/components/form-control/numpad/Numpad.spec.tsx +40 -40
- package/tests/components/form-control/select/Select.spec.tsx +9 -9
- package/tests/components/form-control/select/SelectItem.spec.tsx +10 -10
- package/tests/helpers/createAppStructure.spec.tsx +57 -57
- package/tests/helpers/mergeStyles.spec.ts +31 -31
|
@@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
3
3
|
import { createSignal } from "solid-js";
|
|
4
4
|
import { Dropdown } from "../../../src/components/disclosure/Dropdown";
|
|
5
5
|
|
|
6
|
-
describe("Dropdown
|
|
6
|
+
describe("Dropdown", () => {
|
|
7
7
|
beforeEach(() => {
|
|
8
8
|
vi.stubGlobal("innerWidth", 1024);
|
|
9
9
|
vi.stubGlobal("innerHeight", 768);
|
|
@@ -15,8 +15,8 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
15
15
|
vi.unstubAllGlobals();
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
describe("Trigger/Content
|
|
19
|
-
it("
|
|
18
|
+
describe("Trigger/Content structure", () => {
|
|
19
|
+
it("renders Content on Trigger click", async () => {
|
|
20
20
|
render(() => (
|
|
21
21
|
<Dropdown>
|
|
22
22
|
<Dropdown.Trigger>
|
|
@@ -38,7 +38,7 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
it("
|
|
41
|
+
it("closes on second Trigger click", () => {
|
|
42
42
|
const [open, setOpen] = createSignal(false);
|
|
43
43
|
const handleOpenChange = vi.fn((v: boolean) => setOpen(v));
|
|
44
44
|
|
|
@@ -61,7 +61,7 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
61
61
|
expect(handleOpenChange).toHaveBeenCalledWith(false);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it("
|
|
64
|
+
it("ignores Trigger click when disabled", () => {
|
|
65
65
|
const [open, setOpen] = createSignal(false);
|
|
66
66
|
const handleOpenChange = vi.fn((v: boolean) => setOpen(v));
|
|
67
67
|
|
|
@@ -81,8 +81,8 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
describe("
|
|
85
|
-
it("open prop
|
|
84
|
+
describe("controlled mode", () => {
|
|
85
|
+
it("is controlled by open prop", async () => {
|
|
86
86
|
const [open, setOpen] = createSignal(false);
|
|
87
87
|
|
|
88
88
|
render(() => (
|
|
@@ -106,8 +106,8 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
describe("Context menu (Trigger
|
|
110
|
-
it("position
|
|
109
|
+
describe("Context menu (no Trigger)", () => {
|
|
110
|
+
it("sets position via position prop", async () => {
|
|
111
111
|
render(() => (
|
|
112
112
|
<Dropdown position={{ x: 300, y: 200 }} open={true}>
|
|
113
113
|
<Dropdown.Content>
|
|
@@ -124,8 +124,8 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
124
124
|
});
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
describe("
|
|
128
|
-
it("
|
|
127
|
+
describe("close detection", () => {
|
|
128
|
+
it("closes on outside pointerdown", async () => {
|
|
129
129
|
const handleOpenChange = vi.fn();
|
|
130
130
|
|
|
131
131
|
render(() => (
|
|
@@ -150,7 +150,7 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
150
150
|
expect(handleOpenChange).toHaveBeenCalledWith(false);
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
-
it("Escape
|
|
153
|
+
it("closes on Escape key", async () => {
|
|
154
154
|
const handleOpenChange = vi.fn();
|
|
155
155
|
|
|
156
156
|
render(() => (
|
|
@@ -174,7 +174,7 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
174
174
|
});
|
|
175
175
|
|
|
176
176
|
describe("maxHeight", () => {
|
|
177
|
-
it("
|
|
177
|
+
it("defaults to 300px", async () => {
|
|
178
178
|
render(() => (
|
|
179
179
|
<Dropdown open={true}>
|
|
180
180
|
<Dropdown.Trigger>
|
|
@@ -192,7 +192,7 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
192
192
|
});
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
it("
|
|
195
|
+
it("applies custom value", async () => {
|
|
196
196
|
render(() => (
|
|
197
197
|
<Dropdown open={true} maxHeight={500}>
|
|
198
198
|
<Dropdown.Trigger>
|
|
@@ -210,4 +210,124 @@ describe("Dropdown 컴포넌트", () => {
|
|
|
210
210
|
});
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
|
+
|
|
214
|
+
describe("keyboardNav tabbable navigation", () => {
|
|
215
|
+
it("ArrowDown from trigger focuses first tabbable in popup (input, not list item)", async () => {
|
|
216
|
+
const [open, setOpen] = createSignal(true);
|
|
217
|
+
|
|
218
|
+
render(() => (
|
|
219
|
+
<Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
|
|
220
|
+
<Dropdown.Trigger>
|
|
221
|
+
<button data-testid="trigger">trigger</button>
|
|
222
|
+
</Dropdown.Trigger>
|
|
223
|
+
<Dropdown.Content>
|
|
224
|
+
<input data-testid="search" />
|
|
225
|
+
<button data-testid="action-btn" type="button">action</button>
|
|
226
|
+
<button data-list-item data-testid="item1" type="button">item1</button>
|
|
227
|
+
</Dropdown.Content>
|
|
228
|
+
</Dropdown>
|
|
229
|
+
));
|
|
230
|
+
|
|
231
|
+
await waitFor(() => {
|
|
232
|
+
expect(document.querySelector("[data-dropdown]")).not.toBeNull();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const triggerWrapper = document.querySelector("[data-dropdown-trigger]") as HTMLElement;
|
|
236
|
+
triggerWrapper.focus();
|
|
237
|
+
|
|
238
|
+
fireEvent.keyDown(triggerWrapper, { key: "ArrowDown" });
|
|
239
|
+
|
|
240
|
+
const search = document.querySelector('[data-testid="search"]') as HTMLElement;
|
|
241
|
+
expect(document.activeElement).toBe(search);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("ArrowDown from input focuses next tabbable (button)", async () => {
|
|
245
|
+
const [open, setOpen] = createSignal(true);
|
|
246
|
+
|
|
247
|
+
render(() => (
|
|
248
|
+
<Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
|
|
249
|
+
<Dropdown.Trigger>
|
|
250
|
+
<button data-testid="trigger">trigger</button>
|
|
251
|
+
</Dropdown.Trigger>
|
|
252
|
+
<Dropdown.Content>
|
|
253
|
+
<input data-testid="search" />
|
|
254
|
+
<button data-testid="action-btn" type="button">action</button>
|
|
255
|
+
<button data-list-item data-testid="item1" type="button">item1</button>
|
|
256
|
+
</Dropdown.Content>
|
|
257
|
+
</Dropdown>
|
|
258
|
+
));
|
|
259
|
+
|
|
260
|
+
await waitFor(() => {
|
|
261
|
+
expect(document.querySelector("[data-dropdown]")).not.toBeNull();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const search = document.querySelector('[data-testid="search"]') as HTMLElement;
|
|
265
|
+
search.focus();
|
|
266
|
+
|
|
267
|
+
const popup = document.querySelector("[data-dropdown]") as HTMLElement;
|
|
268
|
+
fireEvent.keyDown(popup, { key: "ArrowDown" });
|
|
269
|
+
|
|
270
|
+
const actionBtn = document.querySelector('[data-testid="action-btn"]') as HTMLElement;
|
|
271
|
+
expect(document.activeElement).toBe(actionBtn);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("ArrowUp from input focuses trigger (no prev tabbable, dir=down)", async () => {
|
|
275
|
+
const [open, setOpen] = createSignal(true);
|
|
276
|
+
|
|
277
|
+
render(() => (
|
|
278
|
+
<Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
|
|
279
|
+
<Dropdown.Trigger>
|
|
280
|
+
<button data-testid="trigger">trigger</button>
|
|
281
|
+
</Dropdown.Trigger>
|
|
282
|
+
<Dropdown.Content>
|
|
283
|
+
<input data-testid="search" />
|
|
284
|
+
<button data-list-item data-testid="item1" type="button">item1</button>
|
|
285
|
+
</Dropdown.Content>
|
|
286
|
+
</Dropdown>
|
|
287
|
+
));
|
|
288
|
+
|
|
289
|
+
await waitFor(() => {
|
|
290
|
+
expect(document.querySelector("[data-dropdown]")).not.toBeNull();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const search = document.querySelector('[data-testid="search"]') as HTMLElement;
|
|
294
|
+
search.focus();
|
|
295
|
+
|
|
296
|
+
const popup = document.querySelector("[data-dropdown]") as HTMLElement;
|
|
297
|
+
fireEvent.keyDown(popup, { key: "ArrowUp" });
|
|
298
|
+
|
|
299
|
+
const triggerWrapper = document.querySelector("[data-dropdown-trigger]") as HTMLElement;
|
|
300
|
+
expect(document.activeElement).toBe(triggerWrapper);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("ArrowUp from action button focuses prev tabbable (input)", async () => {
|
|
304
|
+
const [open, setOpen] = createSignal(true);
|
|
305
|
+
|
|
306
|
+
render(() => (
|
|
307
|
+
<Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
|
|
308
|
+
<Dropdown.Trigger>
|
|
309
|
+
<button data-testid="trigger">trigger</button>
|
|
310
|
+
</Dropdown.Trigger>
|
|
311
|
+
<Dropdown.Content>
|
|
312
|
+
<input data-testid="search" />
|
|
313
|
+
<button data-testid="action-btn" type="button">action</button>
|
|
314
|
+
<button data-list-item data-testid="item1" type="button">item1</button>
|
|
315
|
+
</Dropdown.Content>
|
|
316
|
+
</Dropdown>
|
|
317
|
+
));
|
|
318
|
+
|
|
319
|
+
await waitFor(() => {
|
|
320
|
+
expect(document.querySelector("[data-dropdown]")).not.toBeNull();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const actionBtn = document.querySelector('[data-testid="action-btn"]') as HTMLElement;
|
|
324
|
+
actionBtn.focus();
|
|
325
|
+
|
|
326
|
+
const popup = document.querySelector("[data-dropdown]") as HTMLElement;
|
|
327
|
+
fireEvent.keyDown(popup, { key: "ArrowUp" });
|
|
328
|
+
|
|
329
|
+
const search = document.querySelector('[data-testid="search"]') as HTMLElement;
|
|
330
|
+
expect(document.activeElement).toBe(search);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
213
333
|
});
|
|
@@ -3,9 +3,9 @@ import { describe, it, expect, vi } from "vitest";
|
|
|
3
3
|
import { createSignal } from "solid-js";
|
|
4
4
|
import { Tabs } from "../../../src/components/disclosure/Tabs";
|
|
5
5
|
|
|
6
|
-
describe("Tabs
|
|
6
|
+
describe("Tabs", () => {
|
|
7
7
|
describe("basic rendering", () => {
|
|
8
|
-
it("tablist role
|
|
8
|
+
it("renders with tablist role", () => {
|
|
9
9
|
const { getByRole } = render(() => (
|
|
10
10
|
<Tabs>
|
|
11
11
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -14,7 +14,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
14
14
|
expect(getByRole("tablist")).toBeTruthy();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it("Tabs.Tab
|
|
17
|
+
it("renders Tabs.Tab with tab role", () => {
|
|
18
18
|
const { getByRole } = render(() => (
|
|
19
19
|
<Tabs>
|
|
20
20
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -23,7 +23,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
23
23
|
expect(getByRole("tab")).toBeTruthy();
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it("children
|
|
26
|
+
it("renders children", () => {
|
|
27
27
|
const { getByText } = render(() => (
|
|
28
28
|
<Tabs>
|
|
29
29
|
<Tabs.Tab value="a">탭 A</Tabs.Tab>
|
|
@@ -35,8 +35,8 @@ describe("Tabs 컴포넌트", () => {
|
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
describe("
|
|
39
|
-
it("
|
|
38
|
+
describe("selection behavior", () => {
|
|
39
|
+
it("sets aria-selected to true on click", () => {
|
|
40
40
|
const { getAllByRole } = render(() => (
|
|
41
41
|
<Tabs>
|
|
42
42
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -50,7 +50,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
50
50
|
expect(tabs[1].getAttribute("aria-selected")).toBe("false");
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
it("
|
|
53
|
+
it("changes selection on different tab click", () => {
|
|
54
54
|
const { getAllByRole } = render(() => (
|
|
55
55
|
<Tabs value="a">
|
|
56
56
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -64,7 +64,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
64
64
|
expect(tabs[0].getAttribute("aria-selected")).toBe("false");
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
it("disabled
|
|
67
|
+
it("does not select disabled tab on click", () => {
|
|
68
68
|
const handleChange = vi.fn();
|
|
69
69
|
const { getAllByRole } = render(() => (
|
|
70
70
|
<Tabs onValueChange={handleChange}>
|
|
@@ -80,8 +80,8 @@ describe("Tabs 컴포넌트", () => {
|
|
|
80
80
|
});
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
describe("
|
|
84
|
-
it("Space
|
|
83
|
+
describe("keyboard behavior", () => {
|
|
84
|
+
it("selects tab with Space key", () => {
|
|
85
85
|
const { getAllByRole } = render(() => (
|
|
86
86
|
<Tabs>
|
|
87
87
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -93,7 +93,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
93
93
|
expect(getAllByRole("tab")[0].getAttribute("aria-selected")).toBe("true");
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
it("Enter
|
|
96
|
+
it("selects tab with Enter key", () => {
|
|
97
97
|
const { getAllByRole } = render(() => (
|
|
98
98
|
<Tabs>
|
|
99
99
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -106,8 +106,8 @@ describe("Tabs 컴포넌트", () => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
describe("controlled
|
|
110
|
-
it("value prop
|
|
109
|
+
describe("controlled pattern", () => {
|
|
110
|
+
it("reflects value prop as selected state", () => {
|
|
111
111
|
const { getAllByRole } = render(() => (
|
|
112
112
|
<Tabs value="b">
|
|
113
113
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -119,7 +119,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
119
119
|
expect(getAllByRole("tab")[1].getAttribute("aria-selected")).toBe("true");
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
it("onValueChange
|
|
122
|
+
it("calls onValueChange on click", () => {
|
|
123
123
|
const handleChange = vi.fn();
|
|
124
124
|
const { getAllByRole } = render(() => (
|
|
125
125
|
<Tabs value="a" onValueChange={handleChange}>
|
|
@@ -132,7 +132,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
132
132
|
expect(handleChange).toHaveBeenCalledWith("b");
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
it("
|
|
135
|
+
it("updates when external state changes", () => {
|
|
136
136
|
const [value, setValue] = createSignal("a");
|
|
137
137
|
const { getAllByRole } = render(() => (
|
|
138
138
|
<Tabs value={value()} onValueChange={setValue}>
|
|
@@ -149,8 +149,8 @@ describe("Tabs 컴포넌트", () => {
|
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
describe("
|
|
153
|
-
it("
|
|
152
|
+
describe("size", () => {
|
|
153
|
+
it("applies different styles per size prop", () => {
|
|
154
154
|
const { getAllByRole: getDefault } = render(() => (
|
|
155
155
|
<Tabs>
|
|
156
156
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -167,7 +167,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
describe("accessibility", () => {
|
|
170
|
-
it("
|
|
170
|
+
it("sets aria-disabled on disabled tab", () => {
|
|
171
171
|
const { getAllByRole } = render(() => (
|
|
172
172
|
<Tabs>
|
|
173
173
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -180,7 +180,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
180
180
|
expect(getAllByRole("tab")[1].getAttribute("aria-disabled")).toBe("true");
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
-
it("
|
|
183
|
+
it("sets tabIndex to -1 on disabled tab", () => {
|
|
184
184
|
const { getAllByRole } = render(() => (
|
|
185
185
|
<Tabs>
|
|
186
186
|
<Tabs.Tab value="a">A</Tabs.Tab>
|
|
@@ -195,7 +195,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
195
195
|
});
|
|
196
196
|
|
|
197
197
|
describe("class merging", () => {
|
|
198
|
-
it("
|
|
198
|
+
it("merges custom class on Tabs", () => {
|
|
199
199
|
const { getByRole } = render(() => (
|
|
200
200
|
// eslint-disable-next-line tailwindcss/no-custom-classname
|
|
201
201
|
<Tabs class="my-tab-class">
|
|
@@ -205,7 +205,7 @@ describe("Tabs 컴포넌트", () => {
|
|
|
205
205
|
expect(getByRole("tablist").classList.contains("my-tab-class")).toBe(true);
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
-
it("
|
|
208
|
+
it("merges custom class on Tabs.Tab", () => {
|
|
209
209
|
const { getByRole } = render(() => (
|
|
210
210
|
<Tabs>
|
|
211
211
|
{/* eslint-disable-next-line tailwindcss/no-custom-classname */}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
registerDialog,
|
|
4
|
+
unregisterDialog,
|
|
5
|
+
getTopmostDialog,
|
|
6
|
+
} from "../../../src/components/disclosure/dialogZIndex";
|
|
7
|
+
|
|
8
|
+
describe("getTopmostDialog", () => {
|
|
9
|
+
let el1: HTMLElement;
|
|
10
|
+
let el2: HTMLElement;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
el1 = document.createElement("div");
|
|
14
|
+
el2 = document.createElement("div");
|
|
15
|
+
// Clean up any leftover registrations
|
|
16
|
+
unregisterDialog(el1);
|
|
17
|
+
unregisterDialog(el2);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns null when no dialogs are registered", () => {
|
|
21
|
+
expect(getTopmostDialog()).toBeNull();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("returns the only registered dialog", () => {
|
|
25
|
+
registerDialog(el1);
|
|
26
|
+
expect(getTopmostDialog()).toBe(el1);
|
|
27
|
+
unregisterDialog(el1);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("returns the last registered dialog when multiple are open", () => {
|
|
31
|
+
registerDialog(el1);
|
|
32
|
+
registerDialog(el2);
|
|
33
|
+
expect(getTopmostDialog()).toBe(el2);
|
|
34
|
+
unregisterDialog(el2);
|
|
35
|
+
unregisterDialog(el1);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("returns previous dialog after topmost is unregistered", () => {
|
|
39
|
+
registerDialog(el1);
|
|
40
|
+
registerDialog(el2);
|
|
41
|
+
unregisterDialog(el2);
|
|
42
|
+
expect(getTopmostDialog()).toBe(el1);
|
|
43
|
+
unregisterDialog(el1);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
|
|
|
2
2
|
import { describe, it, expect } from "vitest";
|
|
3
3
|
import { Alert } from "../../../src/components/display/Alert";
|
|
4
4
|
|
|
5
|
-
describe("Alert
|
|
5
|
+
describe("Alert", () => {
|
|
6
6
|
describe("basic rendering", () => {
|
|
7
|
-
it("children
|
|
7
|
+
it("renders children", () => {
|
|
8
8
|
const { getByText } = render(() => <Alert>This is a note</Alert>);
|
|
9
9
|
expect(getByText("This is a note")).toBeTruthy();
|
|
10
10
|
});
|
|
@@ -16,8 +16,8 @@ describe("Alert 컴포넌트", () => {
|
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
describe("theme
|
|
20
|
-
it("
|
|
19
|
+
describe("theme prop", () => {
|
|
20
|
+
it("applies different styles per theme", () => {
|
|
21
21
|
const { container: defaultContainer } = render(() => <Alert>Content</Alert>);
|
|
22
22
|
const { container: themedContainer } = render(() => <Alert theme="danger">Content</Alert>);
|
|
23
23
|
|
|
@@ -3,28 +3,28 @@ import { describe, it, expect } from "vitest";
|
|
|
3
3
|
import { createSignal } from "solid-js";
|
|
4
4
|
import { Barcode } from "../../../src/components/display/Barcode";
|
|
5
5
|
|
|
6
|
-
describe("Barcode
|
|
6
|
+
describe("Barcode", () => {
|
|
7
7
|
describe("basic rendering", () => {
|
|
8
|
-
it("data-barcode
|
|
8
|
+
it("renders with data-barcode attribute", () => {
|
|
9
9
|
const { container } = render(() => <Barcode type="qrcode" value="test" />);
|
|
10
10
|
expect(container.querySelector("[data-barcode]")).toBeTruthy();
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
it("value
|
|
13
|
+
it("renders SVG when value is provided", () => {
|
|
14
14
|
const { container } = render(() => <Barcode type="qrcode" value="hello" />);
|
|
15
15
|
const el = container.querySelector("[data-barcode]")!;
|
|
16
16
|
expect(el.querySelector("svg")).toBeTruthy();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it("value
|
|
19
|
+
it("renders empty when value is absent", () => {
|
|
20
20
|
const { container } = render(() => <Barcode type="qrcode" />);
|
|
21
21
|
const el = container.querySelector("[data-barcode]")!;
|
|
22
22
|
expect(el.innerHTML).toBe("");
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
describe("
|
|
27
|
-
it("
|
|
26
|
+
describe("reactivity", () => {
|
|
27
|
+
it("updates SVG when value changes", () => {
|
|
28
28
|
const [value, setValue] = createSignal("first");
|
|
29
29
|
const { container } = render(() => <Barcode type="qrcode" value={value()} />);
|
|
30
30
|
const el = container.querySelector("[data-barcode]")!;
|
|
@@ -38,7 +38,7 @@ describe("Barcode 컴포넌트", () => {
|
|
|
38
38
|
expect(firstSvg).not.toBe(secondSvg);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
it("value
|
|
41
|
+
it("removes SVG when value changes to empty string", () => {
|
|
42
42
|
const [value, setValue] = createSignal("hello");
|
|
43
43
|
const { container } = render(() => <Barcode type="qrcode" value={value()} />);
|
|
44
44
|
const el = container.querySelector("[data-barcode]")!;
|
|
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
|
|
|
2
2
|
import { describe, it, expect } from "vitest";
|
|
3
3
|
import { Card } from "../../../src/components/display/Card";
|
|
4
4
|
|
|
5
|
-
describe("Card
|
|
5
|
+
describe("Card", () => {
|
|
6
6
|
describe("basic rendering", () => {
|
|
7
|
-
it("children
|
|
7
|
+
it("renders children", () => {
|
|
8
8
|
const { getByText } = render(() => <Card>Card Content</Card>);
|
|
9
9
|
expect(getByText("Card Content")).toBeTruthy();
|
|
10
10
|
});
|
|
@@ -32,7 +32,7 @@ describe("Card 컴포넌트", () => {
|
|
|
32
32
|
expect(card.getAttribute("data-testid")).toBe("test-card");
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
it("id
|
|
35
|
+
it("passes id attribute", () => {
|
|
36
36
|
const { container } = render(() => <Card id="my-card">Content</Card>);
|
|
37
37
|
const card = container.firstChild as HTMLElement;
|
|
38
38
|
expect(card.id).toBe("my-card");
|
|
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
|
|
|
2
2
|
import { describe, it, expect } from "vitest";
|
|
3
3
|
import { Link } from "../../../src/components/display/Link";
|
|
4
4
|
|
|
5
|
-
describe("Link
|
|
5
|
+
describe("Link", () => {
|
|
6
6
|
describe("basic rendering", () => {
|
|
7
|
-
it("children
|
|
7
|
+
it("renders children", () => {
|
|
8
8
|
const { getByText } = render(() => <Link href="https://example.com">링크</Link>);
|
|
9
9
|
expect(getByText("링크")).toBeTruthy();
|
|
10
10
|
});
|
|
@@ -16,14 +16,14 @@ describe("Link 컴포넌트", () => {
|
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
describe("href
|
|
20
|
-
it("href
|
|
19
|
+
describe("href prop", () => {
|
|
20
|
+
it("passes href to anchor element", () => {
|
|
21
21
|
const { container } = render(() => <Link href="https://example.com">링크</Link>);
|
|
22
22
|
const link = container.firstChild as HTMLAnchorElement;
|
|
23
23
|
expect(link.getAttribute("href")).toBe("https://example.com");
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it("target
|
|
26
|
+
it("passes target attribute", () => {
|
|
27
27
|
const { container } = render(() => (
|
|
28
28
|
<Link href="https://example.com" target="_blank">
|
|
29
29
|
링크
|
|
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
|
|
|
2
2
|
import { describe, it, expect } from "vitest";
|
|
3
3
|
import { Tag } from "../../../src/components/display/Tag";
|
|
4
4
|
|
|
5
|
-
describe("Tag
|
|
5
|
+
describe("Tag", () => {
|
|
6
6
|
describe("basic rendering", () => {
|
|
7
|
-
it("children
|
|
7
|
+
it("renders children", () => {
|
|
8
8
|
const { getByText } = render(() => <Tag>New</Tag>);
|
|
9
9
|
expect(getByText("New")).toBeTruthy();
|
|
10
10
|
});
|
|
@@ -16,8 +16,8 @@ describe("Tag 컴포넌트", () => {
|
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
describe("theme
|
|
20
|
-
it("
|
|
19
|
+
describe("theme prop", () => {
|
|
20
|
+
it("applies different styles per theme", () => {
|
|
21
21
|
const { container: defaultContainer } = render(() => <Tag>Tag</Tag>);
|
|
22
22
|
const { container: themedContainer } = render(() => <Tag theme="danger">Tag</Tag>);
|
|
23
23
|
|
|
@@ -22,7 +22,7 @@ function TestApp() {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
describe("AddressSearchContent", () => {
|
|
25
|
-
it("
|
|
25
|
+
it("mounts and renders Daum Postcode widget inside content area", async () => {
|
|
26
26
|
const { getByTestId } = render(() => (
|
|
27
27
|
<DialogProvider>
|
|
28
28
|
<TestApp />
|
|
@@ -31,12 +31,12 @@ describe("AddressSearchContent", () => {
|
|
|
31
31
|
|
|
32
32
|
getByTestId("open-btn").click();
|
|
33
33
|
|
|
34
|
-
// Daum Postcode
|
|
34
|
+
// wait for Daum Postcode script load + widget embed
|
|
35
35
|
await waitFor(
|
|
36
36
|
() => {
|
|
37
37
|
const content = document.querySelector("[data-address-content]");
|
|
38
38
|
expect(content).not.toBeNull();
|
|
39
|
-
// Daum Postcode
|
|
39
|
+
// once the Daum Postcode widget is embedded, content has child elements
|
|
40
40
|
expect(content!.children.length).toBeGreaterThan(0);
|
|
41
41
|
},
|
|
42
42
|
{ timeout: 10000 },
|