@internetarchive/collection-browser 4.1.0 → 4.2.0-alpha-webdev8164.0
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/.editorconfig +29 -29
- package/.github/workflows/ci.yml +27 -27
- package/.github/workflows/gh-pages-main.yml +39 -39
- package/.github/workflows/npm-publish.yml +39 -39
- package/.github/workflows/pr-preview.yml +38 -38
- package/.husky/pre-commit +1 -1
- package/.prettierignore +1 -1
- package/LICENSE +661 -661
- package/README.md +83 -83
- package/dist/src/collection-browser.js +761 -761
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/facets-template.js +5 -0
- package/dist/src/collection-facets/facets-template.js.map +1 -1
- package/dist/src/collection-facets/more-facets-content.d.ts +92 -8
- package/dist/src/collection-facets/more-facets-content.js +526 -84
- package/dist/src/collection-facets/more-facets-content.js.map +1 -1
- package/dist/src/collection-facets/more-facets-pagination.d.ts +12 -3
- package/dist/src/collection-facets/more-facets-pagination.js +69 -8
- package/dist/src/collection-facets/more-facets-pagination.js.map +1 -1
- package/dist/src/collection-facets/toggle-switch.js +1 -0
- package/dist/src/collection-facets/toggle-switch.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
- package/dist/src/data-source/collection-browser-query-state.js.map +1 -1
- package/dist/src/sort-filter-bar/sort-filter-bar.js +280 -280
- package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
- package/dist/test/collection-browser.test.js +189 -189
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-content.test.js +162 -3
- package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-pagination.test.js +63 -3
- package/dist/test/collection-facets/more-facets-pagination.test.js.map +1 -1
- package/dist/test/mocks/mock-search-responses.d.ts +5 -0
- package/dist/test/mocks/mock-search-responses.js +44 -0
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/dist/test/mocks/mock-search-service.js +2 -1
- package/dist/test/mocks/mock-search-service.js.map +1 -1
- package/dist/test/sort-filter-bar/sort-filter-bar.test.js +22 -22
- package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +1 -1
- package/eslint.config.mjs +53 -53
- package/index.html +24 -24
- package/local.archive.org.cert +86 -86
- package/local.archive.org.key +27 -27
- package/package.json +121 -120
- package/renovate.json +6 -6
- package/src/collection-browser.ts +3070 -3070
- package/src/collection-facets/facets-template.ts +5 -0
- package/src/collection-facets/more-facets-content.ts +566 -96
- package/src/collection-facets/more-facets-pagination.ts +80 -9
- package/src/collection-facets/toggle-switch.ts +1 -0
- package/src/data-source/collection-browser-data-source.ts +1444 -1444
- package/src/data-source/collection-browser-query-state.ts +60 -60
- package/src/sort-filter-bar/sort-filter-bar.ts +733 -733
- package/test/collection-browser.test.ts +2402 -2402
- package/test/collection-facets/more-facets-content.test.ts +251 -4
- package/test/collection-facets/more-facets-pagination.test.ts +87 -3
- package/test/mocks/mock-search-responses.ts +48 -0
- package/test/mocks/mock-search-service.ts +2 -0
- package/test/sort-filter-bar/sort-filter-bar.test.ts +443 -443
- package/tsconfig.json +25 -25
- package/web-dev-server.config.mjs +30 -30
- package/web-test-runner.config.mjs +52 -52
- package/.claude/settings.local.json +0 -8
|
@@ -1,443 +1,443 @@
|
|
|
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 type { SortFilterBar } from '../../src/sort-filter-bar/sort-filter-bar';
|
|
6
|
-
import { SortField, defaultSortAvailability } from '../../src/models';
|
|
7
|
-
|
|
8
|
-
import '../../src/sort-filter-bar/sort-filter-bar';
|
|
9
|
-
|
|
10
|
-
describe('Sort dropdown behavior', () => {
|
|
11
|
-
let el: SortFilterBar;
|
|
12
|
-
let sortDropdown: IaDropdown;
|
|
13
|
-
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
el = await fixture<SortFilterBar>(html`
|
|
16
|
-
<sort-filter-bar></sort-filter-bar>
|
|
17
|
-
`);
|
|
18
|
-
sortDropdown = el.shadowRoot?.querySelector('#sort-dropdown') as IaDropdown;
|
|
19
|
-
await el.updateComplete;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should render basic component', async () => {
|
|
23
|
-
const sortSelectorContainer = el.shadowRoot?.querySelector(
|
|
24
|
-
'#sort-selector-container',
|
|
25
|
-
);
|
|
26
|
-
expect(sortSelectorContainer).to.exist;
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should render sort-by label', async () => {
|
|
30
|
-
const sortByLabel = el.shadowRoot?.querySelector('.sort-by-text');
|
|
31
|
-
expect(sortByLabel).to.exist;
|
|
32
|
-
expect(sortByLabel?.textContent?.trim()).to.equal('Sort by:');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should render sort direction button', async () => {
|
|
36
|
-
const sortDirections = el.shadowRoot?.querySelector(
|
|
37
|
-
'.sort-direction-container',
|
|
38
|
-
);
|
|
39
|
-
expect(sortDirections).to.exist;
|
|
40
|
-
expect(sortDirections?.querySelector('.sort-direction-icon')).to.exist;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('renders default set of sort options in dropdown', async () => {
|
|
44
|
-
expect(sortDropdown).to.exist;
|
|
45
|
-
expect(sortDropdown.options.map(o => o.id)).to.deep.equal([
|
|
46
|
-
SortField.relevance,
|
|
47
|
-
SortField.alltimeview,
|
|
48
|
-
SortField.weeklyview,
|
|
49
|
-
SortField.title,
|
|
50
|
-
SortField.date,
|
|
51
|
-
SortField.datearchived,
|
|
52
|
-
SortField.datereviewed,
|
|
53
|
-
SortField.dateadded,
|
|
54
|
-
SortField.creator,
|
|
55
|
-
]);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('respects overridden sort field availability', async () => {
|
|
59
|
-
const customSortAvailability: Record<SortField, boolean> = {
|
|
60
|
-
...defaultSortAvailability,
|
|
61
|
-
[SortField.title]: false,
|
|
62
|
-
[SortField.datearchived]: false,
|
|
63
|
-
[SortField.datereviewed]: false,
|
|
64
|
-
[SortField.creator]: false,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
el.sortFieldAvailability = customSortAvailability;
|
|
68
|
-
await el.updateComplete;
|
|
69
|
-
|
|
70
|
-
const dropdown = el.shadowRoot?.querySelector(
|
|
71
|
-
'#sort-dropdown',
|
|
72
|
-
) as IaDropdown;
|
|
73
|
-
expect(dropdown.options.length).to.equal(5);
|
|
74
|
-
expect(dropdown.options.map(o => o.id)).to.deep.equal([
|
|
75
|
-
SortField.relevance,
|
|
76
|
-
SortField.alltimeview,
|
|
77
|
-
SortField.weeklyview,
|
|
78
|
-
SortField.date,
|
|
79
|
-
SortField.dateadded,
|
|
80
|
-
]);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('shows the display name of the selected sort', async () => {
|
|
84
|
-
el.selectedSort = SortField.alltimeview;
|
|
85
|
-
await el.updateComplete;
|
|
86
|
-
|
|
87
|
-
const label = sortDropdown?.querySelector('.dropdown-label');
|
|
88
|
-
expect(label?.textContent?.trim()).to.equal('All-time views');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('falls back to first available sort when default is unavailable', async () => {
|
|
92
|
-
el.selectedSort = SortField.default;
|
|
93
|
-
el.defaultSortField = SortField.relevance;
|
|
94
|
-
el.sortFieldAvailability = {
|
|
95
|
-
...defaultSortAvailability,
|
|
96
|
-
[SortField.relevance]: false,
|
|
97
|
-
};
|
|
98
|
-
await el.updateComplete;
|
|
99
|
-
|
|
100
|
-
const label = sortDropdown?.querySelector('.dropdown-label');
|
|
101
|
-
// No relevance, so fall back to the first one in the list
|
|
102
|
-
expect(label?.textContent?.trim()).to.equal('All-time views');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('changes selected sort when dropdown option selected', async () => {
|
|
106
|
-
expect(sortDropdown).to.exist;
|
|
107
|
-
|
|
108
|
-
sortDropdown.selectedOption = 'title';
|
|
109
|
-
const option = { id: 'title' };
|
|
110
|
-
sortDropdown.dispatchEvent(
|
|
111
|
-
new CustomEvent('optionSelected', { detail: { option } }),
|
|
112
|
-
);
|
|
113
|
-
await el.updateComplete;
|
|
114
|
-
|
|
115
|
-
expect(el.selectedSort).to.equal('title');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('selects a sort option by clicking it in the dropdown', async () => {
|
|
119
|
-
el.selectedSort = SortField.title;
|
|
120
|
-
await el.updateComplete;
|
|
121
|
-
|
|
122
|
-
const dropdown = el.shadowRoot?.querySelector(
|
|
123
|
-
'#sort-dropdown',
|
|
124
|
-
) as IaDropdown;
|
|
125
|
-
expect(dropdown).to.exist;
|
|
126
|
-
|
|
127
|
-
const firstOption = dropdown?.shadowRoot?.querySelector(
|
|
128
|
-
'li > button',
|
|
129
|
-
) as HTMLButtonElement;
|
|
130
|
-
expect(firstOption).to.exist;
|
|
131
|
-
|
|
132
|
-
firstOption?.click();
|
|
133
|
-
await el.updateComplete;
|
|
134
|
-
|
|
135
|
-
// The first option is relevance by default
|
|
136
|
-
expect(el.selectedSort).to.equal(SortField.relevance);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('emits sortChanged event when sort option selected', async () => {
|
|
140
|
-
const sortChangedHandler = sinon.spy();
|
|
141
|
-
el.addEventListener('sortChanged', sortChangedHandler);
|
|
142
|
-
|
|
143
|
-
const option = { id: SortField.title };
|
|
144
|
-
sortDropdown.dispatchEvent(
|
|
145
|
-
new CustomEvent('optionSelected', { detail: { option } }),
|
|
146
|
-
);
|
|
147
|
-
await el.updateComplete;
|
|
148
|
-
|
|
149
|
-
expect(sortChangedHandler.calledOnce).to.be.true;
|
|
150
|
-
const eventDetail = sortChangedHandler.firstCall.args[0].detail;
|
|
151
|
-
expect(eventDetail.selectedSort).to.equal(SortField.title);
|
|
152
|
-
expect(eventDetail.sortDirection).to.equal('asc');
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('renders sort selector backdrop when dropdown is open', async () => {
|
|
156
|
-
expect(sortDropdown).to.exist;
|
|
157
|
-
|
|
158
|
-
const caret = sortDropdown?.shadowRoot?.querySelector(
|
|
159
|
-
'.caret',
|
|
160
|
-
) as HTMLElement;
|
|
161
|
-
expect(caret).to.exist;
|
|
162
|
-
|
|
163
|
-
caret!.click();
|
|
164
|
-
await el.updateComplete;
|
|
165
|
-
|
|
166
|
-
let backdrop = el.shadowRoot?.querySelector(
|
|
167
|
-
'#sort-selector-backdrop',
|
|
168
|
-
) as HTMLElement;
|
|
169
|
-
expect(backdrop).to.exist;
|
|
170
|
-
|
|
171
|
-
// Clicking the backdrop should close the dropdown
|
|
172
|
-
backdrop!.click();
|
|
173
|
-
await el.updateComplete;
|
|
174
|
-
|
|
175
|
-
backdrop = el.shadowRoot?.querySelector(
|
|
176
|
-
'#sort-selector-backdrop',
|
|
177
|
-
) as HTMLElement;
|
|
178
|
-
expect(backdrop).not.to.exist;
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('pressing Escape key closes the dropdown', async () => {
|
|
182
|
-
expect(sortDropdown).to.exist;
|
|
183
|
-
|
|
184
|
-
const caret = sortDropdown?.shadowRoot?.querySelector(
|
|
185
|
-
'.caret',
|
|
186
|
-
) as HTMLElement;
|
|
187
|
-
expect(caret).to.exist;
|
|
188
|
-
|
|
189
|
-
caret!.click();
|
|
190
|
-
await el.updateComplete;
|
|
191
|
-
|
|
192
|
-
let backdrop = el.shadowRoot?.querySelector(
|
|
193
|
-
'#sort-selector-backdrop',
|
|
194
|
-
) as HTMLElement;
|
|
195
|
-
expect(backdrop).to.exist;
|
|
196
|
-
|
|
197
|
-
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
|
|
198
|
-
await el.updateComplete;
|
|
199
|
-
|
|
200
|
-
backdrop = el.shadowRoot?.querySelector(
|
|
201
|
-
'#sort-selector-backdrop',
|
|
202
|
-
) as HTMLElement;
|
|
203
|
-
expect(backdrop).not.to.exist;
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it('clears title filter when sort changed from title', async () => {
|
|
207
|
-
el.selectedSort = 'title' as SortField;
|
|
208
|
-
el.selectedTitleFilter = 'A';
|
|
209
|
-
await el.updateComplete;
|
|
210
|
-
|
|
211
|
-
const dropdown = el.shadowRoot?.querySelector(
|
|
212
|
-
'#sort-dropdown',
|
|
213
|
-
) as IaDropdown;
|
|
214
|
-
expect(dropdown).to.exist;
|
|
215
|
-
|
|
216
|
-
dropdown.selectedOption = 'relevance';
|
|
217
|
-
const option = { id: 'relevance' };
|
|
218
|
-
dropdown.dispatchEvent(
|
|
219
|
-
new CustomEvent('optionSelected', { detail: { option } }),
|
|
220
|
-
);
|
|
221
|
-
await el.updateComplete;
|
|
222
|
-
|
|
223
|
-
expect(el.selectedSort).to.equal('relevance');
|
|
224
|
-
expect(el.selectedTitleFilter).to.be.null;
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('clears creator filter when sort changed from creator', async () => {
|
|
228
|
-
el.selectedSort = 'creator' as SortField;
|
|
229
|
-
el.selectedCreatorFilter = 'A';
|
|
230
|
-
await el.updateComplete;
|
|
231
|
-
|
|
232
|
-
const dropdown = el.shadowRoot?.querySelector(
|
|
233
|
-
'#sort-dropdown',
|
|
234
|
-
) as IaDropdown;
|
|
235
|
-
expect(dropdown).to.exist;
|
|
236
|
-
|
|
237
|
-
dropdown.selectedOption = 'relevance';
|
|
238
|
-
const option = { id: 'relevance' };
|
|
239
|
-
dropdown.dispatchEvent(
|
|
240
|
-
new CustomEvent('optionSelected', { detail: { option } }),
|
|
241
|
-
);
|
|
242
|
-
await el.updateComplete;
|
|
243
|
-
|
|
244
|
-
expect(el.selectedSort).to.equal('relevance');
|
|
245
|
-
expect(el.selectedCreatorFilter).to.be.null;
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it('contains sort-options slot when enabled', async () => {
|
|
249
|
-
const slotEl = await fixture<SortFilterBar>(html`
|
|
250
|
-
<sort-filter-bar .enableSortOptionsSlot=${true}></sort-filter-bar>
|
|
251
|
-
`);
|
|
252
|
-
await slotEl.updateComplete;
|
|
253
|
-
|
|
254
|
-
const sortOptionsSlot = slotEl?.shadowRoot?.querySelector(
|
|
255
|
-
'slot[name="sort-options"]',
|
|
256
|
-
);
|
|
257
|
-
expect(sortOptionsSlot).to.exist;
|
|
258
|
-
|
|
259
|
-
expect(slotEl?.shadowRoot?.querySelector('#sort-selector-container')).to.not
|
|
260
|
-
.exist;
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
describe('Sort direction button behavior', () => {
|
|
265
|
-
it('should disable sort direction button when sorting by relevance', async () => {
|
|
266
|
-
const el = await fixture<SortFilterBar>(html`
|
|
267
|
-
<sort-filter-bar> </sort-filter-bar>
|
|
268
|
-
`);
|
|
269
|
-
|
|
270
|
-
el.selectedSort = 'relevance' as SortField;
|
|
271
|
-
await el.updateComplete;
|
|
272
|
-
|
|
273
|
-
const sortDirectionButton = el.shadowRoot?.querySelector(
|
|
274
|
-
'.sort-direction-selector',
|
|
275
|
-
) as HTMLButtonElement;
|
|
276
|
-
expect(sortDirectionButton).to.exist;
|
|
277
|
-
expect(sortDirectionButton.disabled).to.be.true;
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('should enable sort direction button when not sorting by relevance', async () => {
|
|
281
|
-
const el = await fixture<SortFilterBar>(html`
|
|
282
|
-
<sort-filter-bar> </sort-filter-bar>
|
|
283
|
-
`);
|
|
284
|
-
|
|
285
|
-
el.selectedSort = 'title' as SortField;
|
|
286
|
-
await el.updateComplete;
|
|
287
|
-
|
|
288
|
-
const sortDirectionButton = el.shadowRoot?.querySelector(
|
|
289
|
-
'.sort-direction-selector',
|
|
290
|
-
) as HTMLButtonElement;
|
|
291
|
-
expect(sortDirectionButton).to.exist;
|
|
292
|
-
expect(sortDirectionButton.disabled).to.be.false;
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('should toggle sort direction when clicked', async () => {
|
|
296
|
-
const el = await fixture<SortFilterBar>(html`
|
|
297
|
-
<sort-filter-bar> </sort-filter-bar>
|
|
298
|
-
`);
|
|
299
|
-
|
|
300
|
-
el.selectedSort = 'title' as SortField;
|
|
301
|
-
el.sortDirection = 'asc';
|
|
302
|
-
await el.updateComplete;
|
|
303
|
-
|
|
304
|
-
const sortDirectionButton = el.shadowRoot?.querySelector(
|
|
305
|
-
'.sort-direction-selector',
|
|
306
|
-
) as HTMLButtonElement;
|
|
307
|
-
|
|
308
|
-
sortDirectionButton.click();
|
|
309
|
-
await el.updateComplete;
|
|
310
|
-
expect(el.sortDirection).to.equal('desc');
|
|
311
|
-
|
|
312
|
-
sortDirectionButton.click();
|
|
313
|
-
await el.updateComplete;
|
|
314
|
-
expect(el.sortDirection).to.equal('asc');
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
describe('Display mode/style buttons', () => {
|
|
319
|
-
it('should render all display mode buttons', async () => {
|
|
320
|
-
const el = await fixture<SortFilterBar>(html`
|
|
321
|
-
<sort-filter-bar> </sort-filter-bar>
|
|
322
|
-
`);
|
|
323
|
-
|
|
324
|
-
const displayModeButtonList = el.shadowRoot
|
|
325
|
-
?.querySelector('#display-style-selector')
|
|
326
|
-
?.querySelector('ul');
|
|
327
|
-
|
|
328
|
-
const gridButton = displayModeButtonList?.children
|
|
329
|
-
.item(0)
|
|
330
|
-
?.querySelector('#grid-button');
|
|
331
|
-
expect(gridButton).to.exist;
|
|
332
|
-
|
|
333
|
-
const detailListButton = displayModeButtonList?.children
|
|
334
|
-
.item(1)
|
|
335
|
-
?.querySelector('#list-detail-button');
|
|
336
|
-
expect(detailListButton).to.exist;
|
|
337
|
-
|
|
338
|
-
const compactListButton = displayModeButtonList?.children
|
|
339
|
-
.item(2)
|
|
340
|
-
?.querySelector('#list-compact-button');
|
|
341
|
-
expect(compactListButton).to.exist;
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it('should not render display mode buttons when suppressed', async () => {
|
|
345
|
-
const el = await fixture<SortFilterBar>(html`
|
|
346
|
-
<sort-filter-bar suppressDisplayModes></sort-filter-bar>
|
|
347
|
-
`);
|
|
348
|
-
|
|
349
|
-
const displayModeButtonList = el.shadowRoot?.querySelector(
|
|
350
|
-
'#display-style-selector',
|
|
351
|
-
);
|
|
352
|
-
expect(displayModeButtonList).not.to.exist;
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
it('should active current display mode', async () => {
|
|
356
|
-
const el = await fixture<SortFilterBar>(html`
|
|
357
|
-
<sort-filter-bar> </sort-filter-bar>
|
|
358
|
-
`);
|
|
359
|
-
|
|
360
|
-
el.displayMode = 'grid';
|
|
361
|
-
await el.updateComplete;
|
|
362
|
-
|
|
363
|
-
const displayModeTitle = el.shadowRoot
|
|
364
|
-
?.querySelector('#display-style-selector')
|
|
365
|
-
?.querySelector('button.active')
|
|
366
|
-
?.getAttribute('title');
|
|
367
|
-
expect(displayModeTitle).to.equal('Tile view');
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
it('should change displayMode prop to the one clicked', async () => {
|
|
371
|
-
const el = await fixture<SortFilterBar>(html`
|
|
372
|
-
<sort-filter-bar> </sort-filter-bar>
|
|
373
|
-
`);
|
|
374
|
-
|
|
375
|
-
el.displayMode = 'grid';
|
|
376
|
-
await el.updateComplete;
|
|
377
|
-
|
|
378
|
-
const extendedListButton = el.shadowRoot?.querySelector(
|
|
379
|
-
'#list-detail-button',
|
|
380
|
-
) as HTMLElement;
|
|
381
|
-
extendedListButton.click();
|
|
382
|
-
await el.updateComplete;
|
|
383
|
-
expect(el.displayMode).to.equal('list-detail');
|
|
384
|
-
|
|
385
|
-
const compactListButton = el.shadowRoot?.querySelector(
|
|
386
|
-
'#list-compact-button',
|
|
387
|
-
) as HTMLElement;
|
|
388
|
-
compactListButton.click();
|
|
389
|
-
await el.updateComplete;
|
|
390
|
-
expect(el.displayMode).to.equal('list-compact');
|
|
391
|
-
|
|
392
|
-
const gridModeButton = el.shadowRoot?.querySelector(
|
|
393
|
-
'#grid-button',
|
|
394
|
-
) as HTMLElement;
|
|
395
|
-
gridModeButton.click();
|
|
396
|
-
await el.updateComplete;
|
|
397
|
-
expect(el.displayMode).to.equal('grid');
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
describe('Sort/filter bar letter behavior', () => {
|
|
402
|
-
it('sets the selected title letter when clicked', async () => {
|
|
403
|
-
const el = await fixture<SortFilterBar>(html`
|
|
404
|
-
<sort-filter-bar></sort-filter-bar>
|
|
405
|
-
`);
|
|
406
|
-
|
|
407
|
-
el.selectedSort = 'title' as SortField;
|
|
408
|
-
el.prefixFilterCountMap = { title: { T: 1 }, creator: {} };
|
|
409
|
-
await el.updateComplete;
|
|
410
|
-
|
|
411
|
-
const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
|
|
412
|
-
const letterLink = alphaBar?.shadowRoot?.querySelector(
|
|
413
|
-
'li > button:not(:disabled)',
|
|
414
|
-
) as HTMLAnchorElement;
|
|
415
|
-
expect(letterLink?.textContent?.trim()).to.equal('T');
|
|
416
|
-
|
|
417
|
-
letterLink?.click();
|
|
418
|
-
await el.updateComplete;
|
|
419
|
-
|
|
420
|
-
expect(el.selectedTitleFilter).to.equal('T');
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
it('sets the selected creator letter when clicked', async () => {
|
|
424
|
-
const el = await fixture<SortFilterBar>(html`
|
|
425
|
-
<sort-filter-bar></sort-filter-bar>
|
|
426
|
-
`);
|
|
427
|
-
|
|
428
|
-
el.selectedSort = 'creator' as SortField;
|
|
429
|
-
el.prefixFilterCountMap = { title: {}, creator: { C: 1 } };
|
|
430
|
-
await el.updateComplete;
|
|
431
|
-
|
|
432
|
-
const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
|
|
433
|
-
const letterLink = alphaBar?.shadowRoot?.querySelector(
|
|
434
|
-
'li > button:not(:disabled)',
|
|
435
|
-
) as HTMLAnchorElement;
|
|
436
|
-
expect(letterLink?.textContent?.trim()).to.equal('C');
|
|
437
|
-
|
|
438
|
-
letterLink?.click();
|
|
439
|
-
await el.updateComplete;
|
|
440
|
-
|
|
441
|
-
expect(el.selectedCreatorFilter).to.equal('C');
|
|
442
|
-
});
|
|
443
|
-
});
|
|
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 type { SortFilterBar } from '../../src/sort-filter-bar/sort-filter-bar';
|
|
6
|
+
import { SortField, defaultSortAvailability } from '../../src/models';
|
|
7
|
+
|
|
8
|
+
import '../../src/sort-filter-bar/sort-filter-bar';
|
|
9
|
+
|
|
10
|
+
describe('Sort dropdown behavior', () => {
|
|
11
|
+
let el: SortFilterBar;
|
|
12
|
+
let sortDropdown: IaDropdown;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
el = await fixture<SortFilterBar>(html`
|
|
16
|
+
<sort-filter-bar></sort-filter-bar>
|
|
17
|
+
`);
|
|
18
|
+
sortDropdown = el.shadowRoot?.querySelector('#sort-dropdown') as IaDropdown;
|
|
19
|
+
await el.updateComplete;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should render basic component', async () => {
|
|
23
|
+
const sortSelectorContainer = el.shadowRoot?.querySelector(
|
|
24
|
+
'#sort-selector-container',
|
|
25
|
+
);
|
|
26
|
+
expect(sortSelectorContainer).to.exist;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should render sort-by label', async () => {
|
|
30
|
+
const sortByLabel = el.shadowRoot?.querySelector('.sort-by-text');
|
|
31
|
+
expect(sortByLabel).to.exist;
|
|
32
|
+
expect(sortByLabel?.textContent?.trim()).to.equal('Sort by:');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should render sort direction button', async () => {
|
|
36
|
+
const sortDirections = el.shadowRoot?.querySelector(
|
|
37
|
+
'.sort-direction-container',
|
|
38
|
+
);
|
|
39
|
+
expect(sortDirections).to.exist;
|
|
40
|
+
expect(sortDirections?.querySelector('.sort-direction-icon')).to.exist;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('renders default set of sort options in dropdown', async () => {
|
|
44
|
+
expect(sortDropdown).to.exist;
|
|
45
|
+
expect(sortDropdown.options.map(o => o.id)).to.deep.equal([
|
|
46
|
+
SortField.relevance,
|
|
47
|
+
SortField.alltimeview,
|
|
48
|
+
SortField.weeklyview,
|
|
49
|
+
SortField.title,
|
|
50
|
+
SortField.date,
|
|
51
|
+
SortField.datearchived,
|
|
52
|
+
SortField.datereviewed,
|
|
53
|
+
SortField.dateadded,
|
|
54
|
+
SortField.creator,
|
|
55
|
+
]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('respects overridden sort field availability', async () => {
|
|
59
|
+
const customSortAvailability: Record<SortField, boolean> = {
|
|
60
|
+
...defaultSortAvailability,
|
|
61
|
+
[SortField.title]: false,
|
|
62
|
+
[SortField.datearchived]: false,
|
|
63
|
+
[SortField.datereviewed]: false,
|
|
64
|
+
[SortField.creator]: false,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
el.sortFieldAvailability = customSortAvailability;
|
|
68
|
+
await el.updateComplete;
|
|
69
|
+
|
|
70
|
+
const dropdown = el.shadowRoot?.querySelector(
|
|
71
|
+
'#sort-dropdown',
|
|
72
|
+
) as IaDropdown;
|
|
73
|
+
expect(dropdown.options.length).to.equal(5);
|
|
74
|
+
expect(dropdown.options.map(o => o.id)).to.deep.equal([
|
|
75
|
+
SortField.relevance,
|
|
76
|
+
SortField.alltimeview,
|
|
77
|
+
SortField.weeklyview,
|
|
78
|
+
SortField.date,
|
|
79
|
+
SortField.dateadded,
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('shows the display name of the selected sort', async () => {
|
|
84
|
+
el.selectedSort = SortField.alltimeview;
|
|
85
|
+
await el.updateComplete;
|
|
86
|
+
|
|
87
|
+
const label = sortDropdown?.querySelector('.dropdown-label');
|
|
88
|
+
expect(label?.textContent?.trim()).to.equal('All-time views');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('falls back to first available sort when default is unavailable', async () => {
|
|
92
|
+
el.selectedSort = SortField.default;
|
|
93
|
+
el.defaultSortField = SortField.relevance;
|
|
94
|
+
el.sortFieldAvailability = {
|
|
95
|
+
...defaultSortAvailability,
|
|
96
|
+
[SortField.relevance]: false,
|
|
97
|
+
};
|
|
98
|
+
await el.updateComplete;
|
|
99
|
+
|
|
100
|
+
const label = sortDropdown?.querySelector('.dropdown-label');
|
|
101
|
+
// No relevance, so fall back to the first one in the list
|
|
102
|
+
expect(label?.textContent?.trim()).to.equal('All-time views');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('changes selected sort when dropdown option selected', async () => {
|
|
106
|
+
expect(sortDropdown).to.exist;
|
|
107
|
+
|
|
108
|
+
sortDropdown.selectedOption = 'title';
|
|
109
|
+
const option = { id: 'title' };
|
|
110
|
+
sortDropdown.dispatchEvent(
|
|
111
|
+
new CustomEvent('optionSelected', { detail: { option } }),
|
|
112
|
+
);
|
|
113
|
+
await el.updateComplete;
|
|
114
|
+
|
|
115
|
+
expect(el.selectedSort).to.equal('title');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('selects a sort option by clicking it in the dropdown', async () => {
|
|
119
|
+
el.selectedSort = SortField.title;
|
|
120
|
+
await el.updateComplete;
|
|
121
|
+
|
|
122
|
+
const dropdown = el.shadowRoot?.querySelector(
|
|
123
|
+
'#sort-dropdown',
|
|
124
|
+
) as IaDropdown;
|
|
125
|
+
expect(dropdown).to.exist;
|
|
126
|
+
|
|
127
|
+
const firstOption = dropdown?.shadowRoot?.querySelector(
|
|
128
|
+
'li > button',
|
|
129
|
+
) as HTMLButtonElement;
|
|
130
|
+
expect(firstOption).to.exist;
|
|
131
|
+
|
|
132
|
+
firstOption?.click();
|
|
133
|
+
await el.updateComplete;
|
|
134
|
+
|
|
135
|
+
// The first option is relevance by default
|
|
136
|
+
expect(el.selectedSort).to.equal(SortField.relevance);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('emits sortChanged event when sort option selected', async () => {
|
|
140
|
+
const sortChangedHandler = sinon.spy();
|
|
141
|
+
el.addEventListener('sortChanged', sortChangedHandler);
|
|
142
|
+
|
|
143
|
+
const option = { id: SortField.title };
|
|
144
|
+
sortDropdown.dispatchEvent(
|
|
145
|
+
new CustomEvent('optionSelected', { detail: { option } }),
|
|
146
|
+
);
|
|
147
|
+
await el.updateComplete;
|
|
148
|
+
|
|
149
|
+
expect(sortChangedHandler.calledOnce).to.be.true;
|
|
150
|
+
const eventDetail = sortChangedHandler.firstCall.args[0].detail;
|
|
151
|
+
expect(eventDetail.selectedSort).to.equal(SortField.title);
|
|
152
|
+
expect(eventDetail.sortDirection).to.equal('asc');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('renders sort selector backdrop when dropdown is open', async () => {
|
|
156
|
+
expect(sortDropdown).to.exist;
|
|
157
|
+
|
|
158
|
+
const caret = sortDropdown?.shadowRoot?.querySelector(
|
|
159
|
+
'.caret',
|
|
160
|
+
) as HTMLElement;
|
|
161
|
+
expect(caret).to.exist;
|
|
162
|
+
|
|
163
|
+
caret!.click();
|
|
164
|
+
await el.updateComplete;
|
|
165
|
+
|
|
166
|
+
let backdrop = el.shadowRoot?.querySelector(
|
|
167
|
+
'#sort-selector-backdrop',
|
|
168
|
+
) as HTMLElement;
|
|
169
|
+
expect(backdrop).to.exist;
|
|
170
|
+
|
|
171
|
+
// Clicking the backdrop should close the dropdown
|
|
172
|
+
backdrop!.click();
|
|
173
|
+
await el.updateComplete;
|
|
174
|
+
|
|
175
|
+
backdrop = el.shadowRoot?.querySelector(
|
|
176
|
+
'#sort-selector-backdrop',
|
|
177
|
+
) as HTMLElement;
|
|
178
|
+
expect(backdrop).not.to.exist;
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('pressing Escape key closes the dropdown', async () => {
|
|
182
|
+
expect(sortDropdown).to.exist;
|
|
183
|
+
|
|
184
|
+
const caret = sortDropdown?.shadowRoot?.querySelector(
|
|
185
|
+
'.caret',
|
|
186
|
+
) as HTMLElement;
|
|
187
|
+
expect(caret).to.exist;
|
|
188
|
+
|
|
189
|
+
caret!.click();
|
|
190
|
+
await el.updateComplete;
|
|
191
|
+
|
|
192
|
+
let backdrop = el.shadowRoot?.querySelector(
|
|
193
|
+
'#sort-selector-backdrop',
|
|
194
|
+
) as HTMLElement;
|
|
195
|
+
expect(backdrop).to.exist;
|
|
196
|
+
|
|
197
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
|
|
198
|
+
await el.updateComplete;
|
|
199
|
+
|
|
200
|
+
backdrop = el.shadowRoot?.querySelector(
|
|
201
|
+
'#sort-selector-backdrop',
|
|
202
|
+
) as HTMLElement;
|
|
203
|
+
expect(backdrop).not.to.exist;
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('clears title filter when sort changed from title', async () => {
|
|
207
|
+
el.selectedSort = 'title' as SortField;
|
|
208
|
+
el.selectedTitleFilter = 'A';
|
|
209
|
+
await el.updateComplete;
|
|
210
|
+
|
|
211
|
+
const dropdown = el.shadowRoot?.querySelector(
|
|
212
|
+
'#sort-dropdown',
|
|
213
|
+
) as IaDropdown;
|
|
214
|
+
expect(dropdown).to.exist;
|
|
215
|
+
|
|
216
|
+
dropdown.selectedOption = 'relevance';
|
|
217
|
+
const option = { id: 'relevance' };
|
|
218
|
+
dropdown.dispatchEvent(
|
|
219
|
+
new CustomEvent('optionSelected', { detail: { option } }),
|
|
220
|
+
);
|
|
221
|
+
await el.updateComplete;
|
|
222
|
+
|
|
223
|
+
expect(el.selectedSort).to.equal('relevance');
|
|
224
|
+
expect(el.selectedTitleFilter).to.be.null;
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('clears creator filter when sort changed from creator', async () => {
|
|
228
|
+
el.selectedSort = 'creator' as SortField;
|
|
229
|
+
el.selectedCreatorFilter = 'A';
|
|
230
|
+
await el.updateComplete;
|
|
231
|
+
|
|
232
|
+
const dropdown = el.shadowRoot?.querySelector(
|
|
233
|
+
'#sort-dropdown',
|
|
234
|
+
) as IaDropdown;
|
|
235
|
+
expect(dropdown).to.exist;
|
|
236
|
+
|
|
237
|
+
dropdown.selectedOption = 'relevance';
|
|
238
|
+
const option = { id: 'relevance' };
|
|
239
|
+
dropdown.dispatchEvent(
|
|
240
|
+
new CustomEvent('optionSelected', { detail: { option } }),
|
|
241
|
+
);
|
|
242
|
+
await el.updateComplete;
|
|
243
|
+
|
|
244
|
+
expect(el.selectedSort).to.equal('relevance');
|
|
245
|
+
expect(el.selectedCreatorFilter).to.be.null;
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('contains sort-options slot when enabled', async () => {
|
|
249
|
+
const slotEl = await fixture<SortFilterBar>(html`
|
|
250
|
+
<sort-filter-bar .enableSortOptionsSlot=${true}></sort-filter-bar>
|
|
251
|
+
`);
|
|
252
|
+
await slotEl.updateComplete;
|
|
253
|
+
|
|
254
|
+
const sortOptionsSlot = slotEl?.shadowRoot?.querySelector(
|
|
255
|
+
'slot[name="sort-options"]',
|
|
256
|
+
);
|
|
257
|
+
expect(sortOptionsSlot).to.exist;
|
|
258
|
+
|
|
259
|
+
expect(slotEl?.shadowRoot?.querySelector('#sort-selector-container')).to.not
|
|
260
|
+
.exist;
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe('Sort direction button behavior', () => {
|
|
265
|
+
it('should disable sort direction button when sorting by relevance', async () => {
|
|
266
|
+
const el = await fixture<SortFilterBar>(html`
|
|
267
|
+
<sort-filter-bar> </sort-filter-bar>
|
|
268
|
+
`);
|
|
269
|
+
|
|
270
|
+
el.selectedSort = 'relevance' as SortField;
|
|
271
|
+
await el.updateComplete;
|
|
272
|
+
|
|
273
|
+
const sortDirectionButton = el.shadowRoot?.querySelector(
|
|
274
|
+
'.sort-direction-selector',
|
|
275
|
+
) as HTMLButtonElement;
|
|
276
|
+
expect(sortDirectionButton).to.exist;
|
|
277
|
+
expect(sortDirectionButton.disabled).to.be.true;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should enable sort direction button when not sorting by relevance', async () => {
|
|
281
|
+
const el = await fixture<SortFilterBar>(html`
|
|
282
|
+
<sort-filter-bar> </sort-filter-bar>
|
|
283
|
+
`);
|
|
284
|
+
|
|
285
|
+
el.selectedSort = 'title' as SortField;
|
|
286
|
+
await el.updateComplete;
|
|
287
|
+
|
|
288
|
+
const sortDirectionButton = el.shadowRoot?.querySelector(
|
|
289
|
+
'.sort-direction-selector',
|
|
290
|
+
) as HTMLButtonElement;
|
|
291
|
+
expect(sortDirectionButton).to.exist;
|
|
292
|
+
expect(sortDirectionButton.disabled).to.be.false;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should toggle sort direction when clicked', async () => {
|
|
296
|
+
const el = await fixture<SortFilterBar>(html`
|
|
297
|
+
<sort-filter-bar> </sort-filter-bar>
|
|
298
|
+
`);
|
|
299
|
+
|
|
300
|
+
el.selectedSort = 'title' as SortField;
|
|
301
|
+
el.sortDirection = 'asc';
|
|
302
|
+
await el.updateComplete;
|
|
303
|
+
|
|
304
|
+
const sortDirectionButton = el.shadowRoot?.querySelector(
|
|
305
|
+
'.sort-direction-selector',
|
|
306
|
+
) as HTMLButtonElement;
|
|
307
|
+
|
|
308
|
+
sortDirectionButton.click();
|
|
309
|
+
await el.updateComplete;
|
|
310
|
+
expect(el.sortDirection).to.equal('desc');
|
|
311
|
+
|
|
312
|
+
sortDirectionButton.click();
|
|
313
|
+
await el.updateComplete;
|
|
314
|
+
expect(el.sortDirection).to.equal('asc');
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
describe('Display mode/style buttons', () => {
|
|
319
|
+
it('should render all display mode buttons', async () => {
|
|
320
|
+
const el = await fixture<SortFilterBar>(html`
|
|
321
|
+
<sort-filter-bar> </sort-filter-bar>
|
|
322
|
+
`);
|
|
323
|
+
|
|
324
|
+
const displayModeButtonList = el.shadowRoot
|
|
325
|
+
?.querySelector('#display-style-selector')
|
|
326
|
+
?.querySelector('ul');
|
|
327
|
+
|
|
328
|
+
const gridButton = displayModeButtonList?.children
|
|
329
|
+
.item(0)
|
|
330
|
+
?.querySelector('#grid-button');
|
|
331
|
+
expect(gridButton).to.exist;
|
|
332
|
+
|
|
333
|
+
const detailListButton = displayModeButtonList?.children
|
|
334
|
+
.item(1)
|
|
335
|
+
?.querySelector('#list-detail-button');
|
|
336
|
+
expect(detailListButton).to.exist;
|
|
337
|
+
|
|
338
|
+
const compactListButton = displayModeButtonList?.children
|
|
339
|
+
.item(2)
|
|
340
|
+
?.querySelector('#list-compact-button');
|
|
341
|
+
expect(compactListButton).to.exist;
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should not render display mode buttons when suppressed', async () => {
|
|
345
|
+
const el = await fixture<SortFilterBar>(html`
|
|
346
|
+
<sort-filter-bar suppressDisplayModes></sort-filter-bar>
|
|
347
|
+
`);
|
|
348
|
+
|
|
349
|
+
const displayModeButtonList = el.shadowRoot?.querySelector(
|
|
350
|
+
'#display-style-selector',
|
|
351
|
+
);
|
|
352
|
+
expect(displayModeButtonList).not.to.exist;
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('should active current display mode', async () => {
|
|
356
|
+
const el = await fixture<SortFilterBar>(html`
|
|
357
|
+
<sort-filter-bar> </sort-filter-bar>
|
|
358
|
+
`);
|
|
359
|
+
|
|
360
|
+
el.displayMode = 'grid';
|
|
361
|
+
await el.updateComplete;
|
|
362
|
+
|
|
363
|
+
const displayModeTitle = el.shadowRoot
|
|
364
|
+
?.querySelector('#display-style-selector')
|
|
365
|
+
?.querySelector('button.active')
|
|
366
|
+
?.getAttribute('title');
|
|
367
|
+
expect(displayModeTitle).to.equal('Tile view');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('should change displayMode prop to the one clicked', async () => {
|
|
371
|
+
const el = await fixture<SortFilterBar>(html`
|
|
372
|
+
<sort-filter-bar> </sort-filter-bar>
|
|
373
|
+
`);
|
|
374
|
+
|
|
375
|
+
el.displayMode = 'grid';
|
|
376
|
+
await el.updateComplete;
|
|
377
|
+
|
|
378
|
+
const extendedListButton = el.shadowRoot?.querySelector(
|
|
379
|
+
'#list-detail-button',
|
|
380
|
+
) as HTMLElement;
|
|
381
|
+
extendedListButton.click();
|
|
382
|
+
await el.updateComplete;
|
|
383
|
+
expect(el.displayMode).to.equal('list-detail');
|
|
384
|
+
|
|
385
|
+
const compactListButton = el.shadowRoot?.querySelector(
|
|
386
|
+
'#list-compact-button',
|
|
387
|
+
) as HTMLElement;
|
|
388
|
+
compactListButton.click();
|
|
389
|
+
await el.updateComplete;
|
|
390
|
+
expect(el.displayMode).to.equal('list-compact');
|
|
391
|
+
|
|
392
|
+
const gridModeButton = el.shadowRoot?.querySelector(
|
|
393
|
+
'#grid-button',
|
|
394
|
+
) as HTMLElement;
|
|
395
|
+
gridModeButton.click();
|
|
396
|
+
await el.updateComplete;
|
|
397
|
+
expect(el.displayMode).to.equal('grid');
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
describe('Sort/filter bar letter behavior', () => {
|
|
402
|
+
it('sets the selected title letter when clicked', async () => {
|
|
403
|
+
const el = await fixture<SortFilterBar>(html`
|
|
404
|
+
<sort-filter-bar></sort-filter-bar>
|
|
405
|
+
`);
|
|
406
|
+
|
|
407
|
+
el.selectedSort = 'title' as SortField;
|
|
408
|
+
el.prefixFilterCountMap = { title: { T: 1 }, creator: {} };
|
|
409
|
+
await el.updateComplete;
|
|
410
|
+
|
|
411
|
+
const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
|
|
412
|
+
const letterLink = alphaBar?.shadowRoot?.querySelector(
|
|
413
|
+
'li > button:not(:disabled)',
|
|
414
|
+
) as HTMLAnchorElement;
|
|
415
|
+
expect(letterLink?.textContent?.trim()).to.equal('T');
|
|
416
|
+
|
|
417
|
+
letterLink?.click();
|
|
418
|
+
await el.updateComplete;
|
|
419
|
+
|
|
420
|
+
expect(el.selectedTitleFilter).to.equal('T');
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('sets the selected creator letter when clicked', async () => {
|
|
424
|
+
const el = await fixture<SortFilterBar>(html`
|
|
425
|
+
<sort-filter-bar></sort-filter-bar>
|
|
426
|
+
`);
|
|
427
|
+
|
|
428
|
+
el.selectedSort = 'creator' as SortField;
|
|
429
|
+
el.prefixFilterCountMap = { title: {}, creator: { C: 1 } };
|
|
430
|
+
await el.updateComplete;
|
|
431
|
+
|
|
432
|
+
const alphaBar = el.shadowRoot?.querySelector('alpha-bar');
|
|
433
|
+
const letterLink = alphaBar?.shadowRoot?.querySelector(
|
|
434
|
+
'li > button:not(:disabled)',
|
|
435
|
+
) as HTMLAnchorElement;
|
|
436
|
+
expect(letterLink?.textContent?.trim()).to.equal('C');
|
|
437
|
+
|
|
438
|
+
letterLink?.click();
|
|
439
|
+
await el.updateComplete;
|
|
440
|
+
|
|
441
|
+
expect(el.selectedCreatorFilter).to.equal('C');
|
|
442
|
+
});
|
|
443
|
+
});
|