@simplysm/solid 13.0.70 → 13.0.71
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/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/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
|
@@ -11,7 +11,7 @@ import type { AppPerm } from "../../../../src/helpers/createAppStructure";
|
|
|
11
11
|
import { I18nProvider } from "../../../../src/providers/i18n/I18nContext";
|
|
12
12
|
import { ConfigProvider } from "../../../../src/providers/ConfigContext";
|
|
13
13
|
|
|
14
|
-
// ---
|
|
14
|
+
// --- test data ---
|
|
15
15
|
|
|
16
16
|
const sampleItems: AppPerm[] = [
|
|
17
17
|
{
|
|
@@ -32,11 +32,11 @@ const sampleItems: AppPerm[] = [
|
|
|
32
32
|
];
|
|
33
33
|
|
|
34
34
|
// =====================
|
|
35
|
-
// Part 1:
|
|
35
|
+
// Part 1: utility function tests
|
|
36
36
|
// =====================
|
|
37
37
|
|
|
38
38
|
describe("collectAllPerms", () => {
|
|
39
|
-
it("
|
|
39
|
+
it("collects all unique perm types from the tree", () => {
|
|
40
40
|
const result = collectAllPerms(sampleItems);
|
|
41
41
|
expect(result).toContain("use");
|
|
42
42
|
expect(result).toContain("edit");
|
|
@@ -44,12 +44,12 @@ describe("collectAllPerms", () => {
|
|
|
44
44
|
expect(result).toHaveLength(3);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it("
|
|
47
|
+
it("returns empty result for empty array", () => {
|
|
48
48
|
const result = collectAllPerms([]);
|
|
49
49
|
expect(result).toEqual([]);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
it("
|
|
52
|
+
it("collects perms from nested items", () => {
|
|
53
53
|
const items: AppPerm[] = [
|
|
54
54
|
{
|
|
55
55
|
title: "루트",
|
|
@@ -71,32 +71,32 @@ describe("collectAllPerms", () => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
describe("filterByModules", () => {
|
|
74
|
-
it("
|
|
74
|
+
it("returns all items when modules is undefined", () => {
|
|
75
75
|
const result = filterByModules(sampleItems, undefined);
|
|
76
76
|
expect(result).toBe(sampleItems);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
it("
|
|
79
|
+
it("excludes items with no intersection with active modules", () => {
|
|
80
80
|
const result = filterByModules(sampleItems, ["other"]);
|
|
81
|
-
// "시스템"
|
|
81
|
+
// "시스템" has modules: ["admin"], no intersection with "other" → excluded
|
|
82
82
|
const titles = result.map((i) => i.title);
|
|
83
83
|
expect(titles).toContain("사용자 관리");
|
|
84
84
|
expect(titles).not.toContain("시스템");
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
it("
|
|
87
|
+
it("always includes items with no modules set", () => {
|
|
88
88
|
const result = filterByModules(sampleItems, ["admin"]);
|
|
89
|
-
// "사용자 관리"
|
|
89
|
+
// "사용자 관리" has no modules set → always included
|
|
90
90
|
const titles = result.map((i) => i.title);
|
|
91
91
|
expect(titles).toContain("사용자 관리");
|
|
92
92
|
expect(titles).toContain("시스템");
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
it("
|
|
95
|
+
it("removes group node (no perms) when all children are filtered out", () => {
|
|
96
96
|
const items: AppPerm[] = [
|
|
97
97
|
{
|
|
98
98
|
title: "그룹",
|
|
99
|
-
// perms
|
|
99
|
+
// no perms → group node
|
|
100
100
|
children: [
|
|
101
101
|
{ title: "항목A", href: "/a", perms: ["use"], modules: ["admin"] },
|
|
102
102
|
{ title: "항목B", href: "/b", perms: ["use"], modules: ["admin"] },
|
|
@@ -109,19 +109,19 @@ describe("filterByModules", () => {
|
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
describe("changePermCheck", () => {
|
|
112
|
-
it("
|
|
112
|
+
it("sets perm on a leaf item", () => {
|
|
113
113
|
const result = changePermCheck({}, sampleItems[1], "use", true);
|
|
114
114
|
expect(result["/system/use"]).toBe(true);
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
it("
|
|
117
|
+
it("checking parent checks all children (cascading down)", () => {
|
|
118
118
|
const result = changePermCheck({}, sampleItems[0], "use", true);
|
|
119
119
|
expect(result["/user/use"]).toBe(true);
|
|
120
120
|
expect(result["/user/permission/use"]).toBe(true);
|
|
121
121
|
expect(result["/user/list/use"]).toBe(true);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
it("
|
|
124
|
+
it("unchecking parent unchecks all children (cascading down)", () => {
|
|
125
125
|
const initial: Record<string, boolean> = {
|
|
126
126
|
"/user/use": true,
|
|
127
127
|
"/user/permission/use": true,
|
|
@@ -133,7 +133,7 @@ describe("changePermCheck", () => {
|
|
|
133
133
|
expect(result["/user/list/use"]).toBe(false);
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
it("
|
|
136
|
+
it("unchecking the base perm (perms[0]) unchecks all other perms", () => {
|
|
137
137
|
const initial: Record<string, boolean> = {
|
|
138
138
|
"/user/use": true,
|
|
139
139
|
"/user/edit": true,
|
|
@@ -144,69 +144,69 @@ describe("changePermCheck", () => {
|
|
|
144
144
|
"/user/list/edit": true,
|
|
145
145
|
};
|
|
146
146
|
const result = changePermCheck(initial, sampleItems[0], "use", false);
|
|
147
|
-
//
|
|
147
|
+
// unchecking base perm "use" → "edit", "approve" are also unchecked
|
|
148
148
|
expect(result["/user/edit"]).toBe(false);
|
|
149
149
|
expect(result["/user/permission/edit"]).toBe(false);
|
|
150
150
|
expect(result["/user/permission/approve"]).toBe(false);
|
|
151
151
|
expect(result["/user/list/edit"]).toBe(false);
|
|
152
152
|
});
|
|
153
153
|
|
|
154
|
-
it("
|
|
155
|
-
//
|
|
154
|
+
it("checking non-base perm cascades to children, skipping items where base perm is off", () => {
|
|
155
|
+
// parent (/user) base perm "use" is off, but children's "use" is on
|
|
156
156
|
const initial: Record<string, boolean> = {
|
|
157
157
|
"/user/permission/use": true,
|
|
158
158
|
"/user/list/use": true,
|
|
159
159
|
};
|
|
160
160
|
const result = changePermCheck(initial, sampleItems[0], "edit", true);
|
|
161
|
-
//
|
|
161
|
+
// parent (/user): use is off → skip setting edit
|
|
162
162
|
expect(result["/user/edit"]).toBeUndefined();
|
|
163
|
-
//
|
|
163
|
+
// children: use is on → edit is set
|
|
164
164
|
expect(result["/user/permission/edit"]).toBe(true);
|
|
165
165
|
expect(result["/user/list/edit"]).toBe(true);
|
|
166
166
|
});
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
// =====================
|
|
170
|
-
// Part 2:
|
|
170
|
+
// Part 2: component rendering tests
|
|
171
171
|
// =====================
|
|
172
172
|
|
|
173
|
-
describe("PermissionTable
|
|
173
|
+
describe("PermissionTable component", () => {
|
|
174
174
|
describe("basic rendering", () => {
|
|
175
|
-
it("
|
|
175
|
+
it("renders as DataSheet (div with data-sheet attribute)", () => {
|
|
176
176
|
const { container } = render(() => <PermissionTable items={sampleItems} />);
|
|
177
|
-
const wrapper = container.querySelector("[data-
|
|
177
|
+
const wrapper = container.querySelector("[data-sheet]");
|
|
178
178
|
expect(wrapper).toBeTruthy();
|
|
179
179
|
expect(wrapper!.tagName).toBe("DIV");
|
|
180
180
|
});
|
|
181
181
|
|
|
182
|
-
it("
|
|
182
|
+
it("renders a table inside DataSheet", () => {
|
|
183
183
|
const { container } = render(() => <PermissionTable items={sampleItems} />);
|
|
184
184
|
const table = container.querySelector("[data-sheet] table");
|
|
185
185
|
expect(table).toBeTruthy();
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
it("
|
|
188
|
+
it("displays perm type columns in header", () => {
|
|
189
189
|
const { getByText } = render(() => <PermissionTable items={sampleItems} />);
|
|
190
190
|
expect(getByText("use")).toBeTruthy();
|
|
191
191
|
expect(getByText("edit")).toBeTruthy();
|
|
192
192
|
expect(getByText("approve")).toBeTruthy();
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
it("
|
|
195
|
+
it("displays item titles", () => {
|
|
196
196
|
const { getByText } = render(() => <PermissionTable items={sampleItems} />);
|
|
197
197
|
expect(getByText("사용자 관리")).toBeTruthy();
|
|
198
198
|
expect(getByText("시스템")).toBeTruthy();
|
|
199
199
|
});
|
|
200
200
|
|
|
201
|
-
it("
|
|
201
|
+
it("child items are expanded by default", () => {
|
|
202
202
|
const { getByText } = render(() => <PermissionTable items={sampleItems} />);
|
|
203
203
|
expect(getByText("권한 설정")).toBeTruthy();
|
|
204
204
|
expect(getByText("사용자 목록")).toBeTruthy();
|
|
205
205
|
});
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
-
describe("
|
|
209
|
-
it("
|
|
208
|
+
describe("checkbox interaction", () => {
|
|
209
|
+
it("clicking a checkbox calls onValueChange", () => {
|
|
210
210
|
const handleChange = vi.fn();
|
|
211
211
|
const { getAllByRole } = render(() => (
|
|
212
212
|
<ConfigProvider clientName="test"><I18nProvider>
|
|
@@ -215,12 +215,12 @@ describe("PermissionTable 컴포넌트", () => {
|
|
|
215
215
|
));
|
|
216
216
|
|
|
217
217
|
const checkboxes = getAllByRole("checkbox");
|
|
218
|
-
//
|
|
218
|
+
// click the first checkbox
|
|
219
219
|
fireEvent.click(checkboxes[0]);
|
|
220
220
|
expect(handleChange).toHaveBeenCalled();
|
|
221
221
|
});
|
|
222
222
|
|
|
223
|
-
it("controlled
|
|
223
|
+
it("controlled pattern: value prop is reflected in checkboxes", () => {
|
|
224
224
|
const [value, setValue] = createSignal<Record<string, boolean>>({
|
|
225
225
|
"/system/use": true,
|
|
226
226
|
});
|
|
@@ -232,43 +232,43 @@ describe("PermissionTable 컴포넌트", () => {
|
|
|
232
232
|
));
|
|
233
233
|
|
|
234
234
|
const checkboxes = getAllByRole("checkbox");
|
|
235
|
-
// "시스템"
|
|
235
|
+
// "시스템"'s "use" checkbox should be checked
|
|
236
236
|
const checkedBox = checkboxes.find((cb) => cb.getAttribute("aria-checked") === "true");
|
|
237
237
|
expect(checkedBox).toBeTruthy();
|
|
238
238
|
});
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
-
describe("
|
|
242
|
-
it("
|
|
241
|
+
describe("expand/collapse", () => {
|
|
242
|
+
it("rows with children have an expand/collapse toggle", () => {
|
|
243
243
|
const { getByText } = render(() => <PermissionTable items={sampleItems} />);
|
|
244
|
-
// "사용자 관리"
|
|
244
|
+
// find the row containing "사용자 관리" and check for expand toggle button
|
|
245
245
|
const titleEl = getByText("사용자 관리");
|
|
246
246
|
const row = titleEl.closest("tr")!;
|
|
247
247
|
const expandButton = row.querySelector("button");
|
|
248
248
|
expect(expandButton).toBeTruthy();
|
|
249
249
|
});
|
|
250
250
|
|
|
251
|
-
it("
|
|
251
|
+
it("clicking collapse button removes children from the DOM", () => {
|
|
252
252
|
const { getByText, queryByText } = render(() => <PermissionTable items={sampleItems} />);
|
|
253
253
|
|
|
254
|
-
//
|
|
254
|
+
// initially: children are visible (all expanded by default)
|
|
255
255
|
expect(getByText("권한 설정")).toBeTruthy();
|
|
256
256
|
expect(getByText("사용자 목록")).toBeTruthy();
|
|
257
257
|
|
|
258
|
-
//
|
|
258
|
+
// click collapse button (expand toggle on "사용자 관리" row)
|
|
259
259
|
const titleEl = getByText("사용자 관리");
|
|
260
260
|
const row = titleEl.closest("tr")!;
|
|
261
261
|
const expandButton = row.querySelector("button")!;
|
|
262
262
|
fireEvent.click(expandButton);
|
|
263
263
|
|
|
264
|
-
//
|
|
264
|
+
// children are removed from the DOM (Sheet does not render collapsed items)
|
|
265
265
|
expect(queryByText("권한 설정")).toBeNull();
|
|
266
266
|
expect(queryByText("사용자 목록")).toBeNull();
|
|
267
267
|
});
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
-
describe("
|
|
271
|
-
it("disabled prop
|
|
270
|
+
describe("disabled state", () => {
|
|
271
|
+
it("checkbox clicks are ignored when disabled prop is true", () => {
|
|
272
272
|
const handleChange = vi.fn();
|
|
273
273
|
const { getAllByRole } = render(() => (
|
|
274
274
|
<ConfigProvider clientName="test"><I18nProvider>
|
|
@@ -430,9 +430,9 @@ describe("SharedDataSelectList", () => {
|
|
|
430
430
|
});
|
|
431
431
|
});
|
|
432
432
|
|
|
433
|
-
// ─── header
|
|
433
|
+
// ─── header ────────────────────────────────────────────
|
|
434
434
|
|
|
435
|
-
describe("header
|
|
435
|
+
describe("header", () => {
|
|
436
436
|
it("header text is displayed when header is provided", () => {
|
|
437
437
|
const accessor = createMockAccessor(["Apple"]);
|
|
438
438
|
|
|
@@ -444,20 +444,5 @@ describe("SharedDataSelectList", () => {
|
|
|
444
444
|
|
|
445
445
|
expect(screen.getByText("과일 목록")).toBeTruthy();
|
|
446
446
|
});
|
|
447
|
-
|
|
448
|
-
it("management button is displayed when modal is provided", () => {
|
|
449
|
-
const accessor = createMockAccessor(["Apple"]);
|
|
450
|
-
|
|
451
|
-
renderWithDialog(() => (
|
|
452
|
-
<SharedDataSelectList data={accessor} header="과일" modal={() => <div>Modal</div>} required>
|
|
453
|
-
<SharedDataSelectList.ItemTemplate>{(item) => <>{item}</>}</SharedDataSelectList.ItemTemplate>
|
|
454
|
-
</SharedDataSelectList>
|
|
455
|
-
));
|
|
456
|
-
|
|
457
|
-
// Button is rendered (with IconExternalLink)
|
|
458
|
-
const headerArea = screen.getByText("과일").parentElement!;
|
|
459
|
-
const button = headerArea.querySelector("button");
|
|
460
|
-
expect(button).toBeTruthy();
|
|
461
|
-
});
|
|
462
447
|
});
|
|
463
448
|
});
|
|
@@ -5,7 +5,7 @@ import { BusyContainer } from "../../../../src/components/feedback/busy/BusyCont
|
|
|
5
5
|
|
|
6
6
|
describe("BusyContainer", () => {
|
|
7
7
|
describe("basic rendering", () => {
|
|
8
|
-
it("children
|
|
8
|
+
it("renders children", () => {
|
|
9
9
|
const { getByText } = render(() => (
|
|
10
10
|
<BusyContainer>
|
|
11
11
|
<span>Content</span>
|
|
@@ -14,7 +14,7 @@ describe("BusyContainer", () => {
|
|
|
14
14
|
expect(getByText("Content")).toBeTruthy();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it("
|
|
17
|
+
it("does not show overlay when busy is false", () => {
|
|
18
18
|
const { container } = render(() => (
|
|
19
19
|
<BusyContainer busy={false}>
|
|
20
20
|
<span>Content</span>
|
|
@@ -26,7 +26,7 @@ describe("BusyContainer", () => {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
describe("ready prop", () => {
|
|
29
|
-
it("
|
|
29
|
+
it("removes children from DOM when ready is false", () => {
|
|
30
30
|
const { queryByText } = render(() => (
|
|
31
31
|
<BusyContainer ready={false}>
|
|
32
32
|
<span>Content</span>
|
|
@@ -35,7 +35,7 @@ describe("BusyContainer", () => {
|
|
|
35
35
|
expect(queryByText("Content")).toBeNull();
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
it("ready
|
|
38
|
+
it("shows children when ready is true", () => {
|
|
39
39
|
const { getByText } = render(() => (
|
|
40
40
|
<BusyContainer ready={true}>
|
|
41
41
|
<span>Content</span>
|
|
@@ -44,7 +44,7 @@ describe("BusyContainer", () => {
|
|
|
44
44
|
expect(getByText("Content")).toBeTruthy();
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it("ready
|
|
47
|
+
it("shows children when ready is undefined", () => {
|
|
48
48
|
const { getByText } = render(() => (
|
|
49
49
|
<BusyContainer>
|
|
50
50
|
<span>Content</span>
|
|
@@ -53,7 +53,7 @@ describe("BusyContainer", () => {
|
|
|
53
53
|
expect(getByText("Content")).toBeTruthy();
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
it("ready
|
|
56
|
+
it("mounts overlay when ready is false", async () => {
|
|
57
57
|
const { container } = render(() => (
|
|
58
58
|
<BusyContainer ready={false}>
|
|
59
59
|
<span>Content</span>
|
|
@@ -65,7 +65,7 @@ describe("BusyContainer", () => {
|
|
|
65
65
|
expect(overlay).toBeTruthy();
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it("ready
|
|
68
|
+
it("shows children again when ready changes from false to true", () => {
|
|
69
69
|
const [ready, setReady] = createSignal(false);
|
|
70
70
|
const { queryByText } = render(() => (
|
|
71
71
|
<BusyContainer ready={ready()}>
|
|
@@ -15,7 +15,7 @@ describe("NotificationBell", () => {
|
|
|
15
15
|
vi.unstubAllGlobals();
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it("
|
|
18
|
+
it("renders button", () => {
|
|
19
19
|
const { container } = render(() => (
|
|
20
20
|
<ConfigContext.Provider value={{ clientName: "testApp" }}>
|
|
21
21
|
<NotificationProvider>
|
|
@@ -27,7 +27,7 @@ describe("NotificationBell", () => {
|
|
|
27
27
|
expect(container.querySelector("[data-notification-bell]")).not.toBeNull();
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it("
|
|
30
|
+
it("does not show badge when there are no notifications", () => {
|
|
31
31
|
render(() => (
|
|
32
32
|
<ConfigContext.Provider value={{ clientName: "testApp" }}>
|
|
33
33
|
<NotificationProvider>
|
|
@@ -40,7 +40,7 @@ describe("NotificationBell", () => {
|
|
|
40
40
|
expect(badge).toBeNull();
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
it("
|
|
43
|
+
it("shows count on badge when notifications are present", async () => {
|
|
44
44
|
let notification: ReturnType<typeof useNotification>;
|
|
45
45
|
|
|
46
46
|
render(() => (
|
|
@@ -64,7 +64,7 @@ describe("NotificationBell", () => {
|
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
it("
|
|
67
|
+
it("opens Dropdown on button click", async () => {
|
|
68
68
|
let notification: ReturnType<typeof useNotification>;
|
|
69
69
|
|
|
70
70
|
render(() => (
|
|
@@ -90,7 +90,7 @@ describe("NotificationBell", () => {
|
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
it("
|
|
93
|
+
it("shows notification list in Dropdown", async () => {
|
|
94
94
|
let notification: ReturnType<typeof useNotification>;
|
|
95
95
|
|
|
96
96
|
render(() => (
|
|
@@ -118,7 +118,7 @@ describe("NotificationBell", () => {
|
|
|
118
118
|
});
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
-
it("aria-label
|
|
121
|
+
it("includes notification count in aria-label", async () => {
|
|
122
122
|
let notification: ReturnType<typeof useNotification>;
|
|
123
123
|
|
|
124
124
|
render(() => (
|
|
@@ -141,7 +141,7 @@ describe("NotificationBell", () => {
|
|
|
141
141
|
});
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
it("aria-haspopup
|
|
144
|
+
it("sets aria-haspopup and aria-expanded correctly", async () => {
|
|
145
145
|
render(() => (
|
|
146
146
|
<ConfigContext.Provider value={{ clientName: "testApp" }}>
|
|
147
147
|
<NotificationProvider>
|
|
@@ -161,7 +161,7 @@ describe("NotificationBell", () => {
|
|
|
161
161
|
});
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
-
it("
|
|
164
|
+
it("marks all notifications as read when dropdown opens", async () => {
|
|
165
165
|
let notification: ReturnType<typeof useNotification>;
|
|
166
166
|
|
|
167
167
|
render(() => (
|
|
@@ -191,7 +191,7 @@ describe("NotificationBell", () => {
|
|
|
191
191
|
});
|
|
192
192
|
});
|
|
193
193
|
|
|
194
|
-
it("
|
|
194
|
+
it("calls clear when clear-all button is clicked", async () => {
|
|
195
195
|
let notification: ReturnType<typeof useNotification>;
|
|
196
196
|
|
|
197
197
|
render(() => (
|
|
@@ -2,7 +2,7 @@ import { render } from "@solidjs/testing-library";
|
|
|
2
2
|
import { describe, it, expect } from "vitest";
|
|
3
3
|
import { Print } from "../../../../src/components/feedback/print/Print";
|
|
4
4
|
|
|
5
|
-
describe("Print
|
|
5
|
+
describe("Print", () => {
|
|
6
6
|
describe("basic rendering", () => {
|
|
7
7
|
it("renders children", () => {
|
|
8
8
|
const { getByText } = render(() => <Print>테스트 내용</Print>);
|
|
@@ -11,7 +11,7 @@ describe("Print 컴포넌트", () => {
|
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
describe("Print.Page", () => {
|
|
14
|
-
it("data-print-page
|
|
14
|
+
it("renders with data-print-page attribute", () => {
|
|
15
15
|
const { container } = render(() => (
|
|
16
16
|
<Print>
|
|
17
17
|
<Print.Page>페이지 1</Print.Page>
|
|
@@ -21,7 +21,7 @@ describe("Print 컴포넌트", () => {
|
|
|
21
21
|
expect(page).toBeTruthy();
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
it("
|
|
24
|
+
it("each Print.Page has data-print-page attribute", () => {
|
|
25
25
|
const { container } = render(() => (
|
|
26
26
|
<Print>
|
|
27
27
|
<Print.Page>페이지 1</Print.Page>
|
|
@@ -33,7 +33,7 @@ describe("Print 컴포넌트", () => {
|
|
|
33
33
|
expect(pages.length).toBe(3);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it("Print.Page children
|
|
36
|
+
it("renders Print.Page children", () => {
|
|
37
37
|
const { getByText } = render(() => (
|
|
38
38
|
<Print>
|
|
39
39
|
<Print.Page>페이지 내용</Print.Page>
|
|
@@ -2,23 +2,23 @@ import { render, fireEvent } from "@solidjs/testing-library";
|
|
|
2
2
|
import { describe, it, expect, vi } from "vitest";
|
|
3
3
|
import { Button } from "../../../src/components/form-control/Button";
|
|
4
4
|
|
|
5
|
-
describe("Button
|
|
5
|
+
describe("Button component", () => {
|
|
6
6
|
describe("basic rendering", () => {
|
|
7
|
-
it("children
|
|
7
|
+
it("renders children inside the button", () => {
|
|
8
8
|
const { getByRole } = render(() => <Button>Click Me</Button>);
|
|
9
9
|
const button = getByRole("button");
|
|
10
10
|
|
|
11
11
|
expect(button.textContent).toBe("Click Me");
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it("type
|
|
14
|
+
it("defaults type to button", () => {
|
|
15
15
|
const { getByRole } = render(() => <Button>Click</Button>);
|
|
16
16
|
const button = getByRole("button");
|
|
17
17
|
|
|
18
18
|
expect(button.getAttribute("type")).toBe("button");
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it("type
|
|
21
|
+
it("overrides type with submit", () => {
|
|
22
22
|
const { getByRole } = render(() => <Button type="submit">Submit</Button>);
|
|
23
23
|
const button = getByRole("button");
|
|
24
24
|
|
|
@@ -26,8 +26,8 @@ describe("Button 컴포넌트", () => {
|
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
describe("theme
|
|
30
|
-
it("
|
|
29
|
+
describe("theme prop", () => {
|
|
30
|
+
it("applies different styles per theme", () => {
|
|
31
31
|
const { getByRole: getDefault } = render(() => <Button>Click</Button>);
|
|
32
32
|
const { getByRole: getThemed } = render(() => <Button theme="danger">Click</Button>);
|
|
33
33
|
|
|
@@ -35,8 +35,8 @@ describe("Button 컴포넌트", () => {
|
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
describe("variant
|
|
39
|
-
it("
|
|
38
|
+
describe("variant prop", () => {
|
|
39
|
+
it("applies different styles per variant", () => {
|
|
40
40
|
const { getByRole: getOutline } = render(() => <Button>Click</Button>);
|
|
41
41
|
const { getByRole: getSolid } = render(() => <Button variant="solid">Click</Button>);
|
|
42
42
|
const { getByRole: getGhost } = render(() => <Button variant="ghost">Click</Button>);
|
|
@@ -51,8 +51,8 @@ describe("Button 컴포넌트", () => {
|
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
describe("size
|
|
55
|
-
it("
|
|
54
|
+
describe("size prop", () => {
|
|
55
|
+
it("applies different styles per size", () => {
|
|
56
56
|
const { getByRole: getDefault } = render(() => <Button>Click</Button>);
|
|
57
57
|
const { getByRole: getSm } = render(() => <Button size="sm">Click</Button>);
|
|
58
58
|
const { getByRole: getLg } = render(() => <Button size="lg">Click</Button>);
|
|
@@ -67,8 +67,8 @@ describe("Button 컴포넌트", () => {
|
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
describe("inset
|
|
71
|
-
it("
|
|
70
|
+
describe("inset prop", () => {
|
|
71
|
+
it("applies different styles when inset", () => {
|
|
72
72
|
const { getByRole: getDefault } = render(() => <Button>Click</Button>);
|
|
73
73
|
const { getByRole: getInset } = render(() => <Button inset>Click</Button>);
|
|
74
74
|
|
|
@@ -76,23 +76,23 @@ describe("Button 컴포넌트", () => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
describe("disabled
|
|
80
|
-
it("
|
|
79
|
+
describe("disabled prop", () => {
|
|
80
|
+
it("applies different styles when disabled", () => {
|
|
81
81
|
const { getByRole: getDefault } = render(() => <Button>Click</Button>);
|
|
82
82
|
const { getByRole: getDisabled } = render(() => <Button disabled>Click</Button>);
|
|
83
83
|
|
|
84
84
|
expect(getDefault("button").className).not.toBe(getDisabled("button").className);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
it("
|
|
87
|
+
it("sets HTML disabled attribute when disabled=true", () => {
|
|
88
88
|
const { getByRole } = render(() => <Button disabled>Click</Button>);
|
|
89
89
|
|
|
90
90
|
expect(getByRole("button").hasAttribute("disabled")).toBe(true);
|
|
91
91
|
});
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
describe("
|
|
95
|
-
it("onClick handler
|
|
94
|
+
describe("event handling", () => {
|
|
95
|
+
it("calls onClick handler on click", () => {
|
|
96
96
|
const handleClick = vi.fn();
|
|
97
97
|
const { getByRole } = render(() => <Button onClick={handleClick}>Click</Button>);
|
|
98
98
|
|
|
@@ -101,7 +101,7 @@ describe("Button 컴포넌트", () => {
|
|
|
101
101
|
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
-
it("
|
|
104
|
+
it("blocks click when disabled", () => {
|
|
105
105
|
const { getByRole } = render(() => <Button disabled>Click</Button>);
|
|
106
106
|
|
|
107
107
|
expect(getByRole("button").hasAttribute("disabled")).toBe(true);
|