@internetarchive/collection-browser 3.1.1-alpha-webdev6778.7 → 3.1.1-alpha-webdev6778.9

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.
Files changed (73) hide show
  1. package/dist/src/app-root.js +606 -606
  2. package/dist/src/app-root.js.map +1 -1
  3. package/dist/src/collection-browser.js.map +1 -1
  4. package/dist/src/collection-facets/facet-row.js +140 -140
  5. package/dist/src/collection-facets/facet-row.js.map +1 -1
  6. package/dist/src/collection-facets/models.js.map +1 -1
  7. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +75 -75
  8. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  9. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js +54 -54
  10. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js.map +1 -1
  11. package/dist/src/data-source/collection-browser-data-source-interface.js.map +1 -1
  12. package/dist/src/data-source/collection-browser-data-source.js +1 -3
  13. package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
  14. package/dist/src/data-source/models.js.map +1 -1
  15. package/dist/src/expanded-date-picker.js +52 -52
  16. package/dist/src/expanded-date-picker.js.map +1 -1
  17. package/dist/src/manage/manage-bar.js +77 -77
  18. package/dist/src/manage/manage-bar.js.map +1 -1
  19. package/dist/src/models.js.map +1 -1
  20. package/dist/src/sort-filter-bar/sort-filter-bar.js +376 -376
  21. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  22. package/dist/src/tiles/base-tile-component.js.map +1 -1
  23. package/dist/src/tiles/grid/account-tile.js +36 -36
  24. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  25. package/dist/src/tiles/grid/search-tile.js +42 -42
  26. package/dist/src/tiles/grid/search-tile.js.map +1 -1
  27. package/dist/src/tiles/grid/styles/tile-grid-shared-styles.js +119 -119
  28. package/dist/src/tiles/grid/styles/tile-grid-shared-styles.js.map +1 -1
  29. package/dist/src/tiles/list/tile-list-compact.js +97 -97
  30. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  31. package/dist/src/utils/analytics-events.js.map +1 -1
  32. package/dist/src/utils/format-date.js.map +1 -1
  33. package/dist/test/collection-browser.test.js +187 -187
  34. package/dist/test/collection-browser.test.js.map +1 -1
  35. package/dist/test/collection-facets/facet-row.test.js +23 -23
  36. package/dist/test/collection-facets/facet-row.test.js.map +1 -1
  37. package/dist/test/collection-facets.test.js +20 -20
  38. package/dist/test/collection-facets.test.js.map +1 -1
  39. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +37 -37
  40. package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +1 -1
  41. package/dist/test/tiles/grid/item-tile.test.js +64 -64
  42. package/dist/test/tiles/grid/item-tile.test.js.map +1 -1
  43. package/dist/test/tiles/list/tile-list-compact.test.js +57 -57
  44. package/dist/test/tiles/list/tile-list-compact.test.js.map +1 -1
  45. package/dist/test/utils/format-date.test.js.map +1 -1
  46. package/package.json +2 -2
  47. package/src/app-root.ts +1140 -1140
  48. package/src/collection-browser.ts +1 -1
  49. package/src/collection-facets/facet-row.ts +296 -296
  50. package/src/collection-facets/models.ts +10 -10
  51. package/src/collection-facets/smart-facets/smart-facet-bar.ts +437 -437
  52. package/src/collection-facets/smart-facets/smart-facet-dropdown.ts +185 -185
  53. package/src/data-source/collection-browser-data-source-interface.ts +333 -333
  54. package/src/data-source/collection-browser-data-source.ts +2 -4
  55. package/src/data-source/models.ts +43 -43
  56. package/src/expanded-date-picker.ts +191 -191
  57. package/src/manage/manage-bar.ts +247 -247
  58. package/src/models.ts +870 -870
  59. package/src/sort-filter-bar/sort-filter-bar.ts +1283 -1283
  60. package/src/tiles/base-tile-component.ts +53 -53
  61. package/src/tiles/grid/account-tile.ts +112 -112
  62. package/src/tiles/grid/search-tile.ts +90 -90
  63. package/src/tiles/grid/styles/tile-grid-shared-styles.ts +130 -130
  64. package/src/tiles/list/tile-list-compact.ts +236 -236
  65. package/src/utils/analytics-events.ts +29 -29
  66. package/src/utils/format-date.ts +42 -42
  67. package/test/collection-browser.test.ts +2359 -2359
  68. package/test/collection-facets/facet-row.test.ts +375 -375
  69. package/test/collection-facets.test.ts +928 -928
  70. package/test/sort-filter-bar/sort-filter-bar.test.ts +885 -885
  71. package/test/tiles/grid/item-tile.test.ts +464 -464
  72. package/test/tiles/list/tile-list-compact.test.ts +228 -228
  73. package/test/utils/format-date.test.ts +39 -39
