@instructure/ui-tree-browser 10.16.1 → 10.16.3
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/CHANGELOG.md +16 -0
- package/es/TreeBrowser/TreeButton/__new-tests__/TreeButton.test.js +165 -0
- package/es/TreeBrowser/TreeCollection/__new-tests__/TreeCollection.test.js +454 -0
- package/es/TreeBrowser/{TreeBrowserLocator.js → TreeNode/__new-tests__/TreeNode.test.js} +31 -14
- package/es/TreeBrowser/__new-tests__/TreeBrowser.test.js +525 -0
- package/lib/TreeBrowser/TreeButton/__new-tests__/TreeButton.test.js +166 -0
- package/lib/TreeBrowser/TreeCollection/__new-tests__/TreeCollection.test.js +457 -0
- package/lib/TreeBrowser/TreeNode/__new-tests__/TreeNode.test.js +56 -0
- package/lib/TreeBrowser/__new-tests__/TreeBrowser.test.js +527 -0
- package/package.json +17 -14
- package/src/TreeBrowser/TreeButton/__new-tests__/TreeButton.test.tsx +162 -0
- package/src/TreeBrowser/TreeCollection/__new-tests__/TreeCollection.test.tsx +423 -0
- package/src/TreeBrowser/{TreeBrowserLocator.ts → TreeNode/__new-tests__/TreeNode.test.tsx} +30 -13
- package/src/TreeBrowser/__new-tests__/TreeBrowser.test.tsx +575 -0
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/TreeBrowser/TreeButton/__new-tests__/TreeButton.test.d.ts +2 -0
- package/types/TreeBrowser/TreeButton/__new-tests__/TreeButton.test.d.ts.map +1 -0
- package/types/TreeBrowser/TreeCollection/__new-tests__/TreeCollection.test.d.ts +2 -0
- package/types/TreeBrowser/TreeCollection/__new-tests__/TreeCollection.test.d.ts.map +1 -0
- package/types/TreeBrowser/TreeNode/__new-tests__/TreeNode.test.d.ts +2 -0
- package/types/TreeBrowser/TreeNode/__new-tests__/TreeNode.test.d.ts.map +1 -0
- package/types/TreeBrowser/__new-tests__/TreeBrowser.test.d.ts +2 -0
- package/types/TreeBrowser/__new-tests__/TreeBrowser.test.d.ts.map +1 -0
- package/es/TreeBrowser/locator.js +0 -26
- package/lib/TreeBrowser/TreeBrowserLocator.js +0 -44
- package/lib/TreeBrowser/locator.js +0 -37
- package/src/TreeBrowser/locator.ts +0 -27
- package/types/TreeBrowser/TreeBrowserLocator.d.ts +0 -1065
- package/types/TreeBrowser/TreeBrowserLocator.d.ts.map +0 -1
- package/types/TreeBrowser/locator.d.ts +0 -4
- package/types/TreeBrowser/locator.d.ts.map +0 -1
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
var _TreeBrowser, _TreeBrowser2, _TreeBrowser3, _TreeBrowser4, _TreeBrowser5, _TreeBrowser6, _TreeBrowser7, _TreeBrowser8, _TreeBrowser9, _TreeBrowser10, _TreeBrowser11, _svg, _TreeBrowser12, _TreeNode, _TreeNode2, _svg2, _TreeBrowser13, _TreeBrowser14, _TreeBrowser15, _TreeBrowser16, _TreeBrowser17;
|
|
2
|
+
/*
|
|
3
|
+
* The MIT License (MIT)
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2015 - present Instructure, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
* copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
* SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
27
|
+
import userEvent from '@testing-library/user-event';
|
|
28
|
+
import { vi } from 'vitest';
|
|
29
|
+
import { runAxeCheck } from '@instructure/ui-axe-check';
|
|
30
|
+
import '@testing-library/jest-dom';
|
|
31
|
+
import { TreeBrowser } from '../index';
|
|
32
|
+
import { TreeNode } from '../TreeNode';
|
|
33
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
34
|
+
const COLLECTIONS_DATA = {
|
|
35
|
+
2: {
|
|
36
|
+
id: 2,
|
|
37
|
+
name: 'Root Directory',
|
|
38
|
+
collections: [3, 4],
|
|
39
|
+
items: [1]
|
|
40
|
+
},
|
|
41
|
+
3: {
|
|
42
|
+
id: 3,
|
|
43
|
+
name: 'Sub Root 1',
|
|
44
|
+
collections: [5]
|
|
45
|
+
},
|
|
46
|
+
4: {
|
|
47
|
+
id: 4,
|
|
48
|
+
name: 'Sub Root 2'
|
|
49
|
+
},
|
|
50
|
+
5: {
|
|
51
|
+
id: 5,
|
|
52
|
+
name: 'Nested Sub Collection'
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const COLLECTIONS_DATA_WITH_ZERO = {
|
|
56
|
+
0: {
|
|
57
|
+
id: 0,
|
|
58
|
+
name: 'Root Directory',
|
|
59
|
+
collections: [3, 4],
|
|
60
|
+
items: [1]
|
|
61
|
+
},
|
|
62
|
+
3: {
|
|
63
|
+
id: 3,
|
|
64
|
+
name: 'Sub Root 1',
|
|
65
|
+
collections: [5]
|
|
66
|
+
},
|
|
67
|
+
4: {
|
|
68
|
+
id: 4,
|
|
69
|
+
name: 'Sub Root 2'
|
|
70
|
+
},
|
|
71
|
+
5: {
|
|
72
|
+
id: 5,
|
|
73
|
+
name: 'Nested Sub Collection'
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const COLLECTIONS_DATA_WITH_STRING_IDS = {
|
|
77
|
+
'2': {
|
|
78
|
+
id: '2',
|
|
79
|
+
name: 'Root Directory',
|
|
80
|
+
collections: ['3', '4'],
|
|
81
|
+
items: [1]
|
|
82
|
+
},
|
|
83
|
+
'3': {
|
|
84
|
+
id: '3',
|
|
85
|
+
name: 'Sub Root 1',
|
|
86
|
+
collections: ['5']
|
|
87
|
+
},
|
|
88
|
+
'4': {
|
|
89
|
+
id: '4',
|
|
90
|
+
name: 'Sub Root 2'
|
|
91
|
+
},
|
|
92
|
+
'5': {
|
|
93
|
+
id: '5',
|
|
94
|
+
name: 'Nested Sub Collection'
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const ITEMS_DATA = {
|
|
98
|
+
1: {
|
|
99
|
+
id: 1,
|
|
100
|
+
name: 'Item 1'
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
describe('<TreeBrowser />', () => {
|
|
104
|
+
let consoleWarningMock;
|
|
105
|
+
let consoleErrorMock;
|
|
106
|
+
beforeEach(() => {
|
|
107
|
+
// Mocking console to prevent test output pollution and expect for messages
|
|
108
|
+
consoleWarningMock = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
109
|
+
consoleErrorMock = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
110
|
+
});
|
|
111
|
+
afterEach(() => {
|
|
112
|
+
consoleWarningMock.mockRestore();
|
|
113
|
+
consoleErrorMock.mockRestore();
|
|
114
|
+
});
|
|
115
|
+
it('should render a tree', async () => {
|
|
116
|
+
const _render = render(_TreeBrowser || (_TreeBrowser = _jsx(TreeBrowser, {
|
|
117
|
+
collections: COLLECTIONS_DATA,
|
|
118
|
+
items: ITEMS_DATA,
|
|
119
|
+
rootId: 2
|
|
120
|
+
}))),
|
|
121
|
+
container = _render.container;
|
|
122
|
+
const tree = container.querySelector('[class$="-treeBrowser"]');
|
|
123
|
+
expect(tree).toBeInTheDocument();
|
|
124
|
+
});
|
|
125
|
+
it('should render subcollections', async () => {
|
|
126
|
+
render(_TreeBrowser2 || (_TreeBrowser2 = _jsx(TreeBrowser, {
|
|
127
|
+
collections: COLLECTIONS_DATA,
|
|
128
|
+
items: ITEMS_DATA,
|
|
129
|
+
rootId: 2
|
|
130
|
+
})));
|
|
131
|
+
const items = screen.getAllByRole('treeitem');
|
|
132
|
+
expect(items.length).toEqual(1);
|
|
133
|
+
await userEvent.click(items[0]);
|
|
134
|
+
await waitFor(() => {
|
|
135
|
+
const itemsAfterClick = screen.getAllByRole('treeitem');
|
|
136
|
+
expect(itemsAfterClick.length).toEqual(4);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
it('should render all collections at top level if showRootCollection is true and rootId is undefined', async () => {
|
|
140
|
+
render(_TreeBrowser3 || (_TreeBrowser3 = _jsx(TreeBrowser, {
|
|
141
|
+
collections: COLLECTIONS_DATA,
|
|
142
|
+
items: ITEMS_DATA,
|
|
143
|
+
rootId: void 0
|
|
144
|
+
})));
|
|
145
|
+
const items = screen.getAllByRole('treeitem');
|
|
146
|
+
expect(items.length).toEqual(4);
|
|
147
|
+
});
|
|
148
|
+
describe('expanded', () => {
|
|
149
|
+
it('should not expand collections or items without defaultExpanded prop', async () => {
|
|
150
|
+
render(_TreeBrowser4 || (_TreeBrowser4 = _jsx(TreeBrowser, {
|
|
151
|
+
collections: COLLECTIONS_DATA,
|
|
152
|
+
items: ITEMS_DATA,
|
|
153
|
+
rootId: 2
|
|
154
|
+
})));
|
|
155
|
+
const items = screen.getAllByRole('treeitem');
|
|
156
|
+
expect(items.length).toEqual(1);
|
|
157
|
+
expect(items[0]).toHaveTextContent('Root Directory');
|
|
158
|
+
});
|
|
159
|
+
it('should accept an array of default expanded collections', async () => {
|
|
160
|
+
render(_jsx(TreeBrowser, {
|
|
161
|
+
collections: COLLECTIONS_DATA,
|
|
162
|
+
items: ITEMS_DATA,
|
|
163
|
+
rootId: 2,
|
|
164
|
+
defaultExpanded: [2, 3]
|
|
165
|
+
}));
|
|
166
|
+
const items = screen.getAllByRole('treeitem');
|
|
167
|
+
const subRoot2 = screen.getByLabelText('Sub Root 2');
|
|
168
|
+
const nestedSub = screen.getByLabelText('Nested Sub Collection');
|
|
169
|
+
expect(items.length).toEqual(5);
|
|
170
|
+
expect(subRoot2).toHaveAttribute('aria-label', 'Sub Root 2');
|
|
171
|
+
expect(subRoot2).toHaveTextContent('Sub Root 2');
|
|
172
|
+
expect(nestedSub).toHaveAttribute('aria-label', 'Nested Sub Collection');
|
|
173
|
+
expect(nestedSub).toHaveTextContent('Nested Sub Collection');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
describe('selected', () => {
|
|
177
|
+
it('should not show the selection if selectionType is none', async () => {
|
|
178
|
+
render(_TreeBrowser5 || (_TreeBrowser5 = _jsx(TreeBrowser, {
|
|
179
|
+
collections: COLLECTIONS_DATA,
|
|
180
|
+
items: ITEMS_DATA,
|
|
181
|
+
rootId: 2
|
|
182
|
+
})));
|
|
183
|
+
const item = screen.getByRole('treeitem');
|
|
184
|
+
await userEvent.click(item);
|
|
185
|
+
await waitFor(() => {
|
|
186
|
+
expect(item).not.toHaveAttribute('aria-selected');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
it('should show the selection indicator on last clicked collection or item', async () => {
|
|
190
|
+
render(_TreeBrowser6 || (_TreeBrowser6 = _jsx(TreeBrowser, {
|
|
191
|
+
collections: COLLECTIONS_DATA,
|
|
192
|
+
items: ITEMS_DATA,
|
|
193
|
+
rootId: 2,
|
|
194
|
+
selectionType: "single"
|
|
195
|
+
})));
|
|
196
|
+
const item = screen.getByLabelText('Root Directory');
|
|
197
|
+
await userEvent.click(item);
|
|
198
|
+
await waitFor(() => {
|
|
199
|
+
expect(item).toHaveAttribute('aria-selected');
|
|
200
|
+
});
|
|
201
|
+
const nestedItem = screen.getByLabelText('Item 1');
|
|
202
|
+
await userEvent.click(nestedItem);
|
|
203
|
+
await waitFor(() => {
|
|
204
|
+
expect(nestedItem).toHaveAttribute('aria-selected');
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe('collections', () => {
|
|
209
|
+
it('should render collections with string-keyed ids', async () => {
|
|
210
|
+
render(_TreeBrowser7 || (_TreeBrowser7 = _jsx(TreeBrowser, {
|
|
211
|
+
collections: COLLECTIONS_DATA_WITH_STRING_IDS,
|
|
212
|
+
items: ITEMS_DATA,
|
|
213
|
+
rootId: '2',
|
|
214
|
+
showRootCollection: true
|
|
215
|
+
})));
|
|
216
|
+
const item = screen.getByLabelText('Root Directory');
|
|
217
|
+
expect(item).toBeInTheDocument();
|
|
218
|
+
});
|
|
219
|
+
it('should not show the first keyed collection if showRootCollection is false', async () => {
|
|
220
|
+
render(_TreeBrowser8 || (_TreeBrowser8 = _jsx(TreeBrowser, {
|
|
221
|
+
collections: COLLECTIONS_DATA,
|
|
222
|
+
items: ITEMS_DATA,
|
|
223
|
+
rootId: 2,
|
|
224
|
+
showRootCollection: false
|
|
225
|
+
})));
|
|
226
|
+
const items = screen.getAllByRole('treeitem');
|
|
227
|
+
expect(items.length).toEqual(3);
|
|
228
|
+
});
|
|
229
|
+
it('should render first keyed collection if showRootCollection is true and rootId specified', async () => {
|
|
230
|
+
render(_TreeBrowser9 || (_TreeBrowser9 = _jsx(TreeBrowser, {
|
|
231
|
+
collections: COLLECTIONS_DATA,
|
|
232
|
+
items: ITEMS_DATA,
|
|
233
|
+
rootId: 2
|
|
234
|
+
})));
|
|
235
|
+
const item = screen.getByLabelText('Root Directory');
|
|
236
|
+
expect(item).toBeInTheDocument();
|
|
237
|
+
});
|
|
238
|
+
it('should not show the first keyed collection if showRootCollection is false and rootId is 0', async () => {
|
|
239
|
+
render(_TreeBrowser10 || (_TreeBrowser10 = _jsx(TreeBrowser, {
|
|
240
|
+
collections: COLLECTIONS_DATA_WITH_ZERO,
|
|
241
|
+
items: ITEMS_DATA,
|
|
242
|
+
rootId: 0,
|
|
243
|
+
showRootCollection: false
|
|
244
|
+
})));
|
|
245
|
+
const items = screen.getAllByRole('treeitem');
|
|
246
|
+
expect(items.length).toEqual(3);
|
|
247
|
+
});
|
|
248
|
+
it('should render a folder icon by default', async () => {
|
|
249
|
+
const _render2 = render(_TreeBrowser11 || (_TreeBrowser11 = _jsx(TreeBrowser, {
|
|
250
|
+
collections: COLLECTIONS_DATA,
|
|
251
|
+
items: ITEMS_DATA,
|
|
252
|
+
rootId: 2
|
|
253
|
+
}))),
|
|
254
|
+
container = _render2.container;
|
|
255
|
+
const iconFolder = container.querySelectorAll('svg[name="IconFolder"]');
|
|
256
|
+
expect(iconFolder.length).toEqual(1);
|
|
257
|
+
});
|
|
258
|
+
it('should render a custom icon', async () => {
|
|
259
|
+
const IconCustom = _svg || (_svg = _jsxs("svg", {
|
|
260
|
+
height: "100",
|
|
261
|
+
width: "100",
|
|
262
|
+
"data-testid": "icon-custom",
|
|
263
|
+
children: [_jsx("title", {
|
|
264
|
+
"data-testid": "icon-custom-title",
|
|
265
|
+
children: "Custom icon"
|
|
266
|
+
}), _jsx("circle", {
|
|
267
|
+
cx: "50",
|
|
268
|
+
cy: "50",
|
|
269
|
+
r: "40"
|
|
270
|
+
})]
|
|
271
|
+
}));
|
|
272
|
+
render(_jsx(TreeBrowser, {
|
|
273
|
+
collections: COLLECTIONS_DATA,
|
|
274
|
+
items: ITEMS_DATA,
|
|
275
|
+
rootId: 2,
|
|
276
|
+
collectionIcon: () => IconCustom
|
|
277
|
+
}));
|
|
278
|
+
const iconCustom = screen.getByTestId('icon-custom');
|
|
279
|
+
const title = screen.getByTestId('icon-custom-title');
|
|
280
|
+
expect(iconCustom).toBeInTheDocument();
|
|
281
|
+
expect(title).toBeInTheDocument();
|
|
282
|
+
expect(title).toHaveTextContent('Custom icon');
|
|
283
|
+
});
|
|
284
|
+
it('should render without icon if set to null', async () => {
|
|
285
|
+
const _render3 = render(_TreeBrowser12 || (_TreeBrowser12 = _jsx(TreeBrowser, {
|
|
286
|
+
collections: COLLECTIONS_DATA,
|
|
287
|
+
items: ITEMS_DATA,
|
|
288
|
+
rootId: 2,
|
|
289
|
+
collectionIcon: null
|
|
290
|
+
}))),
|
|
291
|
+
container = _render3.container;
|
|
292
|
+
const icon = container.querySelector('svg');
|
|
293
|
+
expect(icon).not.toBeInTheDocument();
|
|
294
|
+
});
|
|
295
|
+
it('should call onCollectionToggle when expanding and collapsing with mouse', async () => {
|
|
296
|
+
const onCollectionToggle = vi.fn();
|
|
297
|
+
render(_jsx(TreeBrowser, {
|
|
298
|
+
collections: COLLECTIONS_DATA,
|
|
299
|
+
items: ITEMS_DATA,
|
|
300
|
+
rootId: 2,
|
|
301
|
+
onCollectionToggle: onCollectionToggle
|
|
302
|
+
}));
|
|
303
|
+
const item = screen.getByRole('treeitem');
|
|
304
|
+
await userEvent.click(item);
|
|
305
|
+
await waitFor(() => {
|
|
306
|
+
expect(onCollectionToggle).toHaveBeenCalled();
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
it('should call onCollectionClick on button activation (space/enter or click)', async () => {
|
|
310
|
+
const onCollectionClick = vi.fn();
|
|
311
|
+
render(_jsx(TreeBrowser, {
|
|
312
|
+
collections: COLLECTIONS_DATA,
|
|
313
|
+
items: ITEMS_DATA,
|
|
314
|
+
rootId: 2,
|
|
315
|
+
onCollectionClick: onCollectionClick
|
|
316
|
+
}));
|
|
317
|
+
const item = screen.getByLabelText('Root Directory');
|
|
318
|
+
await userEvent.click(item);
|
|
319
|
+
await userEvent.type(item, '{space}');
|
|
320
|
+
await userEvent.type(item, '{enter}');
|
|
321
|
+
await waitFor(() => {
|
|
322
|
+
expect(onCollectionClick).toHaveBeenCalledTimes(3);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
it('should render before, after nodes of the provided collection', async () => {
|
|
326
|
+
const _render4 = render(_jsx(TreeBrowser, {
|
|
327
|
+
collections: {
|
|
328
|
+
2: {
|
|
329
|
+
id: 2,
|
|
330
|
+
name: 'Root Directory',
|
|
331
|
+
collections: [],
|
|
332
|
+
items: [],
|
|
333
|
+
renderBeforeItems: _TreeNode || (_TreeNode = _jsx(TreeNode, {
|
|
334
|
+
children: _jsx("input", {
|
|
335
|
+
id: "input-before"
|
|
336
|
+
})
|
|
337
|
+
})),
|
|
338
|
+
renderAfterItems: _TreeNode2 || (_TreeNode2 = _jsx(TreeNode, {
|
|
339
|
+
children: _jsx("input", {
|
|
340
|
+
id: "input-after"
|
|
341
|
+
})
|
|
342
|
+
}))
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
items: {},
|
|
346
|
+
expanded: [2],
|
|
347
|
+
rootId: 2
|
|
348
|
+
})),
|
|
349
|
+
container = _render4.container;
|
|
350
|
+
const contentBefore = container.querySelector('#input-before');
|
|
351
|
+
const contentAfter = container.querySelector('#input-after');
|
|
352
|
+
expect(contentBefore).toBeInTheDocument();
|
|
353
|
+
expect(contentAfter).toBeInTheDocument();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
describe('items', () => {
|
|
357
|
+
it('should render a document icon by default', async () => {
|
|
358
|
+
const _render5 = render(_jsx(TreeBrowser, {
|
|
359
|
+
collections: COLLECTIONS_DATA,
|
|
360
|
+
items: ITEMS_DATA,
|
|
361
|
+
rootId: 2,
|
|
362
|
+
defaultExpanded: [2]
|
|
363
|
+
})),
|
|
364
|
+
container = _render5.container;
|
|
365
|
+
const iconDocument = container.querySelectorAll('svg[name="IconDocument"]');
|
|
366
|
+
expect(iconDocument.length).toEqual(1);
|
|
367
|
+
});
|
|
368
|
+
it('should render a custom icon', async () => {
|
|
369
|
+
const IconCustom = _svg2 || (_svg2 = _jsxs("svg", {
|
|
370
|
+
height: "100",
|
|
371
|
+
width: "100",
|
|
372
|
+
"data-testid": "icon-custom",
|
|
373
|
+
children: [_jsx("title", {
|
|
374
|
+
"data-testid": "icon-custom-title",
|
|
375
|
+
children: "Custom icon"
|
|
376
|
+
}), _jsx("circle", {
|
|
377
|
+
cx: "50",
|
|
378
|
+
cy: "50",
|
|
379
|
+
r: "40"
|
|
380
|
+
})]
|
|
381
|
+
}));
|
|
382
|
+
render(_jsx(TreeBrowser, {
|
|
383
|
+
collections: COLLECTIONS_DATA,
|
|
384
|
+
items: ITEMS_DATA,
|
|
385
|
+
rootId: 2,
|
|
386
|
+
defaultExpanded: [2],
|
|
387
|
+
itemIcon: () => IconCustom
|
|
388
|
+
}));
|
|
389
|
+
const iconCustom = screen.getByTestId('icon-custom');
|
|
390
|
+
const title = screen.getByTestId('icon-custom-title');
|
|
391
|
+
expect(iconCustom).toBeInTheDocument();
|
|
392
|
+
expect(title).toBeInTheDocument();
|
|
393
|
+
expect(title).toHaveTextContent('Custom icon');
|
|
394
|
+
});
|
|
395
|
+
it('should render without icon if set to null', async () => {
|
|
396
|
+
const _render6 = render(_TreeBrowser13 || (_TreeBrowser13 = _jsx(TreeBrowser, {
|
|
397
|
+
collections: COLLECTIONS_DATA,
|
|
398
|
+
items: ITEMS_DATA,
|
|
399
|
+
rootId: 2
|
|
400
|
+
}))),
|
|
401
|
+
container = _render6.container;
|
|
402
|
+
const iconDocument = container.querySelector('svg[name="IconDocument"]');
|
|
403
|
+
expect(iconDocument).not.toBeInTheDocument();
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
describe('for a11y', () => {
|
|
407
|
+
it('should meet a11y standards', async () => {
|
|
408
|
+
const _render7 = render(_TreeBrowser14 || (_TreeBrowser14 = _jsx(TreeBrowser, {
|
|
409
|
+
collections: COLLECTIONS_DATA,
|
|
410
|
+
items: ITEMS_DATA,
|
|
411
|
+
rootId: 2
|
|
412
|
+
}))),
|
|
413
|
+
container = _render7.container;
|
|
414
|
+
const axeCheck = await runAxeCheck(container);
|
|
415
|
+
expect(axeCheck).toBe(true);
|
|
416
|
+
});
|
|
417
|
+
it('should accept a treeLabel prop', async () => {
|
|
418
|
+
render(_TreeBrowser15 || (_TreeBrowser15 = _jsx(TreeBrowser, {
|
|
419
|
+
collections: COLLECTIONS_DATA,
|
|
420
|
+
items: ITEMS_DATA,
|
|
421
|
+
rootId: 2,
|
|
422
|
+
treeLabel: "Test treeLabel"
|
|
423
|
+
})));
|
|
424
|
+
const tree = screen.getByLabelText('Test treeLabel');
|
|
425
|
+
expect(tree).toBeInTheDocument();
|
|
426
|
+
});
|
|
427
|
+
it('should toggle aria-expanded', async () => {
|
|
428
|
+
render(_TreeBrowser16 || (_TreeBrowser16 = _jsx(TreeBrowser, {
|
|
429
|
+
collections: COLLECTIONS_DATA,
|
|
430
|
+
items: ITEMS_DATA,
|
|
431
|
+
rootId: 2
|
|
432
|
+
})));
|
|
433
|
+
const item = screen.getByRole('treeitem');
|
|
434
|
+
expect(item).toHaveAttribute('aria-expanded', 'false');
|
|
435
|
+
await userEvent.click(item);
|
|
436
|
+
await waitFor(() => {
|
|
437
|
+
expect(item).toHaveAttribute('aria-expanded', 'true');
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
it('should use aria-selected when selectionType is not none', async () => {
|
|
441
|
+
render(_TreeBrowser17 || (_TreeBrowser17 = _jsx(TreeBrowser, {
|
|
442
|
+
collections: COLLECTIONS_DATA,
|
|
443
|
+
items: ITEMS_DATA,
|
|
444
|
+
rootId: 2,
|
|
445
|
+
selectionType: "single"
|
|
446
|
+
})));
|
|
447
|
+
const item = screen.getByRole('treeitem');
|
|
448
|
+
expect(item).not.toHaveAttribute('aria-selected');
|
|
449
|
+
await userEvent.click(item);
|
|
450
|
+
await waitFor(() => {
|
|
451
|
+
expect(item).toHaveAttribute('aria-selected', 'true');
|
|
452
|
+
});
|
|
453
|
+
const nestedItem = screen.getByLabelText('Sub Root 1');
|
|
454
|
+
expect(nestedItem).toHaveAttribute('aria-selected', 'false');
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
describe('sorting', () => {
|
|
458
|
+
it("should present collections and items in alphabetical order, in spite of the order of 'collections' and 'items' arrays", async () => {
|
|
459
|
+
render(_jsx(TreeBrowser, {
|
|
460
|
+
collections: {
|
|
461
|
+
1: {
|
|
462
|
+
id: 1,
|
|
463
|
+
name: 'Assignments',
|
|
464
|
+
collections: [5, 3, 2, 4],
|
|
465
|
+
items: [3, 5, 2, 1, 4]
|
|
466
|
+
},
|
|
467
|
+
2: {
|
|
468
|
+
id: 2,
|
|
469
|
+
name: 'English Assignments',
|
|
470
|
+
collections: [],
|
|
471
|
+
items: []
|
|
472
|
+
},
|
|
473
|
+
3: {
|
|
474
|
+
id: 3,
|
|
475
|
+
name: 'Math Assignments',
|
|
476
|
+
collections: [],
|
|
477
|
+
items: []
|
|
478
|
+
},
|
|
479
|
+
4: {
|
|
480
|
+
id: 4,
|
|
481
|
+
name: 'Reading Assignments',
|
|
482
|
+
collections: [],
|
|
483
|
+
items: []
|
|
484
|
+
},
|
|
485
|
+
5: {
|
|
486
|
+
id: 5,
|
|
487
|
+
name: 'Advanced Math Assignments',
|
|
488
|
+
items: []
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
items: {
|
|
492
|
+
1: {
|
|
493
|
+
id: 1,
|
|
494
|
+
name: 'Addition Worksheet'
|
|
495
|
+
},
|
|
496
|
+
2: {
|
|
497
|
+
id: 2,
|
|
498
|
+
name: 'Subtraction Worksheet'
|
|
499
|
+
},
|
|
500
|
+
3: {
|
|
501
|
+
id: 3,
|
|
502
|
+
name: 'General Questions'
|
|
503
|
+
},
|
|
504
|
+
4: {
|
|
505
|
+
id: 4,
|
|
506
|
+
name: 'Vogon Poetry'
|
|
507
|
+
},
|
|
508
|
+
5: {
|
|
509
|
+
id: 5,
|
|
510
|
+
name: 'Bistromath'
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
rootId: 1,
|
|
514
|
+
defaultExpanded: [1],
|
|
515
|
+
sortOrder: (a, b) => {
|
|
516
|
+
return a.name.localeCompare(b.name);
|
|
517
|
+
}
|
|
518
|
+
}));
|
|
519
|
+
const items = screen.getAllByRole('treeitem');
|
|
520
|
+
const arr = items.map(item => item.textContent);
|
|
521
|
+
expect(arr.slice(1, 5)).toStrictEqual(['Advanced Math Assignments', 'English Assignments', 'Math Assignments', 'Reading Assignments']);
|
|
522
|
+
expect(arr.slice(5)).toStrictEqual(['Addition Worksheet', 'Bistromath', 'General Questions', 'Subtraction Worksheet', 'Vogon Poetry']);
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = require("@testing-library/react");
|
|
4
|
+
var _vitest = require("vitest");
|
|
5
|
+
require("@testing-library/jest-dom");
|
|
6
|
+
var _index = require("../index");
|
|
7
|
+
var _jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
8
|
+
var _TreeButton, _TreeButton2, _TreeButton3, _svg, _TreeButton4, _TreeButton5, _TreeButton6, _div;
|
|
9
|
+
/*
|
|
10
|
+
* The MIT License (MIT)
|
|
11
|
+
*
|
|
12
|
+
* Copyright (c) 2015 - present Instructure, Inc.
|
|
13
|
+
*
|
|
14
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
* in the Software without restriction, including without limitation the rights
|
|
17
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
* furnished to do so, subject to the following conditions:
|
|
20
|
+
*
|
|
21
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
* copies or substantial portions of the Software.
|
|
23
|
+
*
|
|
24
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
* SOFTWARE.
|
|
31
|
+
*/
|
|
32
|
+
describe('<TreeButton />', () => {
|
|
33
|
+
it('should render', async () => {
|
|
34
|
+
const _render = (0, _react.render)(_TreeButton || (_TreeButton = (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
35
|
+
id: "1"
|
|
36
|
+
}))),
|
|
37
|
+
container = _render.container;
|
|
38
|
+
const treeButton = container.querySelector('button[class$="-treeButton"]');
|
|
39
|
+
expect(treeButton).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
describe('containerRef', () => {
|
|
42
|
+
it('should call with parent element', async () => {
|
|
43
|
+
const containerRef = _vitest.vi.fn();
|
|
44
|
+
(0, _react.render)((0, _jsxRuntime.jsx)("div", {
|
|
45
|
+
"data-testid": "1",
|
|
46
|
+
children: (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
47
|
+
id: "2",
|
|
48
|
+
containerRef: containerRef
|
|
49
|
+
})
|
|
50
|
+
}));
|
|
51
|
+
const div = _react.screen.getByTestId('1');
|
|
52
|
+
expect(containerRef).toHaveBeenCalledWith(div);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('descriptor', () => {
|
|
56
|
+
it('should not render a descriptor element if no descriptor passed', async () => {
|
|
57
|
+
const _render2 = (0, _react.render)(_TreeButton2 || (_TreeButton2 = (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
58
|
+
id: "1"
|
|
59
|
+
}))),
|
|
60
|
+
container = _render2.container;
|
|
61
|
+
const descriptor = container.querySelector('[class$="-treeButton__textDescriptor"]');
|
|
62
|
+
expect(descriptor).not.toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
it('should render a descriptor element if descriptor passed', async () => {
|
|
65
|
+
const _render3 = (0, _react.render)(_TreeButton3 || (_TreeButton3 = (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
66
|
+
id: "1",
|
|
67
|
+
descriptor: "Some Descriptor"
|
|
68
|
+
}))),
|
|
69
|
+
container = _render3.container;
|
|
70
|
+
const descriptor = container.querySelector('[class$="-treeButton__textDescriptor"]');
|
|
71
|
+
expect(descriptor).toBeInTheDocument();
|
|
72
|
+
expect(descriptor).toHaveTextContent('Some Descriptor');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('icons', () => {
|
|
76
|
+
const Icon = _svg || (_svg = (0, _jsxRuntime.jsxs)("svg", {
|
|
77
|
+
height: "100",
|
|
78
|
+
width: "100",
|
|
79
|
+
"data-testid": "custom-icon",
|
|
80
|
+
children: [(0, _jsxRuntime.jsx)("title", {
|
|
81
|
+
"data-testid": "custom-icon-title",
|
|
82
|
+
children: "Test icon"
|
|
83
|
+
}), (0, _jsxRuntime.jsx)("circle", {
|
|
84
|
+
cx: "50",
|
|
85
|
+
cy: "50",
|
|
86
|
+
r: "40"
|
|
87
|
+
})]
|
|
88
|
+
}));
|
|
89
|
+
it('should render a collection icon', async () => {
|
|
90
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
91
|
+
id: "1",
|
|
92
|
+
type: "collection",
|
|
93
|
+
collectionIcon: () => Icon
|
|
94
|
+
}));
|
|
95
|
+
const icon = _react.screen.getByTestId('custom-icon');
|
|
96
|
+
const iconTitle = _react.screen.getByTestId('custom-icon-title');
|
|
97
|
+
expect(icon).toBeInTheDocument();
|
|
98
|
+
expect(icon).toHaveTextContent('Test icon');
|
|
99
|
+
expect(iconTitle).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
it('should render an item icon', async () => {
|
|
102
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
103
|
+
id: "1",
|
|
104
|
+
type: "item",
|
|
105
|
+
itemIcon: () => Icon
|
|
106
|
+
}));
|
|
107
|
+
const icon = _react.screen.getByTestId('custom-icon');
|
|
108
|
+
expect(icon).toBeInTheDocument();
|
|
109
|
+
expect(icon).toHaveTextContent('Test icon');
|
|
110
|
+
});
|
|
111
|
+
it('should render no icon if no icon prop passed', async () => {
|
|
112
|
+
const _render4 = (0, _react.render)(_TreeButton4 || (_TreeButton4 = (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
113
|
+
id: "1"
|
|
114
|
+
}))),
|
|
115
|
+
container = _render4.container;
|
|
116
|
+
const icon = container.querySelector('svg');
|
|
117
|
+
expect(icon).not.toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
it('should render a thumbnail instead of an icon if a thumbnail URL is passed', async () => {
|
|
120
|
+
const _render5 = (0, _react.render)(_TreeButton5 || (_TreeButton5 = (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
121
|
+
id: "1",
|
|
122
|
+
type: "item",
|
|
123
|
+
thumbnail: "data:image/gif;base64,R0lGODlhFAAUAJEAAP/9/fYQEPytrflWViH5BAAAAAAALAAAAAAUABQAQAJKhI+pGe09lnhBnEETfodatVHNh1BR+ZzH9LAOCYrVYpiAfWWJOxrC/5MASbyZT4d6AUIBlUYGoR1FsAXUuTN5YhxAEYbrpKRkQwEAOw=="
|
|
124
|
+
}))),
|
|
125
|
+
container = _render5.container;
|
|
126
|
+
const img = container.querySelector('img');
|
|
127
|
+
expect(img).toBeInTheDocument();
|
|
128
|
+
});
|
|
129
|
+
it('should not render a thumbnail if no thumbnail URL is passed', async () => {
|
|
130
|
+
const _render6 = (0, _react.render)(_TreeButton6 || (_TreeButton6 = (0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
131
|
+
id: "1",
|
|
132
|
+
type: "item"
|
|
133
|
+
}))),
|
|
134
|
+
container = _render6.container;
|
|
135
|
+
const thumbnail = container.querySelector('img');
|
|
136
|
+
expect(thumbnail).not.toBeInTheDocument();
|
|
137
|
+
});
|
|
138
|
+
it('should render a thumbnail if a thumbnail and an icon are passed', async () => {
|
|
139
|
+
const _render7 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
140
|
+
id: "1",
|
|
141
|
+
type: "item",
|
|
142
|
+
itemIcon: () => Icon,
|
|
143
|
+
thumbnail: "data:image/gif;base64,R0lGODlhFAAUAJEAAP/9/fYQEPytrflWViH5BAAAAAAALAAAAAAUABQAQAJKhI+pGe09lnhBnEETfodatVHNh1BR+ZzH9LAOCYrVYpiAfWWJOxrC/5MASbyZT4d6AUIBlUYGoR1FsAXUuTN5YhxAEYbrpKRkQwEAOw=="
|
|
144
|
+
})),
|
|
145
|
+
container = _render7.container;
|
|
146
|
+
const thumbnail = container.querySelector('img');
|
|
147
|
+
const icon = container.querySelector('svg');
|
|
148
|
+
expect(thumbnail).toBeInTheDocument();
|
|
149
|
+
expect(icon).not.toBeInTheDocument();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('renderContent', () => {
|
|
153
|
+
it('should render the content passed to renderContent', async () => {
|
|
154
|
+
const _render8 = (0, _react.render)((0, _jsxRuntime.jsx)(_index.TreeButton, {
|
|
155
|
+
id: "1",
|
|
156
|
+
renderContent: () => _div || (_div = (0, _jsxRuntime.jsx)("div", {
|
|
157
|
+
className: "test1",
|
|
158
|
+
children: "abcd"
|
|
159
|
+
}))
|
|
160
|
+
})),
|
|
161
|
+
container = _render8.container;
|
|
162
|
+
const customElement = container.querySelector('div[class="test1"]');
|
|
163
|
+
expect(customElement).toBeInTheDocument();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|