@@ -1,885 +1,885 @@
1
- import { expect, fixture } from '@open-wc/testing';
2
- import sinon from 'sinon';
3
- import { html } from 'lit';
4
- import type { IaDropdown } from '@internetarchive/ia-dropdown';
5
- import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
6
- import type { SortFilterBar } from '../../src/sort-filter-bar/sort-filter-bar';
7
- import { SortField, defaultSortAvailability } from '../../src/models';
8
-
9
- import '../../src/sort-filter-bar/sort-filter-bar';
10
-
11
- describe('Sort selector default buttons', async () => {
12
- let el: SortFilterBar;
13
- let sortSelectorContainer: HTMLElement | null | undefined;
14
- let desktopSortSelector: HTMLElement | null | undefined;
15
-
16
- beforeEach(async () => {
17
- el = await fixture<SortFilterBar>(html`
18
- <sort-filter-bar></sort-filter-bar>
19
- `);
20
- sortSelectorContainer = el.shadowRoot?.querySelector(
21
- '#sort-selector-container',
22
- );
23
- desktopSortSelector = sortSelectorContainer?.querySelector(
24
- '#desktop-sort-selector',
25
- );
26
-
27
- el.resizeObserver = new SharedResizeObserver();
28
- await el.updateComplete;
29
- });
30
-
31
- it('should render basic component', async () => {
32
- expect(sortSelectorContainer).to.exist;
33
- expect(desktopSortSelector).to.exist;
34
- });
35
-
36
- it('should render sort-by label', async () => {
37
- const sortByLabel = el.shadowRoot?.querySelector('.sort-by-text');
38
- expect(sortByLabel).to.exist;
39
- expect(sortByLabel?.textContent?.trim()).to.equal('Sort by:');
40
- });
41
-
42
- it('should render sort direction button', async () => {
43
- const sortDirections = el.shadowRoot?.querySelector(
44
- '.sort-direction-container',
45
- );
46
- expect(sortDirections).to.exist;
47
- expect(sortDirections?.querySelector('.sort-direction-icon')).to.exist;
48
- });
49
-
50
- it('renders default set of sort options if not overridden', async () => {
51
- const allSortSelectors = desktopSortSelector?.querySelectorAll(
52
- 'button',
53
- ) as NodeListOf<HTMLButtonElement>;
54
- expect(allSortSelectors).to.exist;
55
- expect(allSortSelectors.length).to.equal(3);
56
- expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
57
- expect(allSortSelectors[1]?.textContent?.trim()).to.equal('Title');
58
- expect(allSortSelectors[2]?.textContent?.trim()).to.equal('Creator');
59
-
60
- const allSortDropdowns = desktopSortSelector?.querySelectorAll(
61
- 'ia-dropdown',
62
- ) as NodeListOf<IaDropdown>;
63
- expect(allSortDropdowns).to.exist;
64
- expect(allSortDropdowns.length).to.equal(2);
65
-
66
- expect(allSortDropdowns[0]?.options.length).to.equal(2);
67
- expect(allSortDropdowns[0]?.options.map(o => o.id)).to.deep.equal([
68
- SortField.weeklyview,
69
- SortField.alltimeview,
70
- ]);
71
- expect(allSortDropdowns[0]?.textContent?.trim()).to.equal('Weekly views');
72
-
73
- expect(allSortDropdowns[1]?.options.length).to.equal(4);
74
- expect(allSortDropdowns[1]?.options.map(o => o.id)).to.deep.equal([
75
- SortField.date,
76
- SortField.datearchived,
77
- SortField.datereviewed,
78
- SortField.dateadded,
79
- ]);
80
- expect(allSortDropdowns[1]?.textContent?.trim()).to.equal('Date published');
81
-
82
- // Relevance selected by default
83
- const defaultSortSelector =
84
- desktopSortSelector?.querySelector('button.selected');
85
- expect(defaultSortSelector?.textContent?.trim()).to.equal('Relevance');
86
- });
87
-
88
- it('renders an overridden set of sort options if specified', async () => {
89
- const customSortAvailability: Record<SortField, boolean> = {
90
- ...defaultSortAvailability,
91
- [SortField.title]: false,
92
- [SortField.datefavorited]: true,
93
- [SortField.datearchived]: false,
94
- [SortField.datereviewed]: false,
95
- [SortField.creator]: false,
96
- };
97
-
98
- el.sortFieldAvailability = customSortAvailability;
99
- await el.updateComplete;
100
-
101
- const allSortSelectors = desktopSortSelector?.querySelectorAll(
102
- 'button',
103
- ) as NodeListOf<HTMLButtonElement>;
104
- expect(allSortSelectors).to.exist;
105
- expect(allSortSelectors.length).to.equal(1);
106
- expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
107
-
108
- const allSortDropdowns = desktopSortSelector?.querySelectorAll(
109
- 'ia-dropdown',
110
- ) as NodeListOf<IaDropdown>;
111
- expect(allSortDropdowns).to.exist;
112
- expect(allSortDropdowns.length).to.equal(2);
113
-
114
- expect(allSortDropdowns[0]?.options.length).to.equal(2);
115
- expect(allSortDropdowns[0]?.options.map(o => o.id)).to.deep.equal([
116
- SortField.weeklyview,
117
- SortField.alltimeview,
118
- ]);
119
-
120
- expect(allSortDropdowns[1]?.options.length).to.equal(3);
121
- expect(allSortDropdowns[1]?.options.map(o => o.id)).to.deep.equal([
122
- SortField.datefavorited,
123
- SortField.date,
124
- SortField.dateadded,
125
- ]);
126
- });
127
-
128
- it('renders a views button instead of a dropdown if it would only have one option', async () => {
129
- const customSortAvailability: Record<SortField, boolean> = {
130
- ...defaultSortAvailability,
131
- // Disable weekly views (but keep All-time Views)
132
- [SortField.weeklyview]: false,
133
- };
134
-
135
- el.sortFieldAvailability = customSortAvailability;
136
- await el.updateComplete;
137
-
138
- const allSortSelectors = desktopSortSelector?.querySelectorAll(
139
- 'button',
140
- ) as NodeListOf<HTMLButtonElement>;
141
- expect(allSortSelectors).to.exist;
142
- expect(allSortSelectors.length).to.equal(4);
143
- expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
144
- expect(allSortSelectors[1]?.textContent?.trim()).to.equal('All-time views');
145
- expect(allSortSelectors[2]?.textContent?.trim()).to.equal('Title');
146
- expect(allSortSelectors[3]?.textContent?.trim()).to.equal('Creator');
147
-
148
- const allSortDropdowns = desktopSortSelector?.querySelectorAll(
149
- 'ia-dropdown',
150
- ) as NodeListOf<IaDropdown>;
151
- expect(allSortDropdowns).to.exist;
152
- expect(allSortDropdowns.length).to.equal(1);
153
- });
154
-
155
- it('renders a date button instead of a dropdown if it would only have one option', async () => {
156
- const customSortAvailability: Record<SortField, boolean> = {
157
- ...defaultSortAvailability,
158
- // Disable all default dates except Date Added
159
- [SortField.date]: false,
160
- [SortField.datearchived]: false,
161
- [SortField.datereviewed]: false,
162
- };
163
-
164
- el.sortFieldAvailability = customSortAvailability;
165
- await el.updateComplete;
166
-
167
- const allSortSelectors = desktopSortSelector?.querySelectorAll(
168
- 'button',
169
- ) as NodeListOf<HTMLButtonElement>;
170
- expect(allSortSelectors).to.exist;
171
- expect(allSortSelectors.length).to.equal(4);
172
- expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
173
- expect(allSortSelectors[1]?.textContent?.trim()).to.equal('Title');
174
- expect(allSortSelectors[2]?.textContent?.trim()).to.equal('Date added');
175
- expect(allSortSelectors[3]?.textContent?.trim()).to.equal('Creator');
176
-
177
- const allSortDropdowns = desktopSortSelector?.querySelectorAll(
178
- 'ia-dropdown',
179
- ) as NodeListOf<IaDropdown>;
180
- expect(allSortDropdowns).to.exist;
181
- expect(allSortDropdowns.length).to.equal(1);
182
- });
183
-
184
- it('does not render a views dropdown that would have zero available options', async () => {
185
- const customSortAvailability: Record<SortField, boolean> = {
186
- ...defaultSortAvailability,
187
- // Disable all view sorts
188
- [SortField.weeklyview]: false,
189
- [SortField.alltimeview]: false,
190
- };
191
-
192
- el.sortFieldAvailability = customSortAvailability;
193
- await el.updateComplete;
194
-
195
- const allSortSelectors = desktopSortSelector?.querySelectorAll(
196
- 'button',
197
- ) as NodeListOf<HTMLButtonElement>;
198
- expect(allSortSelectors).to.exist;
199
- expect(allSortSelectors.length).to.equal(3);
200
-
201
- const allSortDropdowns = desktopSortSelector?.querySelectorAll(
202
- 'ia-dropdown',
203
- ) as NodeListOf<IaDropdown>;
204
- expect(allSortDropdowns).to.exist;
205
- expect(allSortDropdowns.length).to.equal(1);
206
- expect(allSortDropdowns[0].options?.[0]?.id).to.equal(SortField.date);
207
- });
208
-
209
- it('does not render a date dropdown that would have zero available options', async () => {
210
- const customSortAvailability: Record<SortField, boolean> = {
211
- ...defaultSortAvailability,
212
- // Disable all date sorts
213
- [SortField.date]: false,
214
- [SortField.dateadded]: false,
215
- [SortField.datearchived]: false,
216
- [SortField.datereviewed]: false,
217
- };
218
-
219
- el.sortFieldAvailability = customSortAvailability;
220
- await el.updateComplete;
221
-
222
- const allSortSelectors = desktopSortSelector?.querySelectorAll(
223
- 'button',
224
- ) as NodeListOf<HTMLButtonElement>;
225
- expect(allSortSelectors).to.exist;
226
- expect(allSortSelectors.length).to.equal(3);
227
-
228
- const allSortDropdowns = desktopSortSelector?.querySelectorAll(
229
- 'ia-dropdown',
230
- ) as NodeListOf<IaDropdown>;
231
- expect(allSortDropdowns).to.exist;
232
- expect(allSortDropdowns.length).to.equal(1);
233
- expect(allSortDropdowns[0].options?.[0]?.id).to.equal(SortField.weeklyview);
234
- });
235
-
236
- it('allows changing the default views sort shown', async () => {
237
- el.defaultViewSort = SortField.alltimeview;
238
- await el.updateComplete;
239
-
240
- const viewsDropdown = el.shadowRoot?.querySelector(
241
- '#views-dropdown',
242
- ) as IaDropdown;
243
- expect(viewsDropdown).to.exist;
244
- expect(viewsDropdown.textContent?.trim()).to.equal('All-time views');
245
- });
246
-
247
- it('allows changing the default date sort shown', async () => {
248
- el.defaultDateSort = SortField.datereviewed;
249
- await el.updateComplete;
250
-
251
- const dateDropdown = el.shadowRoot?.querySelector(
252
- '#date-dropdown',
253
- ) as IaDropdown;
254
- expect(dateDropdown).to.exist;
255
- expect(dateDropdown.textContent?.trim()).to.equal('Date reviewed');
256
- });
257
-
258
- it('should render default view-sort selector', async () => {
259
- const defaultSortSelector = desktopSortSelector?.children
260
- .item(1)
261
- ?.querySelector('ia-dropdown');
262
- expect(defaultSortSelector?.textContent?.trim()).to.equal('Weekly views');
263
- });
264
-
265
- it('should render active view-sort selectors', async () => {
266
- el.selectedSort = 'alltimeview' as SortField;
267
- await el.updateComplete;
268
-
269
- const defaultSortSelector = desktopSortSelector?.querySelector(
270
- 'ia-dropdown.selected',
271
- );
272
- expect(defaultSortSelector?.textContent?.trim()).to.equal('All-time views');
273
- });
274
-
275
- it('should render default title-sort selector', async () => {
276
- const defaultSortSelector = desktopSortSelector?.children
277
- .item(2)
278
- ?.querySelector('button');
279
- expect(defaultSortSelector?.textContent?.trim()).to.equal('Title');
280
- });
281
-
282
- it('should render default date-sort selector', async () => {
283
- const defaultSortSelector = desktopSortSelector?.children
284
- .item(3)
285
- ?.querySelector('ia-dropdown');
286
- expect(defaultSortSelector?.textContent?.trim()).to.equal('Date published');
287
- });
288
-
289
- it('should render active date-sort selectors', async () => {
290
- el.selectedSort = 'datereviewed' as SortField;
291
- await el.updateComplete;
292
-
293
- const defaultSortSelector = desktopSortSelector?.querySelector(
294
- 'ia-dropdown.selected',
295
- );
296
- expect(defaultSortSelector?.textContent?.trim()).to.equal('Date reviewed');
297
- });
298
-
299
- it('should render default creator-sort selector', async () => {
300
- const defaultSortSelector = desktopSortSelector?.children
301
- .item(4)
302
- ?.querySelector('button');
303
- expect(defaultSortSelector?.textContent?.trim()).to.equal('Creator');
304
- });
305
-
306
- it('handles click event on view-sort selector', async () => {
307
- const defaultSortSelector = desktopSortSelector?.children
308
- .item(1)
309
- ?.querySelector('.dropdown-label') as HTMLElement;
310
-
311
- defaultSortSelector?.click();
312
- await el.updateComplete;
313
-
314
- expect(el.selectedSort).to.equal('weeklyview');
315
- });
316
-
317
- it('handles click event on title selector', async () => {
318
- const defaultSortSelector = desktopSortSelector?.children
319
- .item(2)
320
- ?.querySelector('button');
321
-
322
- defaultSortSelector?.click();
323
- await el.updateComplete;
324
-
325
- expect(el.selectedSort).to.equal('title');
326
- });
327
-
328
- it('handles click event on date-sort selector', async () => {
329
- const defaultSortSelector = desktopSortSelector?.children
330
- .item(3)
331
- ?.querySelector('.dropdown-label') as HTMLElement;
332
-
333
- defaultSortSelector?.click();
334
- await el.updateComplete;
335
-
336
- expect(el.selectedSort).to.equal('date');
337
- });
338
-
339
- it('handles click event on creator selector', async () => {
340
- const defaultSortSelector = desktopSortSelector?.children
341
- .item(4)
342
- ?.querySelector('button');
343
-
344
- defaultSortSelector?.click();
345
- await el.updateComplete;
346
-
347
- expect(el.selectedSort).to.equal('creator');
348
- });
349
-
350
- it('handles click event on relevance selector', async () => {
351
- el.sortFieldAvailability = {
352
- ...el.sortFieldAvailability,
353
- [SortField.relevance]: true,
354
- };
355
- el.selectedSort = 'title' as SortField;
356
- await el.updateComplete;
357
-
358
- const defaultSortSelector = desktopSortSelector?.children
359
- .item(0)
360
- ?.querySelector('button');
361
-
362
- defaultSortSelector?.click();
363
- await el.updateComplete;
364
-
365
- expect(el.selectedSort).to.equal('relevance');
366
- });
367
-
368
- it('handles return/space key event on view-sort selector', async () => {
369
- const defaultSortSelector = desktopSortSelector?.children
370
- .item(1)
371
- ?.querySelector('.dropdown-label') as HTMLElement;
372
-
373
- el.selectedSort = 'relevance' as SortField;
374
- const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
375
- defaultSortSelector?.dispatchEvent(enterEvent);
376
- await el.updateComplete;
377
-
378
- expect(el.selectedSort).to.equal('weeklyview');
379
-
380
- el.selectedSort = 'relevance' as SortField;
381
- const spaceEvent = new KeyboardEvent('keydown', { key: ' ' });
382
- defaultSortSelector?.dispatchEvent(spaceEvent);
383
- await el.updateComplete;
384
-
385
- expect(el.selectedSort).to.equal('weeklyview');
386
- });
387
-
388
- it('handles return/space key event on date-sort selector', async () => {
389
- const defaultSortSelector = desktopSortSelector?.children
390
- .item(3)
391
- ?.querySelector('.dropdown-label') as HTMLElement;
392
-
393
- el.selectedSort = 'relevance' as SortField;
394
- const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
395
- defaultSortSelector?.dispatchEvent(enterEvent);
396
- await el.updateComplete;
397
-
398
- expect(el.selectedSort).to.equal('date');
399
-
400
- el.selectedSort = 'relevance' as SortField;
401
- const spaceEvent = new KeyboardEvent('keydown', { key: ' ' });
402
- defaultSortSelector?.dispatchEvent(spaceEvent);
403
- await el.updateComplete;
404
-
405
- expect(el.selectedSort).to.equal('date');
406
- });
407
-
408
- it('handles click event on view-sort dropdown option', async () => {
409
- const defaultSortSelector = desktopSortSelector?.children
410
- .item(1)
411
- ?.querySelector('ia-dropdown') as IaDropdown;
412
-
413
- const firstOption = defaultSortSelector?.shadowRoot?.querySelector(
414
- 'li > button',
415
- ) as HTMLButtonElement;
416
- expect(firstOption).to.exist;
417
-
418
- firstOption?.click();
419
- await el.updateComplete;
420
-
421
- expect(el.selectedSort).to.equal('weeklyview');
422
- });
423
-
424
- it('handles click event on date-sort dropdown option', async () => {
425
- const defaultSortSelector = desktopSortSelector?.children
426
- .item(3)
427
- ?.querySelector('ia-dropdown') as IaDropdown;
428
-
429
- const firstOption = defaultSortSelector?.shadowRoot?.querySelector(
430
- 'li > button',
431
- ) as HTMLButtonElement;
432
- expect(firstOption).to.exist;
433
-
434
- firstOption?.click();
435
- await el.updateComplete;
436
-
437
- expect(el.selectedSort).to.equal('date');
438
- });
439
-
440
- it('shows view sort selector backdrop when view sort open', async () => {
441
- const defaultSortSelector = desktopSortSelector?.children
442
- .item(1)
443
- ?.querySelector('ia-dropdown') as IaDropdown;
444
-
445
- const caret = defaultSortSelector?.shadowRoot?.querySelector(
446
- '.caret',
447
- ) as HTMLElement;
448
- expect(caret).to.exist;
449
-
450
- caret?.click();
451
- await el.updateComplete;
452
-
453
- let backdrop = el.shadowRoot?.querySelector(
454
- '#sort-selector-backdrop',
455
- ) as HTMLElement;
456
- expect(backdrop).to.exist;
457
-
458
- backdrop?.click();
459
- await el.updateComplete;
460
-
461
- backdrop = el.shadowRoot?.querySelector(
462
- '#sort-selector-backdrop',
463
- ) as HTMLElement;
464
- expect(backdrop).not.to.exist;
465
- });
466
-
467
- it('shows date sort selector backdrop when date sort open', async () => {
468
- const defaultSortSelector = desktopSortSelector?.children
469
- .item(3)
470
- ?.querySelector('ia-dropdown') as IaDropdown;
471
-
472
- const caret = defaultSortSelector?.shadowRoot?.querySelector(
473
- '.caret',
474
- ) as HTMLElement;
475
- expect(caret).to.exist;
476
-
477
- caret?.click();
478
- await el.updateComplete;
479
-
480
- let backdrop = el.shadowRoot?.querySelector(
481
- '#sort-selector-backdrop',
482
- ) as HTMLElement;
483
- expect(backdrop).to.exist;
484
-
485
- backdrop?.click();
486
- await el.updateComplete;
487
-
488
- backdrop = el.shadowRoot?.querySelector(
489
- '#sort-selector-backdrop',
490
- ) as HTMLElement;
491
- expect(backdrop).not.to.exist;
492
- });
493
-
494
- it('closes dropdown by hitting escape key', async () => {
495
- const defaultSortSelector = desktopSortSelector?.children
496
- .item(3)
497
- ?.querySelector('ia-dropdown') as IaDropdown;
498
-
499
- const caret = defaultSortSelector?.shadowRoot?.querySelector(
500
- '.caret',
501
- ) as HTMLElement;
502
- expect(caret).to.exist;
503
-
504
- caret?.click();
505
- await el.updateComplete;
506
-
507
- let backdrop = el.shadowRoot?.querySelector(
508
- '#sort-selector-backdrop',
509
- ) as HTMLElement;
510
- expect(backdrop).to.exist;
511
-
512
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
513
- await el.updateComplete;
514
-
515
- backdrop = el.shadowRoot?.querySelector(
516
- '#sort-selector-backdrop',
517
- ) as HTMLElement;
518
- expect(backdrop).not.to.exist;
519
- });
520
- });
521
-
522
- describe('Sort direction button behavior', () => {
523
- it('should disable sort direction button when sorting by relevance', async () => {
524
- const el = await fixture<SortFilterBar>(html`
525
- <sort-filter-bar> </sort-filter-bar>
526
- `);
527
-
528
- el.selectedSort = 'relevance' as SortField;
529
- await el.updateComplete;
530
-
531
- const sortDirectionButton = el.shadowRoot?.querySelector(
532
- '.sort-direction-selector',
533
- ) as HTMLButtonElement;
534
- expect(sortDirectionButton).to.exist;
535
- expect(sortDirectionButton.disabled).to.be.true;
536
- });
537
-
538
- it('should enable sort direction button when not sorting by relevance', async () => {
539
- const el = await fixture<SortFilterBar>(html`
540
- <sort-filter-bar> </sort-filter-bar>
541
- `);
542
-
543
- el.selectedSort = 'title' as SortField;
544
- await el.updateComplete;
545
-
546
- const sortDirectionButton = el.shadowRoot?.querySelector(
547
- '.sort-direction-selector',
548
- ) as HTMLButtonElement;
549
- expect(sortDirectionButton).to.exist;
550
- expect(sortDirectionButton.disabled).to.be.false;
551
- });
552
-
553
- it('should toggle sort direction when clicked', async () => {
554
- const el = await fixture<SortFilterBar>(html`
555
- <sort-filter-bar> </sort-filter-bar>
556
- `);
557
-
558
- el.selectedSort = 'title' as SortField;
559
- el.sortDirection = 'asc';
560
- await el.updateComplete;
561
-
562
- const sortDirectionButton = el.shadowRoot?.querySelector(
563
- '.sort-direction-selector',
564
- ) as HTMLButtonElement;
565
-
566
- sortDirectionButton.click();
567
- await el.updateComplete;
568
- expect(el.sortDirection).to.equal('desc');
569
-
570
- sortDirectionButton.click();
571
- await el.updateComplete;
572
- expect(el.sortDirection).to.equal('asc');
573
- });
574
- });
575
-
576
- describe('Display mode/style buttons', () => {
577
- it('should render all display mode buttons', async () => {
578
- const el = await fixture<SortFilterBar>(html`
579
- <sort-filter-bar> </sort-filter-bar>
580
- `);
581
-
582
- const displayModeButtonList = el.shadowRoot
583
- ?.querySelector('#display-style-selector')
584
- ?.querySelector('ul');
585
-
586
- const gridButton = displayModeButtonList?.children
587
- .item(0)
588
- ?.querySelector('#grid-button');
589
- expect(gridButton).to.exist;
590
-
591
- const detailListButton = displayModeButtonList?.children
592
- .item(1)
593
- ?.querySelector('#list-detail-button');
594
- expect(detailListButton).to.exist;
595
-
596
- const compactListButton = displayModeButtonList?.children
597
- .item(2)
598
- ?.querySelector('#list-compact-button');
599
- expect(compactListButton).to.exist;
600
- });
601
-
602
- it('should not render display mode buttons when suppressed', async () => {
603
- const el = await fixture<SortFilterBar>(html`
604
- <sort-filter-bar suppressDisplayModes></sort-filter-bar>
605
- `);
606
-
607
- const displayModeButtonList = el.shadowRoot?.querySelector(
608
- '#display-style-selector',
609
- );
610
- expect(displayModeButtonList).not.to.exist;
611
- });
612
-
613
- it('should active current display mode', async () => {
614
- const el = await fixture<SortFilterBar>(html`
615
- <sort-filter-bar> </sort-filter-bar>
616
- `);
617
-
618
- el.displayMode = 'grid';
619
- await el.updateComplete;
620
-
621
- const displayModeTitle = el.shadowRoot
622
- ?.querySelector('#display-style-selector')
623
- ?.querySelector('button.active')
624
- ?.getAttribute('title');
625
- expect(displayModeTitle).to.equal('Tile view');
626
- });
627
-
628
- it('should change displayMode prop to the one clicked', async () => {
629
- const el = await fixture<SortFilterBar>(html`
630
- <sort-filter-bar> </sort-filter-bar>
631
- `);
632
-
633
- el.displayMode = 'grid';
634
- await el.updateComplete;
635
-
636
- const extendedListButton = el.shadowRoot?.querySelector(
637
- '#list-detail-button',
638
- ) as HTMLElement;
639
- extendedListButton.click();
640
- await el.updateComplete;
641
- expect(el.displayMode).to.equal('list-detail');
642
-
643
- const compactListButton = el.shadowRoot?.querySelector(
644
- '#list-compact-button',
645
- ) as HTMLElement;
646
- compactListButton.click();
647
- await el.updateComplete;
648
- expect(el.displayMode).to.equal('list-compact');
649
-
650
- const gridModeButton = el.shadowRoot?.querySelector(
651
- '#grid-button',
652
- ) as HTMLElement;
653
- gridModeButton.click();
654
- await el.updateComplete;
655
- expect(el.displayMode).to.equal('grid');
656
- });
657
- });
658
-
659
- describe('Sort/filter bar letter behavior', () => {
660
- it('sets the selected title letter when clicked', async () => {
661
- const el = await fixture<SortFilterBar>(html`
662
- <sort-filter-bar></sort-filter-bar>
663
- `);
664
-
665
- el.selectedSort = 'title' as SortField;
666
- el.prefixFilterCountMap = { title: { T: 1 }, creator: {} };
667
- await el.updateComplete;
668
-
669
- const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
670
- const letterLink = alphaBar?.shadowRoot?.querySelector(
671
- 'li > button:not(:disabled)',
672
- ) as HTMLAnchorElement;
673
- expect(letterLink?.textContent?.trim()).to.equal('T');
674
-
675
- letterLink?.click();
676
- await el.updateComplete;
677
-
678
- expect(el.selectedTitleFilter).to.equal('T');
679
- });
680
-
681
- it('sets the selected creator letter when clicked', async () => {
682
- const el = await fixture<SortFilterBar>(html`
683
- <sort-filter-bar></sort-filter-bar>
684
- `);
685
-
686
- el.selectedSort = 'creator' as SortField;
687
- el.prefixFilterCountMap = { title: {}, creator: { C: 1 } };
688
- await el.updateComplete;
689
-
690
- const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
691
- const letterLink = alphaBar?.shadowRoot?.querySelector(
692
- 'li > button:not(:disabled)',
693
- ) as HTMLAnchorElement;
694
- expect(letterLink?.textContent?.trim()).to.equal('C');
695
-
696
- letterLink?.click();
697
- await el.updateComplete;
698
-
699
- expect(el.selectedCreatorFilter).to.equal('C');
700
- });
701
- });
702
-
703
- describe('Sort/filter bar mobile view', () => {
704
- let origWindowSize: { width: number; height: number };
705
- before(() => {
706
- origWindowSize = { width: window.innerWidth, height: window.innerHeight };
707
- window.resizeTo(500, 600);
708
- });
709
-
710
- after(() => {
711
- window.resizeTo(origWindowSize.width, origWindowSize.height);
712
- });
713
-
714
- it('renders in mobile view', async () => {
715
- const el = await fixture<SortFilterBar>(html`
716
- <sort-filter-bar></sort-filter-bar>
717
- `);
718
-
719
- const mobileSortContainer = el.shadowRoot?.querySelector(
720
- '#mobile-sort-container',
721
- );
722
- const desktopSortContainer = el.shadowRoot?.querySelector(
723
- '#desktop-sort-container',
724
- );
725
-
726
- expect(mobileSortContainer?.classList?.contains('visible')).to.be.true;
727
- expect(desktopSortContainer?.classList?.contains('hidden')).to.be.true;
728
- });
729
-
730
- it('changes selected sort in mobile view', async () => {
731
- const el = await fixture<SortFilterBar>(html`
732
- <sort-filter-bar></sort-filter-bar>
733
- `);
734
-
735
- const mobileDropdown = el.shadowRoot?.querySelector(
736
- '#mobile-dropdown',
737
- ) as IaDropdown;
738
- expect(mobileDropdown).to.exist;
739
-
740
- mobileDropdown.selectedOption = 'title';
741
- const option = { id: 'title' };
742
- mobileDropdown.dispatchEvent(
743
- new CustomEvent('optionSelected', { detail: { option } }),
744
- );
745
- await el.updateComplete;
746
-
747
- expect(el.selectedSort).to.equal('title');
748
- });
749
-
750
- it('clears title filter when sort changed from title in mobile view', async () => {
751
- const el = await fixture<SortFilterBar>(html`
752
- <sort-filter-bar></sort-filter-bar>
753
- `);
754
-
755
- el.selectedSort = 'title' as SortField;
756
- el.selectedTitleFilter = 'A';
757
- await el.updateComplete;
758
-
759
- const mobileDropdown = el.shadowRoot?.querySelector(
760
- '#mobile-dropdown',
761
- ) as IaDropdown;
762
- expect(mobileDropdown).to.exist;
763
-
764
- mobileDropdown.selectedOption = 'relevance';
765
- const option = { id: 'relevance' };
766
- mobileDropdown.dispatchEvent(
767
- new CustomEvent('optionSelected', { detail: { option } }),
768
- );
769
- await el.updateComplete;
770
-
771
- expect(el.selectedSort).to.equal('relevance');
772
- expect(el.selectedTitleFilter).to.be.null;
773
- });
774
-
775
- it('clears creator filter when sort changed from creator in mobile view', async () => {
776
- const el = await fixture<SortFilterBar>(html`
777
- <sort-filter-bar></sort-filter-bar>
778
- `);
779
-
780
- el.selectedSort = 'creator' as SortField;
781
- el.selectedCreatorFilter = 'A';
782
- await el.updateComplete;
783
-
784
- const mobileDropdown = el.shadowRoot?.querySelector(
785
- '#mobile-dropdown',
786
- ) as IaDropdown;
787
- expect(mobileDropdown).to.exist;
788
-
789
- mobileDropdown.selectedOption = 'relevance';
790
- const option = { id: 'relevance' };
791
- mobileDropdown.dispatchEvent(
792
- new CustomEvent('optionSelected', { detail: { option } }),
793
- );
794
- await el.updateComplete;
795
-
796
- expect(el.selectedSort).to.equal('relevance');
797
- expect(el.selectedCreatorFilter).to.be.null;
798
- });
799
-
800
- it('shows sort selector backdrop when mobile sort open', async () => {
801
- const el = await fixture<SortFilterBar>(html`
802
- <sort-filter-bar></sort-filter-bar>
803
- `);
804
-
805
- const mobileDropdown = el.shadowRoot?.querySelector(
806
- '#mobile-dropdown',
807
- ) as IaDropdown;
808
- expect(mobileDropdown).to.exist;
809
-
810
- const caret = mobileDropdown?.shadowRoot?.querySelector(
811
- '.caret',
812
- ) as HTMLElement;
813
- expect(caret).to.exist;
814
-
815
- caret?.click();
816
- await el.updateComplete;
817
-
818
- let backdrop = el.shadowRoot?.querySelector(
819
- '#sort-selector-backdrop',
820
- ) as HTMLElement;
821
- expect(backdrop).to.exist;
822
-
823
- backdrop?.click();
824
- await el.updateComplete;
825
-
826
- backdrop = el.shadowRoot?.querySelector(
827
- '#sort-selector-backdrop',
828
- ) as HTMLElement;
829
- expect(backdrop).not.to.exist;
830
- });
831
-
832
- it('shows loansTab top-bar slot Default View', async () => {
833
- const resizeStub = new SharedResizeObserver();
834
- const addSpy = sinon.spy(resizeStub, 'addObserver');
835
- const removeSpy = sinon.spy(resizeStub, 'removeObserver');
836
-
837
- const el = await fixture<SortFilterBar>(html`
838
- <sort-filter-bar .resizeObserver=${resizeStub}></sort-filter-bar>
839
- `);
840
-
841
- // this element exists
842
- expect(el?.shadowRoot?.querySelector('#sort-selector-container')).to.exist;
843
-
844
- // loads & unloads twice when [re]setting ResizeObserver
845
- expect(addSpy.callCount).to.equal(2);
846
-
847
- const resizeStub2 = new SharedResizeObserver();
848
- el.resizeObserver = resizeStub2;
849
- await el.updateComplete;
850
- expect(removeSpy.callCount).to.equal(2);
851
- });
852
-
853
- it('contains sort-options slot when enabled', async () => {
854
- const resizeStub = new SharedResizeObserver();
855
- const addSpy = sinon.spy(resizeStub, 'addObserver');
856
- const removeSpy = sinon.spy(resizeStub, 'removeObserver');
857
-
858
- const el = await fixture<SortFilterBar>(html`
859
- <sort-filter-bar
860
- .resizeObserver=${resizeStub}
861
- .enableSortOptionsSlot=${true}
862
- ></sort-filter-bar>
863
- `);
864
-
865
- await el.updateComplete;
866
-
867
- // slot exists
868
- const sortOptionsSlot = el?.shadowRoot?.querySelector(
869
- 'slot[name="sort-options"]',
870
- );
871
- expect(sortOptionsSlot).to.exist;
872
-
873
- // sort bar does not exist
874
- expect(el?.shadowRoot?.querySelector('#sort-selector-container')).to.not
875
- .exist;
876
-
877
- const resizeStub2 = new SharedResizeObserver();
878
- el.resizeObserver = resizeStub2;
879
- await el.updateComplete;
880
-
881
- // there's no need for resize observer
882
- expect(addSpy.callCount).to.equal(0);
883
- expect(removeSpy.callCount).to.equal(0);
884
- });
885
- });
1
+ import { expect, fixture } from '@open-wc/testing';
2
+ import sinon from 'sinon';
3
+ import { html } from 'lit';
4
+ import type { IaDropdown } from '@internetarchive/ia-dropdown';
5
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
6
+ import type { SortFilterBar } from '../../src/sort-filter-bar/sort-filter-bar';
7
+ import { SortField, defaultSortAvailability } from '../../src/models';
8
+
9
+ import '../../src/sort-filter-bar/sort-filter-bar';
10
+
11
+ describe('Sort selector default buttons', async () => {
12
+ let el: SortFilterBar;
13
+ let sortSelectorContainer: HTMLElement | null | undefined;
14
+ let desktopSortSelector: HTMLElement | null | undefined;
15
+
16
+ beforeEach(async () => {
17
+ el = await fixture<SortFilterBar>(html`
18
+ <sort-filter-bar></sort-filter-bar>
19
+ `);
20
+ sortSelectorContainer = el.shadowRoot?.querySelector(
21
+ '#sort-selector-container',
22
+ );
23
+ desktopSortSelector = sortSelectorContainer?.querySelector(
24
+ '#desktop-sort-selector',
25
+ );
26
+
27
+ el.resizeObserver = new SharedResizeObserver();
28
+ await el.updateComplete;
29
+ });
30
+
31
+ it('should render basic component', async () => {
32
+ expect(sortSelectorContainer).to.exist;
33
+ expect(desktopSortSelector).to.exist;
34
+ });
35
+
36
+ it('should render sort-by label', async () => {
37
+ const sortByLabel = el.shadowRoot?.querySelector('.sort-by-text');
38
+ expect(sortByLabel).to.exist;
39
+ expect(sortByLabel?.textContent?.trim()).to.equal('Sort by:');
40
+ });
41
+
42
+ it('should render sort direction button', async () => {
43
+ const sortDirections = el.shadowRoot?.querySelector(
44
+ '.sort-direction-container',
45
+ );
46
+ expect(sortDirections).to.exist;
47
+ expect(sortDirections?.querySelector('.sort-direction-icon')).to.exist;
48
+ });
49
+
50
+ it('renders default set of sort options if not overridden', async () => {
51
+ const allSortSelectors = desktopSortSelector?.querySelectorAll(
52
+ 'button',
53
+ ) as NodeListOf<HTMLButtonElement>;
54
+ expect(allSortSelectors).to.exist;
55
+ expect(allSortSelectors.length).to.equal(3);
56
+ expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
57
+ expect(allSortSelectors[1]?.textContent?.trim()).to.equal('Title');
58
+ expect(allSortSelectors[2]?.textContent?.trim()).to.equal('Creator');
59
+
60
+ const allSortDropdowns = desktopSortSelector?.querySelectorAll(
61
+ 'ia-dropdown',
62
+ ) as NodeListOf<IaDropdown>;
63
+ expect(allSortDropdowns).to.exist;
64
+ expect(allSortDropdowns.length).to.equal(2);
65
+
66
+ expect(allSortDropdowns[0]?.options.length).to.equal(2);
67
+ expect(allSortDropdowns[0]?.options.map(o => o.id)).to.deep.equal([
68
+ SortField.weeklyview,
69
+ SortField.alltimeview,
70
+ ]);
71
+ expect(allSortDropdowns[0]?.textContent?.trim()).to.equal('Weekly views');
72
+
73
+ expect(allSortDropdowns[1]?.options.length).to.equal(4);
74
+ expect(allSortDropdowns[1]?.options.map(o => o.id)).to.deep.equal([
75
+ SortField.date,
76
+ SortField.datearchived,
77
+ SortField.datereviewed,
78
+ SortField.dateadded,
79
+ ]);
80
+ expect(allSortDropdowns[1]?.textContent?.trim()).to.equal('Date published');
81
+
82
+ // Relevance selected by default
83
+ const defaultSortSelector =
84
+ desktopSortSelector?.querySelector('button.selected');
85
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('Relevance');
86
+ });
87
+
88
+ it('renders an overridden set of sort options if specified', async () => {
89
+ const customSortAvailability: Record<SortField, boolean> = {
90
+ ...defaultSortAvailability,
91
+ [SortField.title]: false,
92
+ [SortField.datefavorited]: true,
93
+ [SortField.datearchived]: false,
94
+ [SortField.datereviewed]: false,
95
+ [SortField.creator]: false,
96
+ };
97
+
98
+ el.sortFieldAvailability = customSortAvailability;
99
+ await el.updateComplete;
100
+
101
+ const allSortSelectors = desktopSortSelector?.querySelectorAll(
102
+ 'button',
103
+ ) as NodeListOf<HTMLButtonElement>;
104
+ expect(allSortSelectors).to.exist;
105
+ expect(allSortSelectors.length).to.equal(1);
106
+ expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
107
+
108
+ const allSortDropdowns = desktopSortSelector?.querySelectorAll(
109
+ 'ia-dropdown',
110
+ ) as NodeListOf<IaDropdown>;
111
+ expect(allSortDropdowns).to.exist;
112
+ expect(allSortDropdowns.length).to.equal(2);
113
+
114
+ expect(allSortDropdowns[0]?.options.length).to.equal(2);
115
+ expect(allSortDropdowns[0]?.options.map(o => o.id)).to.deep.equal([
116
+ SortField.weeklyview,
117
+ SortField.alltimeview,
118
+ ]);
119
+
120
+ expect(allSortDropdowns[1]?.options.length).to.equal(3);
121
+ expect(allSortDropdowns[1]?.options.map(o => o.id)).to.deep.equal([
122
+ SortField.datefavorited,
123
+ SortField.date,
124
+ SortField.dateadded,
125
+ ]);
126
+ });
127
+
128
+ it('renders a views button instead of a dropdown if it would only have one option', async () => {
129
+ const customSortAvailability: Record<SortField, boolean> = {
130
+ ...defaultSortAvailability,
131
+ // Disable weekly views (but keep All-time Views)
132
+ [SortField.weeklyview]: false,
133
+ };
134
+
135
+ el.sortFieldAvailability = customSortAvailability;
136
+ await el.updateComplete;
137
+
138
+ const allSortSelectors = desktopSortSelector?.querySelectorAll(
139
+ 'button',
140
+ ) as NodeListOf<HTMLButtonElement>;
141
+ expect(allSortSelectors).to.exist;
142
+ expect(allSortSelectors.length).to.equal(4);
143
+ expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
144
+ expect(allSortSelectors[1]?.textContent?.trim()).to.equal('All-time views');
145
+ expect(allSortSelectors[2]?.textContent?.trim()).to.equal('Title');
146
+ expect(allSortSelectors[3]?.textContent?.trim()).to.equal('Creator');
147
+
148
+ const allSortDropdowns = desktopSortSelector?.querySelectorAll(
149
+ 'ia-dropdown',
150
+ ) as NodeListOf<IaDropdown>;
151
+ expect(allSortDropdowns).to.exist;
152
+ expect(allSortDropdowns.length).to.equal(1);
153
+ });
154
+
155
+ it('renders a date button instead of a dropdown if it would only have one option', async () => {
156
+ const customSortAvailability: Record<SortField, boolean> = {
157
+ ...defaultSortAvailability,
158
+ // Disable all default dates except Date Added
159
+ [SortField.date]: false,
160
+ [SortField.datearchived]: false,
161
+ [SortField.datereviewed]: false,
162
+ };
163
+
164
+ el.sortFieldAvailability = customSortAvailability;
165
+ await el.updateComplete;
166
+
167
+ const allSortSelectors = desktopSortSelector?.querySelectorAll(
168
+ 'button',
169
+ ) as NodeListOf<HTMLButtonElement>;
170
+ expect(allSortSelectors).to.exist;
171
+ expect(allSortSelectors.length).to.equal(4);
172
+ expect(allSortSelectors[0]?.textContent?.trim()).to.equal('Relevance');
173
+ expect(allSortSelectors[1]?.textContent?.trim()).to.equal('Title');
174
+ expect(allSortSelectors[2]?.textContent?.trim()).to.equal('Date added');
175
+ expect(allSortSelectors[3]?.textContent?.trim()).to.equal('Creator');
176
+
177
+ const allSortDropdowns = desktopSortSelector?.querySelectorAll(
178
+ 'ia-dropdown',
179
+ ) as NodeListOf<IaDropdown>;
180
+ expect(allSortDropdowns).to.exist;
181
+ expect(allSortDropdowns.length).to.equal(1);
182
+ });
183
+
184
+ it('does not render a views dropdown that would have zero available options', async () => {
185
+ const customSortAvailability: Record<SortField, boolean> = {
186
+ ...defaultSortAvailability,
187
+ // Disable all view sorts
188
+ [SortField.weeklyview]: false,
189
+ [SortField.alltimeview]: false,
190
+ };
191
+
192
+ el.sortFieldAvailability = customSortAvailability;
193
+ await el.updateComplete;
194
+
195
+ const allSortSelectors = desktopSortSelector?.querySelectorAll(
196
+ 'button',
197
+ ) as NodeListOf<HTMLButtonElement>;
198
+ expect(allSortSelectors).to.exist;
199
+ expect(allSortSelectors.length).to.equal(3);
200
+
201
+ const allSortDropdowns = desktopSortSelector?.querySelectorAll(
202
+ 'ia-dropdown',
203
+ ) as NodeListOf<IaDropdown>;
204
+ expect(allSortDropdowns).to.exist;
205
+ expect(allSortDropdowns.length).to.equal(1);
206
+ expect(allSortDropdowns[0].options?.[0]?.id).to.equal(SortField.date);
207
+ });
208
+
209
+ it('does not render a date dropdown that would have zero available options', async () => {
210
+ const customSortAvailability: Record<SortField, boolean> = {
211
+ ...defaultSortAvailability,
212
+ // Disable all date sorts
213
+ [SortField.date]: false,
214
+ [SortField.dateadded]: false,
215
+ [SortField.datearchived]: false,
216
+ [SortField.datereviewed]: false,
217
+ };
218
+
219
+ el.sortFieldAvailability = customSortAvailability;
220
+ await el.updateComplete;
221
+
222
+ const allSortSelectors = desktopSortSelector?.querySelectorAll(
223
+ 'button',
224
+ ) as NodeListOf<HTMLButtonElement>;
225
+ expect(allSortSelectors).to.exist;
226
+ expect(allSortSelectors.length).to.equal(3);
227
+
228
+ const allSortDropdowns = desktopSortSelector?.querySelectorAll(
229
+ 'ia-dropdown',
230
+ ) as NodeListOf<IaDropdown>;
231
+ expect(allSortDropdowns).to.exist;
232
+ expect(allSortDropdowns.length).to.equal(1);
233
+ expect(allSortDropdowns[0].options?.[0]?.id).to.equal(SortField.weeklyview);
234
+ });
235
+
236
+ it('allows changing the default views sort shown', async () => {
237
+ el.defaultViewSort = SortField.alltimeview;
238
+ await el.updateComplete;
239
+
240
+ const viewsDropdown = el.shadowRoot?.querySelector(
241
+ '#views-dropdown',
242
+ ) as IaDropdown;
243
+ expect(viewsDropdown).to.exist;
244
+ expect(viewsDropdown.textContent?.trim()).to.equal('All-time views');
245
+ });
246
+
247
+ it('allows changing the default date sort shown', async () => {
248
+ el.defaultDateSort = SortField.datereviewed;
249
+ await el.updateComplete;
250
+
251
+ const dateDropdown = el.shadowRoot?.querySelector(
252
+ '#date-dropdown',
253
+ ) as IaDropdown;
254
+ expect(dateDropdown).to.exist;
255
+ expect(dateDropdown.textContent?.trim()).to.equal('Date reviewed');
256
+ });
257
+
258
+ it('should render default view-sort selector', async () => {
259
+ const defaultSortSelector = desktopSortSelector?.children
260
+ .item(1)
261
+ ?.querySelector('ia-dropdown');
262
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('Weekly views');
263
+ });
264
+
265
+ it('should render active view-sort selectors', async () => {
266
+ el.selectedSort = 'alltimeview' as SortField;
267
+ await el.updateComplete;
268
+
269
+ const defaultSortSelector = desktopSortSelector?.querySelector(
270
+ 'ia-dropdown.selected',
271
+ );
272
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('All-time views');
273
+ });
274
+
275
+ it('should render default title-sort selector', async () => {
276
+ const defaultSortSelector = desktopSortSelector?.children
277
+ .item(2)
278
+ ?.querySelector('button');
279
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('Title');
280
+ });
281
+
282
+ it('should render default date-sort selector', async () => {
283
+ const defaultSortSelector = desktopSortSelector?.children
284
+ .item(3)
285
+ ?.querySelector('ia-dropdown');
286
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('Date published');
287
+ });
288
+
289
+ it('should render active date-sort selectors', async () => {
290
+ el.selectedSort = 'datereviewed' as SortField;
291
+ await el.updateComplete;
292
+
293
+ const defaultSortSelector = desktopSortSelector?.querySelector(
294
+ 'ia-dropdown.selected',
295
+ );
296
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('Date reviewed');
297
+ });
298
+
299
+ it('should render default creator-sort selector', async () => {
300
+ const defaultSortSelector = desktopSortSelector?.children
301
+ .item(4)
302
+ ?.querySelector('button');
303
+ expect(defaultSortSelector?.textContent?.trim()).to.equal('Creator');
304
+ });
305
+
306
+ it('handles click event on view-sort selector', async () => {
307
+ const defaultSortSelector = desktopSortSelector?.children
308
+ .item(1)
309
+ ?.querySelector('.dropdown-label') as HTMLElement;
310
+
311
+ defaultSortSelector?.click();
312
+ await el.updateComplete;
313
+
314
+ expect(el.selectedSort).to.equal('weeklyview');
315
+ });
316
+
317
+ it('handles click event on title selector', async () => {
318
+ const defaultSortSelector = desktopSortSelector?.children
319
+ .item(2)
320
+ ?.querySelector('button');
321
+
322
+ defaultSortSelector?.click();
323
+ await el.updateComplete;
324
+
325
+ expect(el.selectedSort).to.equal('title');
326
+ });
327
+
328
+ it('handles click event on date-sort selector', async () => {
329
+ const defaultSortSelector = desktopSortSelector?.children
330
+ .item(3)
331
+ ?.querySelector('.dropdown-label') as HTMLElement;
332
+
333
+ defaultSortSelector?.click();
334
+ await el.updateComplete;
335
+
336
+ expect(el.selectedSort).to.equal('date');
337
+ });
338
+
339
+ it('handles click event on creator selector', async () => {
340
+ const defaultSortSelector = desktopSortSelector?.children
341
+ .item(4)
342
+ ?.querySelector('button');
343
+
344
+ defaultSortSelector?.click();
345
+ await el.updateComplete;
346
+
347
+ expect(el.selectedSort).to.equal('creator');
348
+ });
349
+
350
+ it('handles click event on relevance selector', async () => {
351
+ el.sortFieldAvailability = {
352
+ ...el.sortFieldAvailability,
353
+ [SortField.relevance]: true,
354
+ };
355
+ el.selectedSort = 'title' as SortField;
356
+ await el.updateComplete;
357
+
358
+ const defaultSortSelector = desktopSortSelector?.children
359
+ .item(0)
360
+ ?.querySelector('button');
361
+
362
+ defaultSortSelector?.click();
363
+ await el.updateComplete;
364
+
365
+ expect(el.selectedSort).to.equal('relevance');
366
+ });
367
+
368
+ it('handles return/space key event on view-sort selector', async () => {
369
+ const defaultSortSelector = desktopSortSelector?.children
370
+ .item(1)
371
+ ?.querySelector('.dropdown-label') as HTMLElement;
372
+
373
+ el.selectedSort = 'relevance' as SortField;
374
+ const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
375
+ defaultSortSelector?.dispatchEvent(enterEvent);
376
+ await el.updateComplete;
377
+
378
+ expect(el.selectedSort).to.equal('weeklyview');
379
+
380
+ el.selectedSort = 'relevance' as SortField;
381
+ const spaceEvent = new KeyboardEvent('keydown', { key: ' ' });
382
+ defaultSortSelector?.dispatchEvent(spaceEvent);
383
+ await el.updateComplete;
384
+
385
+ expect(el.selectedSort).to.equal('weeklyview');
386
+ });
387
+
388
+ it('handles return/space key event on date-sort selector', async () => {
389
+ const defaultSortSelector = desktopSortSelector?.children
390
+ .item(3)
391
+ ?.querySelector('.dropdown-label') as HTMLElement;
392
+
393
+ el.selectedSort = 'relevance' as SortField;
394
+ const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
395
+ defaultSortSelector?.dispatchEvent(enterEvent);
396
+ await el.updateComplete;
397
+
398
+ expect(el.selectedSort).to.equal('date');
399
+
400
+ el.selectedSort = 'relevance' as SortField;
401
+ const spaceEvent = new KeyboardEvent('keydown', { key: ' ' });
402
+ defaultSortSelector?.dispatchEvent(spaceEvent);
403
+ await el.updateComplete;
404
+
405
+ expect(el.selectedSort).to.equal('date');
406
+ });
407
+
408
+ it('handles click event on view-sort dropdown option', async () => {
409
+ const defaultSortSelector = desktopSortSelector?.children
410
+ .item(1)
411
+ ?.querySelector('ia-dropdown') as IaDropdown;
412
+
413
+ const firstOption = defaultSortSelector?.shadowRoot?.querySelector(
414
+ 'li > button',
415
+ ) as HTMLButtonElement;
416
+ expect(firstOption).to.exist;
417
+
418
+ firstOption?.click();
419
+ await el.updateComplete;
420
+
421
+ expect(el.selectedSort).to.equal('weeklyview');
422
+ });
423
+
424
+ it('handles click event on date-sort dropdown option', async () => {
425
+ const defaultSortSelector = desktopSortSelector?.children
426
+ .item(3)
427
+ ?.querySelector('ia-dropdown') as IaDropdown;
428
+
429
+ const firstOption = defaultSortSelector?.shadowRoot?.querySelector(
430
+ 'li > button',
431
+ ) as HTMLButtonElement;
432
+ expect(firstOption).to.exist;
433
+
434
+ firstOption?.click();
435
+ await el.updateComplete;
436
+
437
+ expect(el.selectedSort).to.equal('date');
438
+ });
439
+
440
+ it('shows view sort selector backdrop when view sort open', async () => {
441
+ const defaultSortSelector = desktopSortSelector?.children
442
+ .item(1)
443
+ ?.querySelector('ia-dropdown') as IaDropdown;
444
+
445
+ const caret = defaultSortSelector?.shadowRoot?.querySelector(
446
+ '.caret',
447
+ ) as HTMLElement;
448
+ expect(caret).to.exist;
449
+
450
+ caret?.click();
451
+ await el.updateComplete;
452
+
453
+ let backdrop = el.shadowRoot?.querySelector(
454
+ '#sort-selector-backdrop',
455
+ ) as HTMLElement;
456
+ expect(backdrop).to.exist;
457
+
458
+ backdrop?.click();
459
+ await el.updateComplete;
460
+
461
+ backdrop = el.shadowRoot?.querySelector(
462
+ '#sort-selector-backdrop',
463
+ ) as HTMLElement;
464
+ expect(backdrop).not.to.exist;
465
+ });
466
+
467
+ it('shows date sort selector backdrop when date sort open', async () => {
468
+ const defaultSortSelector = desktopSortSelector?.children
469
+ .item(3)
470
+ ?.querySelector('ia-dropdown') as IaDropdown;
471
+
472
+ const caret = defaultSortSelector?.shadowRoot?.querySelector(
473
+ '.caret',
474
+ ) as HTMLElement;
475
+ expect(caret).to.exist;
476
+
477
+ caret?.click();
478
+ await el.updateComplete;
479
+
480
+ let backdrop = el.shadowRoot?.querySelector(
481
+ '#sort-selector-backdrop',
482
+ ) as HTMLElement;
483
+ expect(backdrop).to.exist;
484
+
485
+ backdrop?.click();
486
+ await el.updateComplete;
487
+
488
+ backdrop = el.shadowRoot?.querySelector(
489
+ '#sort-selector-backdrop',
490
+ ) as HTMLElement;
491
+ expect(backdrop).not.to.exist;
492
+ });
493
+
494
+ it('closes dropdown by hitting escape key', async () => {
495
+ const defaultSortSelector = desktopSortSelector?.children
496
+ .item(3)
497
+ ?.querySelector('ia-dropdown') as IaDropdown;
498
+
499
+ const caret = defaultSortSelector?.shadowRoot?.querySelector(
500
+ '.caret',
501
+ ) as HTMLElement;
502
+ expect(caret).to.exist;
503
+
504
+ caret?.click();
505
+ await el.updateComplete;
506
+
507
+ let backdrop = el.shadowRoot?.querySelector(
508
+ '#sort-selector-backdrop',
509
+ ) as HTMLElement;
510
+ expect(backdrop).to.exist;
511
+
512
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
513
+ await el.updateComplete;
514
+
515
+ backdrop = el.shadowRoot?.querySelector(
516
+ '#sort-selector-backdrop',
517
+ ) as HTMLElement;
518
+ expect(backdrop).not.to.exist;
519
+ });
520
+ });
521
+
522
+ describe('Sort direction button behavior', () => {
523
+ it('should disable sort direction button when sorting by relevance', async () => {
524
+ const el = await fixture<SortFilterBar>(html`
525
+ <sort-filter-bar> </sort-filter-bar>
526
+ `);
527
+
528
+ el.selectedSort = 'relevance' as SortField;
529
+ await el.updateComplete;
530
+
531
+ const sortDirectionButton = el.shadowRoot?.querySelector(
532
+ '.sort-direction-selector',
533
+ ) as HTMLButtonElement;
534
+ expect(sortDirectionButton).to.exist;
535
+ expect(sortDirectionButton.disabled).to.be.true;
536
+ });
537
+
538
+ it('should enable sort direction button when not sorting by relevance', async () => {
539
+ const el = await fixture<SortFilterBar>(html`
540
+ <sort-filter-bar> </sort-filter-bar>
541
+ `);
542
+
543
+ el.selectedSort = 'title' as SortField;
544
+ await el.updateComplete;
545
+
546
+ const sortDirectionButton = el.shadowRoot?.querySelector(
547
+ '.sort-direction-selector',
548
+ ) as HTMLButtonElement;
549
+ expect(sortDirectionButton).to.exist;
550
+ expect(sortDirectionButton.disabled).to.be.false;
551
+ });
552
+
553
+ it('should toggle sort direction when clicked', async () => {
554
+ const el = await fixture<SortFilterBar>(html`
555
+ <sort-filter-bar> </sort-filter-bar>
556
+ `);
557
+
558
+ el.selectedSort = 'title' as SortField;
559
+ el.sortDirection = 'asc';
560
+ await el.updateComplete;
561
+
562
+ const sortDirectionButton = el.shadowRoot?.querySelector(
563
+ '.sort-direction-selector',
564
+ ) as HTMLButtonElement;
565
+
566
+ sortDirectionButton.click();
567
+ await el.updateComplete;
568
+ expect(el.sortDirection).to.equal('desc');
569
+
570
+ sortDirectionButton.click();
571
+ await el.updateComplete;
572
+ expect(el.sortDirection).to.equal('asc');
573
+ });
574
+ });
575
+
576
+ describe('Display mode/style buttons', () => {
577
+ it('should render all display mode buttons', async () => {
578
+ const el = await fixture<SortFilterBar>(html`
579
+ <sort-filter-bar> </sort-filter-bar>
580
+ `);
581
+
582
+ const displayModeButtonList = el.shadowRoot
583
+ ?.querySelector('#display-style-selector')
584
+ ?.querySelector('ul');
585
+
586
+ const gridButton = displayModeButtonList?.children
587
+ .item(0)
588
+ ?.querySelector('#grid-button');
589
+ expect(gridButton).to.exist;
590
+
591
+ const detailListButton = displayModeButtonList?.children
592
+ .item(1)
593
+ ?.querySelector('#list-detail-button');
594
+ expect(detailListButton).to.exist;
595
+
596
+ const compactListButton = displayModeButtonList?.children
597
+ .item(2)
598
+ ?.querySelector('#list-compact-button');
599
+ expect(compactListButton).to.exist;
600
+ });
601
+
602
+ it('should not render display mode buttons when suppressed', async () => {
603
+ const el = await fixture<SortFilterBar>(html`
604
+ <sort-filter-bar suppressDisplayModes></sort-filter-bar>
605
+ `);
606
+
607
+ const displayModeButtonList = el.shadowRoot?.querySelector(
608
+ '#display-style-selector',
609
+ );
610
+ expect(displayModeButtonList).not.to.exist;
611
+ });
612
+
613
+ it('should active current display mode', async () => {
614
+ const el = await fixture<SortFilterBar>(html`
615
+ <sort-filter-bar> </sort-filter-bar>
616
+ `);
617
+
618
+ el.displayMode = 'grid';
619
+ await el.updateComplete;
620
+
621
+ const displayModeTitle = el.shadowRoot
622
+ ?.querySelector('#display-style-selector')
623
+ ?.querySelector('button.active')
624
+ ?.getAttribute('title');
625
+ expect(displayModeTitle).to.equal('Tile view');
626
+ });
627
+
628
+ it('should change displayMode prop to the one clicked', async () => {
629
+ const el = await fixture<SortFilterBar>(html`
630
+ <sort-filter-bar> </sort-filter-bar>
631
+ `);
632
+
633
+ el.displayMode = 'grid';
634
+ await el.updateComplete;
635
+
636
+ const extendedListButton = el.shadowRoot?.querySelector(
637
+ '#list-detail-button',
638
+ ) as HTMLElement;
639
+ extendedListButton.click();
640
+ await el.updateComplete;
641
+ expect(el.displayMode).to.equal('list-detail');
642
+
643
+ const compactListButton = el.shadowRoot?.querySelector(
644
+ '#list-compact-button',
645
+ ) as HTMLElement;
646
+ compactListButton.click();
647
+ await el.updateComplete;
648
+ expect(el.displayMode).to.equal('list-compact');
649
+
650
+ const gridModeButton = el.shadowRoot?.querySelector(
651
+ '#grid-button',
652
+ ) as HTMLElement;
653
+ gridModeButton.click();
654
+ await el.updateComplete;
655
+ expect(el.displayMode).to.equal('grid');
656
+ });
657
+ });
658
+
659
+ describe('Sort/filter bar letter behavior', () => {
660
+ it('sets the selected title letter when clicked', async () => {
661
+ const el = await fixture<SortFilterBar>(html`
662
+ <sort-filter-bar></sort-filter-bar>
663
+ `);
664
+
665
+ el.selectedSort = 'title' as SortField;
666
+ el.prefixFilterCountMap = { title: { T: 1 }, creator: {} };
667
+ await el.updateComplete;
668
+
669
+ const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
670
+ const letterLink = alphaBar?.shadowRoot?.querySelector(
671
+ 'li > button:not(:disabled)',
672
+ ) as HTMLAnchorElement;
673
+ expect(letterLink?.textContent?.trim()).to.equal('T');
674
+
675
+ letterLink?.click();
676
+ await el.updateComplete;
677
+
678
+ expect(el.selectedTitleFilter).to.equal('T');
679
+ });
680
+
681
+ it('sets the selected creator letter when clicked', async () => {
682
+ const el = await fixture<SortFilterBar>(html`
683
+ <sort-filter-bar></sort-filter-bar>
684
+ `);
685
+
686
+ el.selectedSort = 'creator' as SortField;
687
+ el.prefixFilterCountMap = { title: {}, creator: { C: 1 } };
688
+ await el.updateComplete;
689
+
690
+ const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
691
+ const letterLink = alphaBar?.shadowRoot?.querySelector(
692
+ 'li > button:not(:disabled)',
693
+ ) as HTMLAnchorElement;
694
+ expect(letterLink?.textContent?.trim()).to.equal('C');
695
+
696
+ letterLink?.click();
697
+ await el.updateComplete;
698
+
699
+ expect(el.selectedCreatorFilter).to.equal('C');
700
+ });
701
+ });
702
+
703
+ describe('Sort/filter bar mobile view', () => {
704
+ let origWindowSize: { width: number; height: number };
705
+ before(() => {
706
+ origWindowSize = { width: window.innerWidth, height: window.innerHeight };
707
+ window.resizeTo(500, 600);
708
+ });
709
+
710
+ after(() => {
711
+ window.resizeTo(origWindowSize.width, origWindowSize.height);
712
+ });
713
+
714
+ it('renders in mobile view', async () => {
715
+ const el = await fixture<SortFilterBar>(html`
716
+ <sort-filter-bar></sort-filter-bar>
717
+ `);
718
+
719
+ const mobileSortContainer = el.shadowRoot?.querySelector(
720
+ '#mobile-sort-container',
721
+ );
722
+ const desktopSortContainer = el.shadowRoot?.querySelector(
723
+ '#desktop-sort-container',
724
+ );
725
+
726
+ expect(mobileSortContainer?.classList?.contains('visible')).to.be.true;
727
+ expect(desktopSortContainer?.classList?.contains('hidden')).to.be.true;
728
+ });
729
+
730
+ it('changes selected sort in mobile view', async () => {
731
+ const el = await fixture<SortFilterBar>(html`
732
+ <sort-filter-bar></sort-filter-bar>
733
+ `);
734
+
735
+ const mobileDropdown = el.shadowRoot?.querySelector(
736
+ '#mobile-dropdown',
737
+ ) as IaDropdown;
738
+ expect(mobileDropdown).to.exist;
739
+
740
+ mobileDropdown.selectedOption = 'title';
741
+ const option = { id: 'title' };
742
+ mobileDropdown.dispatchEvent(
743
+ new CustomEvent('optionSelected', { detail: { option } }),
744
+ );
745
+ await el.updateComplete;
746
+
747
+ expect(el.selectedSort).to.equal('title');
748
+ });
749
+
750
+ it('clears title filter when sort changed from title in mobile view', async () => {
751
+ const el = await fixture<SortFilterBar>(html`
752
+ <sort-filter-bar></sort-filter-bar>
753
+ `);
754
+
755
+ el.selectedSort = 'title' as SortField;
756
+ el.selectedTitleFilter = 'A';
757
+ await el.updateComplete;
758
+
759
+ const mobileDropdown = el.shadowRoot?.querySelector(
760
+ '#mobile-dropdown',
761
+ ) as IaDropdown;
762
+ expect(mobileDropdown).to.exist;
763
+
764
+ mobileDropdown.selectedOption = 'relevance';
765
+ const option = { id: 'relevance' };
766
+ mobileDropdown.dispatchEvent(
767
+ new CustomEvent('optionSelected', { detail: { option } }),
768
+ );
769
+ await el.updateComplete;
770
+
771
+ expect(el.selectedSort).to.equal('relevance');
772
+ expect(el.selectedTitleFilter).to.be.null;
773
+ });
774
+
775
+ it('clears creator filter when sort changed from creator in mobile view', async () => {
776
+ const el = await fixture<SortFilterBar>(html`
777
+ <sort-filter-bar></sort-filter-bar>
778
+ `);
779
+
780
+ el.selectedSort = 'creator' as SortField;
781
+ el.selectedCreatorFilter = 'A';
782
+ await el.updateComplete;
783
+
784
+ const mobileDropdown = el.shadowRoot?.querySelector(
785
+ '#mobile-dropdown',
786
+ ) as IaDropdown;
787
+ expect(mobileDropdown).to.exist;
788
+
789
+ mobileDropdown.selectedOption = 'relevance';
790
+ const option = { id: 'relevance' };
791
+ mobileDropdown.dispatchEvent(
792
+ new CustomEvent('optionSelected', { detail: { option } }),
793
+ );
794
+ await el.updateComplete;
795
+
796
+ expect(el.selectedSort).to.equal('relevance');
797
+ expect(el.selectedCreatorFilter).to.be.null;
798
+ });
799
+
800
+ it('shows sort selector backdrop when mobile sort open', async () => {
801
+ const el = await fixture<SortFilterBar>(html`
802
+ <sort-filter-bar></sort-filter-bar>
803
+ `);
804
+
805
+ const mobileDropdown = el.shadowRoot?.querySelector(
806
+ '#mobile-dropdown',
807
+ ) as IaDropdown;
808
+ expect(mobileDropdown).to.exist;
809
+
810
+ const caret = mobileDropdown?.shadowRoot?.querySelector(
811
+ '.caret',
812
+ ) as HTMLElement;
813
+ expect(caret).to.exist;
814
+
815
+ caret?.click();
816
+ await el.updateComplete;
817
+
818
+ let backdrop = el.shadowRoot?.querySelector(
819
+ '#sort-selector-backdrop',
820
+ ) as HTMLElement;
821
+ expect(backdrop).to.exist;
822
+
823
+ backdrop?.click();
824
+ await el.updateComplete;
825
+
826
+ backdrop = el.shadowRoot?.querySelector(
827
+ '#sort-selector-backdrop',
828
+ ) as HTMLElement;
829
+ expect(backdrop).not.to.exist;
830
+ });
831
+
832
+ it('shows loansTab top-bar slot Default View', async () => {
833
+ const resizeStub = new SharedResizeObserver();
834
+ const addSpy = sinon.spy(resizeStub, 'addObserver');
835
+ const removeSpy = sinon.spy(resizeStub, 'removeObserver');
836
+
837
+ const el = await fixture<SortFilterBar>(html`
838
+ <sort-filter-bar .resizeObserver=${resizeStub}></sort-filter-bar>
839
+ `);
840
+
841
+ // this element exists
842
+ expect(el?.shadowRoot?.querySelector('#sort-selector-container')).to.exist;
843
+
844
+ // loads & unloads twice when [re]setting ResizeObserver
845
+ expect(addSpy.callCount).to.equal(2);
846
+
847
+ const resizeStub2 = new SharedResizeObserver();
848
+ el.resizeObserver = resizeStub2;
849
+ await el.updateComplete;
850
+ expect(removeSpy.callCount).to.equal(2);
851
+ });
852
+
853
+ it('contains sort-options slot when enabled', async () => {
854
+ const resizeStub = new SharedResizeObserver();
855
+ const addSpy = sinon.spy(resizeStub, 'addObserver');
856
+ const removeSpy = sinon.spy(resizeStub, 'removeObserver');
857
+
858
+ const el = await fixture<SortFilterBar>(html`
859
+ <sort-filter-bar
860
+ .resizeObserver=${resizeStub}
861
+ .enableSortOptionsSlot=${true}
862
+ ></sort-filter-bar>
863
+ `);
864
+
865
+ await el.updateComplete;
866
+
867
+ // slot exists
868
+ const sortOptionsSlot = el?.shadowRoot?.querySelector(
869
+ 'slot[name="sort-options"]',
870
+ );
871
+ expect(sortOptionsSlot).to.exist;
872
+
873
+ // sort bar does not exist
874
+ expect(el?.shadowRoot?.querySelector('#sort-selector-container')).to.not
875
+ .exist;
876
+
877
+ const resizeStub2 = new SharedResizeObserver();
878
+ el.resizeObserver = resizeStub2;
879
+ await el.updateComplete;
880
+
881
+ // there's no need for resize observer
882
+ expect(addSpy.callCount).to.equal(0);
883
+ expect(removeSpy.callCount).to.equal(0);
884
+ });
885
+ });