@internetarchive/collection-browser 0.3.0 → 0.3.1-alpha.2

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 (212) hide show
  1. package/.editorconfig +29 -29
  2. package/.github/workflows/ci.yml +26 -26
  3. package/.github/workflows/gh-pages-main.yml +39 -39
  4. package/.github/workflows/npm-publish.yml +39 -39
  5. package/.github/workflows/pr-preview.yml +38 -38
  6. package/.husky/pre-commit +4 -4
  7. package/LICENSE +661 -661
  8. package/README.md +83 -83
  9. package/dist/index.d.ts +9 -9
  10. package/dist/index.js +9 -9
  11. package/dist/src/app-root.d.ts +43 -43
  12. package/dist/src/app-root.js +233 -233
  13. package/dist/src/assets/img/icons/arrow-left.d.ts +2 -2
  14. package/dist/src/assets/img/icons/arrow-left.js +2 -2
  15. package/dist/src/assets/img/icons/arrow-right.d.ts +2 -2
  16. package/dist/src/assets/img/icons/arrow-right.js +2 -2
  17. package/dist/src/assets/img/icons/chevron.d.ts +2 -2
  18. package/dist/src/assets/img/icons/chevron.js +2 -2
  19. package/dist/src/assets/img/icons/empty-query.d.ts +2 -2
  20. package/dist/src/assets/img/icons/empty-query.js +2 -2
  21. package/dist/src/assets/img/icons/eye-closed.d.ts +2 -2
  22. package/dist/src/assets/img/icons/eye-closed.js +2 -2
  23. package/dist/src/assets/img/icons/eye.d.ts +2 -2
  24. package/dist/src/assets/img/icons/eye.js +2 -2
  25. package/dist/src/assets/img/icons/favorite-filled.d.ts +1 -1
  26. package/dist/src/assets/img/icons/favorite-filled.js +2 -2
  27. package/dist/src/assets/img/icons/login-required.d.ts +1 -1
  28. package/dist/src/assets/img/icons/login-required.js +2 -2
  29. package/dist/src/assets/img/icons/mediatype/account.d.ts +1 -1
  30. package/dist/src/assets/img/icons/mediatype/account.js +2 -2
  31. package/dist/src/assets/img/icons/mediatype/audio.d.ts +1 -1
  32. package/dist/src/assets/img/icons/mediatype/audio.js +2 -2
  33. package/dist/src/assets/img/icons/mediatype/collection.d.ts +1 -1
  34. package/dist/src/assets/img/icons/mediatype/collection.js +2 -2
  35. package/dist/src/assets/img/icons/mediatype/data.d.ts +1 -1
  36. package/dist/src/assets/img/icons/mediatype/data.js +2 -2
  37. package/dist/src/assets/img/icons/mediatype/etree.d.ts +1 -1
  38. package/dist/src/assets/img/icons/mediatype/etree.js +2 -2
  39. package/dist/src/assets/img/icons/mediatype/film.d.ts +1 -1
  40. package/dist/src/assets/img/icons/mediatype/film.js +2 -2
  41. package/dist/src/assets/img/icons/mediatype/images.d.ts +1 -1
  42. package/dist/src/assets/img/icons/mediatype/images.js +2 -2
  43. package/dist/src/assets/img/icons/mediatype/radio.d.ts +1 -1
  44. package/dist/src/assets/img/icons/mediatype/radio.js +2 -2
  45. package/dist/src/assets/img/icons/mediatype/software.d.ts +1 -1
  46. package/dist/src/assets/img/icons/mediatype/software.js +2 -2
  47. package/dist/src/assets/img/icons/mediatype/texts.d.ts +1 -1
  48. package/dist/src/assets/img/icons/mediatype/texts.js +2 -2
  49. package/dist/src/assets/img/icons/mediatype/tv.d.ts +1 -1
  50. package/dist/src/assets/img/icons/mediatype/tv.js +2 -2
  51. package/dist/src/assets/img/icons/mediatype/video.d.ts +1 -1
  52. package/dist/src/assets/img/icons/mediatype/video.js +2 -2
  53. package/dist/src/assets/img/icons/mediatype/web.d.ts +1 -1
  54. package/dist/src/assets/img/icons/mediatype/web.js +2 -2
  55. package/dist/src/assets/img/icons/null-result.d.ts +2 -2
  56. package/dist/src/assets/img/icons/null-result.js +2 -2
  57. package/dist/src/assets/img/icons/restricted.d.ts +1 -1
  58. package/dist/src/assets/img/icons/restricted.js +2 -2
  59. package/dist/src/assets/img/icons/reviews.d.ts +1 -1
  60. package/dist/src/assets/img/icons/reviews.js +2 -2
  61. package/dist/src/assets/img/icons/upload.d.ts +1 -1
  62. package/dist/src/assets/img/icons/upload.js +2 -2
  63. package/dist/src/assets/img/icons/views.d.ts +1 -1
  64. package/dist/src/assets/img/icons/views.js +2 -2
  65. package/dist/src/circular-activity-indicator.d.ts +5 -5
  66. package/dist/src/circular-activity-indicator.js +17 -17
  67. package/dist/src/collection-browser.d.ts +236 -234
  68. package/dist/src/collection-browser.js +1402 -1367
  69. package/dist/src/collection-browser.js.map +1 -1
  70. package/dist/src/collection-facets/facets-template.d.ts +16 -16
  71. package/dist/src/collection-facets/facets-template.js +125 -125
  72. package/dist/src/collection-facets/more-facets-content.d.ts +74 -74
  73. package/dist/src/collection-facets/more-facets-content.js +330 -330
  74. package/dist/src/collection-facets/more-facets-pagination.d.ts +36 -36
  75. package/dist/src/collection-facets/more-facets-pagination.js +192 -192
  76. package/dist/src/collection-facets.d.ts +71 -71
  77. package/dist/src/collection-facets.js +496 -476
  78. package/dist/src/collection-facets.js.map +1 -1
  79. package/dist/src/empty-placeholder.d.ts +11 -11
  80. package/dist/src/empty-placeholder.js +42 -42
  81. package/dist/src/language-code-handler/language-code-handler.d.ts +37 -37
  82. package/dist/src/language-code-handler/language-code-handler.js +26 -26
  83. package/dist/src/language-code-handler/language-code-mapping.d.ts +1 -1
  84. package/dist/src/language-code-handler/language-code-mapping.js +562 -562
  85. package/dist/src/mediatype/mediatype-config.d.ts +3 -3
  86. package/dist/src/mediatype/mediatype-config.js +85 -85
  87. package/dist/src/models.d.ts +97 -89
  88. package/dist/src/models.js +100 -85
  89. package/dist/src/models.js.map +1 -1
  90. package/dist/src/restoration-state-handler.d.ts +46 -45
  91. package/dist/src/restoration-state-handler.js +231 -219
  92. package/dist/src/restoration-state-handler.js.map +1 -1
  93. package/dist/src/sort-filter-bar/alpha-bar.d.ts +9 -9
  94. package/dist/src/sort-filter-bar/alpha-bar.js +41 -41
  95. package/dist/src/sort-filter-bar/img/compact.d.ts +1 -1
  96. package/dist/src/sort-filter-bar/img/compact.js +2 -2
  97. package/dist/src/sort-filter-bar/img/list.d.ts +1 -1
  98. package/dist/src/sort-filter-bar/img/list.js +2 -2
  99. package/dist/src/sort-filter-bar/img/sort-triangle.d.ts +1 -1
  100. package/dist/src/sort-filter-bar/img/sort-triangle.js +2 -2
  101. package/dist/src/sort-filter-bar/img/tile.d.ts +1 -1
  102. package/dist/src/sort-filter-bar/img/tile.js +2 -2
  103. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +107 -107
  104. package/dist/src/sort-filter-bar/sort-filter-bar.js +423 -423
  105. package/dist/src/styles/item-image-styles.d.ts +8 -8
  106. package/dist/src/styles/item-image-styles.js +9 -9
  107. package/dist/src/tiles/collection-browser-loading-tile.d.ts +5 -5
  108. package/dist/src/tiles/collection-browser-loading-tile.js +15 -15
  109. package/dist/src/tiles/grid/account-tile.d.ts +8 -8
  110. package/dist/src/tiles/grid/account-tile.js +20 -20
  111. package/dist/src/tiles/grid/collection-tile.d.ts +7 -7
  112. package/dist/src/tiles/grid/collection-tile.js +23 -23
  113. package/dist/src/tiles/grid/item-tile.d.ts +24 -24
  114. package/dist/src/tiles/grid/item-tile.js +87 -87
  115. package/dist/src/tiles/grid/tile-stats.d.ts +10 -10
  116. package/dist/src/tiles/grid/tile-stats.js +35 -35
  117. package/dist/src/tiles/image-block.d.ts +17 -17
  118. package/dist/src/tiles/image-block.js +73 -73
  119. package/dist/src/tiles/item-image.d.ts +31 -31
  120. package/dist/src/tiles/item-image.js +103 -103
  121. package/dist/src/tiles/list/account-label.d.ts +1 -1
  122. package/dist/src/tiles/list/account-label.js +6 -6
  123. package/dist/src/tiles/list/date-label.d.ts +1 -1
  124. package/dist/src/tiles/list/date-label.js +12 -12
  125. package/dist/src/tiles/list/tile-list-compact-header.d.ts +12 -12
  126. package/dist/src/tiles/list/tile-list-compact-header.js +41 -41
  127. package/dist/src/tiles/list/tile-list-compact.d.ts +20 -20
  128. package/dist/src/tiles/list/tile-list-compact.js +87 -87
  129. package/dist/src/tiles/list/tile-list.d.ts +50 -50
  130. package/dist/src/tiles/list/tile-list.js +263 -263
  131. package/dist/src/tiles/mediatype-icon.d.ts +9 -9
  132. package/dist/src/tiles/mediatype-icon.js +47 -47
  133. package/dist/src/tiles/overlay/icon-overlay.d.ts +7 -7
  134. package/dist/src/tiles/overlay/icon-overlay.js +31 -31
  135. package/dist/src/tiles/overlay/text-overlay.d.ts +8 -8
  136. package/dist/src/tiles/overlay/text-overlay.js +31 -31
  137. package/dist/src/tiles/text-snippet-block.d.ts +29 -29
  138. package/dist/src/tiles/text-snippet-block.js +81 -81
  139. package/dist/src/tiles/tile-dispatcher.d.ts +36 -36
  140. package/dist/src/tiles/tile-dispatcher.js +128 -128
  141. package/dist/src/utils/analytics-events.d.ts +18 -18
  142. package/dist/src/utils/analytics-events.js +20 -20
  143. package/dist/src/utils/format-count.d.ts +7 -7
  144. package/dist/src/utils/format-count.js +75 -75
  145. package/dist/src/utils/format-date.d.ts +2 -2
  146. package/dist/src/utils/format-date.js +23 -23
  147. package/dist/test/collection-browser.test.d.ts +1 -1
  148. package/dist/test/collection-browser.test.js +344 -342
  149. package/dist/test/collection-browser.test.js.map +1 -1
  150. package/dist/test/collection-facets/facets-template.test.d.ts +1 -1
  151. package/dist/test/collection-facets/facets-template.test.js +62 -62
  152. package/dist/test/collection-facets/more-facets-content.test.d.ts +1 -1
  153. package/dist/test/collection-facets/more-facets-content.test.js +91 -91
  154. package/dist/test/collection-facets/more-facets-pagination.test.d.ts +1 -1
  155. package/dist/test/collection-facets/more-facets-pagination.test.js +117 -117
  156. package/dist/test/collection-facets.test.d.ts +2 -2
  157. package/dist/test/collection-facets.test.js +182 -182
  158. package/dist/test/empty-placeholder.test.d.ts +1 -1
  159. package/dist/test/empty-placeholder.test.js +33 -33
  160. package/dist/test/icon-overlay.test.d.ts +1 -1
  161. package/dist/test/icon-overlay.test.js +24 -24
  162. package/dist/test/item-image.test.d.ts +1 -1
  163. package/dist/test/item-image.test.js +56 -56
  164. package/dist/test/mediatype-config.test.d.ts +1 -1
  165. package/dist/test/mediatype-config.test.js +16 -16
  166. package/dist/test/mocks/mock-analytics-handler.d.ts +10 -10
  167. package/dist/test/mocks/mock-analytics-handler.js +15 -15
  168. package/dist/test/mocks/mock-collection-name-cache.d.ts +7 -7
  169. package/dist/test/mocks/mock-collection-name-cache.js +13 -13
  170. package/dist/test/mocks/mock-search-responses.d.ts +5 -5
  171. package/dist/test/mocks/mock-search-responses.js +103 -103
  172. package/dist/test/mocks/mock-search-service.d.ts +13 -13
  173. package/dist/test/mocks/mock-search-service.js +25 -25
  174. package/dist/test/restoration-state-handler.test.d.ts +1 -1
  175. package/dist/test/restoration-state-handler.test.js +117 -117
  176. package/dist/test/sort-filter-bar/sort-filter-bar.test.d.ts +1 -1
  177. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +113 -113
  178. package/dist/test/text-overlay.test.d.ts +1 -1
  179. package/dist/test/text-overlay.test.js +41 -41
  180. package/dist/test/text-snippet-block.test.d.ts +1 -1
  181. package/dist/test/text-snippet-block.test.js +57 -57
  182. package/dist/test/tile-stats.test.d.ts +1 -1
  183. package/dist/test/tile-stats.test.js +33 -33
  184. package/dist/test/tiles/grid/item-tile.test.d.ts +1 -1
  185. package/dist/test/tiles/grid/item-tile.test.js +107 -107
  186. package/dist/test/tiles/list/tile-list.test.d.ts +1 -1
  187. package/dist/test/tiles/list/tile-list.test.js +36 -36
  188. package/dist/test/utils/format-count.test.d.ts +1 -1
  189. package/dist/test/utils/format-count.test.js +23 -23
  190. package/dist/test/utils/format-date.test.d.ts +1 -1
  191. package/dist/test/utils/format-date.test.js +17 -17
  192. package/index.html +24 -24
  193. package/local.archive.org.cert +86 -86
  194. package/local.archive.org.key +27 -27
  195. package/package.json +115 -115
  196. package/renovate.json +6 -6
  197. package/src/collection-browser.ts +1526 -1489
  198. package/src/collection-facets.ts +569 -541
  199. package/src/models.ts +216 -188
  200. package/src/restoration-state-handler.ts +314 -301
  201. package/test/collection-browser.test.ts +490 -488
  202. package/tsconfig.json +21 -21
  203. package/web-dev-server.config.mjs +30 -30
  204. package/web-test-runner.config.mjs +41 -41
  205. package/dist/src/collection-facets/facets-util.d.ts +0 -10
  206. package/dist/src/collection-facets/facets-util.js +0 -20
  207. package/dist/src/collection-facets/facets-util.js.map +0 -1
  208. package/dist/test/collection-facets/facets-util.test.d.ts +0 -1
  209. package/dist/test/collection-facets/facets-util.test.js +0 -13
  210. package/dist/test/collection-facets/facets-util.test.js.map +0 -1
  211. package/src/collection-facets/facets-util.ts +0 -22
  212. package/test/collection-facets/facets-util.test.ts +0 -18
@@ -1,488 +1,490 @@
1
- /* eslint-disable import/no-duplicates */
2
- import { expect, fixture } from '@open-wc/testing';
3
- import { html } from 'lit';
4
- import sinon from 'sinon';
5
- import type { InfiniteScroller } from '@internetarchive/infinite-scroller';
6
- import { SearchType } from '@internetarchive/search-service';
7
- import type { CollectionBrowser } from '../src/collection-browser';
8
- import '../src/collection-browser';
9
- import {
10
- defaultSelectedFacets,
11
- FacetBucket,
12
- SelectedFacets,
13
- SortField,
14
- } from '../src/models';
15
- import { MockSearchService } from './mocks/mock-search-service';
16
- import { MockCollectionNameCache } from './mocks/mock-collection-name-cache';
17
- import { MockAnalyticsHandler } from './mocks/mock-analytics-handler';
18
- import { analyticsCategories } from '../src/utils/analytics-events';
19
-
20
- describe('Collection Browser', () => {
21
- it('clear existing filter for facets & sort-bar', async () => {
22
- const el = await fixture<CollectionBrowser>(
23
- html`<collection-browser></collection-browser>`
24
- );
25
-
26
- el.selectedSort = 'title' as SortField;
27
- await el.updateComplete;
28
- el.clearFilters();
29
-
30
- expect(el.selectedFacets).to.equal(defaultSelectedFacets);
31
- expect(el.selectedSort).to.equal('relevance');
32
- expect(el.sortDirection).to.null;
33
- expect(el.sortParam).to.null;
34
- expect(el.selectedCreatorFilter).to.null;
35
- expect(el.selectedTitleFilter).to.null;
36
- });
37
-
38
- it('filterBy creator with analytics', async () => {
39
- const mockAnalyticsHandler = new MockAnalyticsHandler();
40
- const el = await fixture<CollectionBrowser>(
41
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
42
- </collection-browser>`
43
- );
44
-
45
- el.searchContext = 'betaSearchService';
46
- el.selectedCreatorFilter = 'A';
47
- await el.updateComplete;
48
-
49
- expect(mockAnalyticsHandler.callCategory).to.equal('betaSearchService');
50
- expect(mockAnalyticsHandler.callAction).to.equal('filterByCreator');
51
- expect(mockAnalyticsHandler.callLabel).to.equal('start-A');
52
-
53
- el.clearFilters();
54
- await el.updateComplete;
55
-
56
- expect(el.selectedTitleFilter).to.null;
57
- expect(mockAnalyticsHandler.callCategory).to.equal('betaSearchService');
58
- expect(mockAnalyticsHandler.callAction).to.equal('filterByCreator');
59
- expect(mockAnalyticsHandler.callLabel).to.equal('clear-A');
60
- });
61
-
62
- it('filterBy title with analytics', async () => {
63
- const mockAnalyticsHandler = new MockAnalyticsHandler();
64
- const el = await fixture<CollectionBrowser>(
65
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
66
- </collection-browser>`
67
- );
68
-
69
- el.searchContext = 'beta-search-service';
70
- el.selectedSort = 'title' as SortField;
71
- el.selectedTitleFilter = 'A';
72
- await el.updateComplete;
73
-
74
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
75
- expect(mockAnalyticsHandler.callAction).to.equal('filterByTitle');
76
- expect(mockAnalyticsHandler.callLabel).to.equal('start-A');
77
-
78
- el.clearFilters();
79
- await el.updateComplete;
80
-
81
- expect(el.selectedTitleFilter).to.null;
82
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
83
- expect(mockAnalyticsHandler.callAction).to.equal('filterByTitle');
84
- expect(mockAnalyticsHandler.callLabel).to.equal('clear-A');
85
- });
86
-
87
- it('selected facets with analytics - not negative facets', async () => {
88
- const mockAnalyticsHandler = new MockAnalyticsHandler();
89
- const mediaTypeBucket = { count: 123, state: 'selected' } as FacetBucket;
90
- const mockedSelectedFacets: SelectedFacets = {
91
- subject: {},
92
- mediatype: { data: mediaTypeBucket },
93
- language: {},
94
- creator: {},
95
- collection: {},
96
- year: {},
97
- };
98
-
99
- const el = await fixture<CollectionBrowser>(
100
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
101
- </collection-browser>`
102
- );
103
-
104
- el.searchContext = 'search-service';
105
- el.selectedFacets = mockedSelectedFacets;
106
- await el.updateComplete;
107
-
108
- el.facetClickHandler('mediatype', true, false);
109
- expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
110
- expect(mockAnalyticsHandler.callAction).to.equal('facetSelected');
111
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
112
-
113
- el.facetClickHandler('mediatype', false, false);
114
- expect(el.selectedFacets).to.equal(mockedSelectedFacets);
115
- expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
116
- expect(mockAnalyticsHandler.callAction).to.equal('facetDeselected');
117
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
118
- });
119
-
120
- it('selected facets with analytics - negative facets', async () => {
121
- const mockAnalyticsHandler = new MockAnalyticsHandler();
122
- const mediaTypeBucket = { count: 123, state: 'selected' } as FacetBucket;
123
- const mockedSelectedFacets: SelectedFacets = {
124
- subject: {},
125
- mediatype: { data: mediaTypeBucket },
126
- language: {},
127
- creator: {},
128
- collection: {},
129
- year: {},
130
- };
131
-
132
- const el = await fixture<CollectionBrowser>(
133
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
134
- </collection-browser>`
135
- );
136
-
137
- el.searchContext = 'beta-search-service';
138
- el.selectedFacets = mockedSelectedFacets;
139
- await el.updateComplete;
140
-
141
- el.facetClickHandler('mediatype', true, true);
142
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
143
- expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeSelected');
144
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
145
-
146
- el.facetClickHandler('mediatype', false, true);
147
- expect(el.selectedFacets).to.equal(mockedSelectedFacets);
148
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
149
- expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeDeselected');
150
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
151
- });
152
-
153
- it('should render with a sort bar, facets, and infinite scroller', async () => {
154
- const el = await fixture<CollectionBrowser>(
155
- html`<collection-browser></collection-browser>`
156
- );
157
-
158
- el.baseQuery = 'hello';
159
- await el.updateComplete;
160
-
161
- const facets = el.shadowRoot?.querySelector('collection-facets');
162
- const sortBar = el.shadowRoot?.querySelector('sort-filter-bar');
163
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
164
- expect(facets).to.exist;
165
- expect(sortBar).to.exist;
166
- expect(infiniteScroller).to.exist;
167
- });
168
-
169
- it('queries the search service when given a base query', async () => {
170
- const searchService = new MockSearchService();
171
-
172
- const el = await fixture<CollectionBrowser>(
173
- html`<collection-browser .searchService=${searchService}>
174
- </collection-browser>`
175
- );
176
-
177
- el.baseQuery = 'collection:foo';
178
- await el.updateComplete;
179
-
180
- expect(searchService.searchParams?.query).to.equal('collection:foo');
181
- expect(
182
- el.shadowRoot?.querySelector('#big-results-label')?.textContent
183
- ).to.contains('Results');
184
- });
185
-
186
- it('queries the search service with a metadata search', async () => {
187
- const searchService = new MockSearchService();
188
-
189
- const el = await fixture<CollectionBrowser>(
190
- html` <collection-browser
191
- .searchService=${searchService}
192
- .searchType=${SearchType.METADATA}
193
- >
194
- </collection-browser>`
195
- );
196
-
197
- el.baseQuery = 'collection:foo';
198
- await el.updateComplete;
199
-
200
- expect(searchService.searchParams?.query).to.equal('collection:foo');
201
- expect(searchService.searchType).to.equal(SearchType.METADATA);
202
- expect(
203
- el.shadowRoot?.querySelector('#big-results-label')?.textContent
204
- ).to.contains('Results');
205
- });
206
-
207
- it('queries the search service with a fulltext search', async () => {
208
- const searchService = new MockSearchService();
209
-
210
- const el = await fixture<CollectionBrowser>(
211
- html` <collection-browser
212
- .searchService=${searchService}
213
- .searchType=${SearchType.FULLTEXT}
214
- >
215
- </collection-browser>`
216
- );
217
-
218
- el.baseQuery = 'collection:foo';
219
- await el.updateComplete;
220
-
221
- expect(searchService.searchParams?.query).to.equal('collection:foo');
222
- expect(searchService.searchType).to.equal(SearchType.FULLTEXT);
223
- expect(
224
- el.shadowRoot?.querySelector('#big-results-label')?.textContent
225
- ).to.contains('Results');
226
- });
227
-
228
- it('queries for collection names after a fetch', async () => {
229
- const searchService = new MockSearchService();
230
- const collectionNameCache = new MockCollectionNameCache();
231
-
232
- const el = await fixture<CollectionBrowser>(
233
- html`<collection-browser
234
- .searchService=${searchService}
235
- .collectionNameCache=${collectionNameCache}
236
- >
237
- </collection-browser>`
238
- );
239
-
240
- el.baseQuery = 'blahblah';
241
- await el.updateComplete;
242
-
243
- expect(collectionNameCache.preloadIdentifiersRequested).to.deep.equal([
244
- 'foo',
245
- 'bar',
246
- 'baz',
247
- 'boop',
248
- ]);
249
- });
250
-
251
- it('keeps search results from fetch if no change to query or sort param', async () => {
252
- const resultsSpy = sinon.spy();
253
- const searchService = new MockSearchService({
254
- asyncResponse: true,
255
- resultsSpy,
256
- });
257
-
258
- const el = await fixture<CollectionBrowser>(
259
- html`<collection-browser .searchService=${searchService}>
260
- </collection-browser>`
261
- );
262
-
263
- el.baseQuery = 'with-sort';
264
- el.sortParam = { field: 'foo', direction: 'asc' };
265
- await el.updateComplete;
266
-
267
- await el.fetchPage(2);
268
-
269
- // If there is no change to the query or sort param during the fetch, the results
270
- // should be read.
271
- expect(resultsSpy.callCount).to.be.greaterThanOrEqual(1);
272
- });
273
-
274
- it('discards obsolete search results if sort params changed before arrival', async () => {
275
- const resultsSpy = sinon.spy();
276
- const searchService = new MockSearchService({
277
- asyncResponse: true,
278
- resultsSpy,
279
- });
280
-
281
- const el = await fixture<CollectionBrowser>(
282
- html`<collection-browser .searchService=${searchService}>
283
- </collection-browser>`
284
- );
285
-
286
- el.baseQuery = 'with-sort';
287
- el.sortParam = { field: 'foo', direction: 'asc' };
288
- await el.updateComplete;
289
-
290
- const fetchPromise = el.fetchPage(2);
291
- el.sortParam = { field: 'foo', direction: 'desc' };
292
- await fetchPromise;
293
-
294
- // If the different sort param causes the results to be discarded,
295
- // the results array should never be read.
296
- expect(resultsSpy.callCount).to.equal(0);
297
- });
298
-
299
- it('discards obsolete search results if sort param added before arrival', async () => {
300
- const resultsSpy = sinon.spy();
301
- const searchService = new MockSearchService({
302
- asyncResponse: true,
303
- resultsSpy,
304
- });
305
-
306
- const el = await fixture<CollectionBrowser>(
307
- html`<collection-browser .searchService=${searchService}>
308
- </collection-browser>`
309
- );
310
-
311
- el.baseQuery = 'single-result';
312
- await el.updateComplete;
313
-
314
- const fetchPromise = el.fetchPage(2);
315
- el.sortParam = { field: 'foo', direction: 'asc' };
316
- await fetchPromise;
317
-
318
- // If the different sort param causes the results to be discarded,
319
- // the results array should never be read.
320
- expect(resultsSpy.callCount).to.equal(0);
321
- });
322
-
323
- it('discards obsolete search results if sort param cleared before arrival', async () => {
324
- const resultsSpy = sinon.spy();
325
- const searchService = new MockSearchService({
326
- asyncResponse: true,
327
- resultsSpy,
328
- });
329
-
330
- const el = await fixture<CollectionBrowser>(
331
- html`<collection-browser .searchService=${searchService}>
332
- </collection-browser>`
333
- );
334
-
335
- el.baseQuery = 'with-sort';
336
- await el.updateComplete;
337
-
338
- const fetchPromise = el.fetchPage(2);
339
- el.sortParam = null;
340
- await fetchPromise;
341
-
342
- // If the different sort param causes the results to be discarded,
343
- // the results array should never be read.
344
- expect(resultsSpy.callCount).to.equal(0);
345
- });
346
-
347
- it('sets sort properties when user changes sort', async () => {
348
- const el = await fixture<CollectionBrowser>(
349
- html`<collection-browser></collection-browser>`
350
- );
351
-
352
- expect(el.selectedSort).to.equal(SortField.relevance);
353
-
354
- el.baseQuery = 'foo';
355
- await el.updateComplete;
356
-
357
- const sortBar = el.shadowRoot?.querySelector('sort-filter-bar');
358
- const sortSelector = sortBar?.shadowRoot?.querySelector(
359
- '#desktop-sort-selector'
360
- );
361
- expect(sortSelector).to.exist;
362
-
363
- // Click the title sorter
364
- [...(sortSelector?.children as HTMLCollection & Iterable<any>)] // tsc doesn't know children is iterable
365
- .find(child => child.textContent?.trim() === 'Title')
366
- ?.querySelector('a[href]')
367
- ?.click();
368
-
369
- await el.updateComplete;
370
-
371
- expect(el.selectedSort).to.equal(SortField.title);
372
- });
373
-
374
- it('scrolls to page', async () => {
375
- const el = await fixture<CollectionBrowser>(
376
- html`<collection-browser></collection-browser>`
377
- );
378
-
379
- const infiniteScroller = el.shadowRoot?.querySelector(
380
- 'infinite-scroller'
381
- ) as InfiniteScroller;
382
- expect(infiniteScroller).to.exist;
383
-
384
- const oldScrollToCell = infiniteScroller.scrollToCell;
385
- const spy = sinon.spy();
386
- infiniteScroller.scrollToCell = spy;
387
-
388
- el.goToPage(1);
389
-
390
- // Give it a second to scroll
391
- await new Promise(res => {
392
- setTimeout(res, 1000);
393
- });
394
-
395
- expect(spy.callCount).to.equal(1);
396
-
397
- infiniteScroller.scrollToCell = oldScrollToCell;
398
- });
399
-
400
- it('refreshes when certain properties change - with some analytics event sampling', async () => {
401
- const mockAnalyticsHandler = new MockAnalyticsHandler();
402
- const searchService = new MockSearchService();
403
- const collectionNameCache = new MockCollectionNameCache();
404
- const el = await fixture<CollectionBrowser>(
405
- html`<collection-browser
406
- .analyticsHandler=${mockAnalyticsHandler}
407
- .searchService=${searchService}
408
- .collectionNameCache=${collectionNameCache}
409
- ></collection-browser>`
410
- );
411
- const infiniteScrollerRefreshSpy = sinon.spy();
412
-
413
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
414
- (infiniteScroller as InfiniteScroller).reload = infiniteScrollerRefreshSpy;
415
- expect(infiniteScrollerRefreshSpy.called).to.be.false;
416
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(0);
417
-
418
- // testing: `loggedIn`
419
- el.loggedIn = true;
420
- await el.updateComplete;
421
- expect(infiniteScrollerRefreshSpy.called).to.be.true;
422
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(1);
423
-
424
- el.loggedIn = false;
425
- await el.updateComplete;
426
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(2);
427
-
428
- // testing: `displayMode`
429
- el.displayMode = 'list-compact';
430
- el.searchContext = 'beta-search';
431
- await el.updateComplete;
432
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(3);
433
-
434
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search');
435
- expect(mockAnalyticsHandler.callAction).to.equal('displayMode');
436
- expect(mockAnalyticsHandler.callLabel).to.equal('list-compact');
437
-
438
- el.displayMode = 'list-detail';
439
- await el.updateComplete;
440
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(4);
441
-
442
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search');
443
- expect(mockAnalyticsHandler.callAction).to.equal('displayMode');
444
- expect(mockAnalyticsHandler.callLabel).to.equal('list-detail');
445
-
446
- // testing: `baseNavigationUrl`
447
- el.baseNavigationUrl = 'https://funtestsite.com';
448
- await el.updateComplete;
449
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(5);
450
-
451
- // testing: `baseImageUrl`
452
- el.baseImageUrl = 'https://funtestsiteforimages.com';
453
- await el.updateComplete;
454
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(6);
455
- });
456
-
457
- it('query the search service for single result', async () => {
458
- const searchService = new MockSearchService();
459
-
460
- const el = await fixture<CollectionBrowser>(
461
- html`<collection-browser .searchService=${searchService}>
462
- </collection-browser>`
463
- );
464
-
465
- el.baseQuery = 'single-result';
466
- await el.updateComplete;
467
-
468
- expect(
469
- el.shadowRoot?.querySelector('#big-results-label')?.textContent
470
- ).to.contains('Result');
471
- });
472
-
473
- it('`searchContext` prop helps describe where component is being used', async () => {
474
- const el = await fixture<CollectionBrowser>(
475
- html`<collection-browser></collection-browser>`
476
- );
477
-
478
- expect(el.searchContext).to.equal(analyticsCategories.default);
479
-
480
- el.searchContext = 'unicorn-search';
481
- await el.updateComplete;
482
-
483
- expect(el.searchContext).to.equal('unicorn-search');
484
-
485
- // property is reflected as attribute
486
- expect(el.getAttribute('searchcontext')).to.equal('unicorn-search');
487
- });
488
- });
1
+ /* eslint-disable import/no-duplicates */
2
+ import { expect, fixture } from '@open-wc/testing';
3
+ import { html } from 'lit';
4
+ import sinon from 'sinon';
5
+ import type { InfiniteScroller } from '@internetarchive/infinite-scroller';
6
+ import { SearchType } from '@internetarchive/search-service';
7
+ import type { CollectionBrowser } from '../src/collection-browser';
8
+ import '../src/collection-browser';
9
+ import {
10
+ defaultSelectedFacets,
11
+ FacetBucket,
12
+ SelectedFacets,
13
+ SortField,
14
+ } from '../src/models';
15
+ import { MockSearchService } from './mocks/mock-search-service';
16
+ import { MockCollectionNameCache } from './mocks/mock-collection-name-cache';
17
+ import { MockAnalyticsHandler } from './mocks/mock-analytics-handler';
18
+ import { analyticsCategories } from '../src/utils/analytics-events';
19
+
20
+ describe('Collection Browser', () => {
21
+ it('clear existing filter for facets & sort-bar', async () => {
22
+ const el = await fixture<CollectionBrowser>(
23
+ html`<collection-browser></collection-browser>`
24
+ );
25
+
26
+ el.selectedSort = 'title' as SortField;
27
+ await el.updateComplete;
28
+ el.clearFilters();
29
+
30
+ expect(el.selectedFacets).to.equal(defaultSelectedFacets);
31
+ expect(el.selectedSort).to.equal('relevance');
32
+ expect(el.sortDirection).to.null;
33
+ expect(el.sortParam).to.null;
34
+ expect(el.selectedCreatorFilter).to.null;
35
+ expect(el.selectedTitleFilter).to.null;
36
+ });
37
+
38
+ it('filterBy creator with analytics', async () => {
39
+ const mockAnalyticsHandler = new MockAnalyticsHandler();
40
+ const el = await fixture<CollectionBrowser>(
41
+ html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
42
+ </collection-browser>`
43
+ );
44
+
45
+ el.searchContext = 'betaSearchService';
46
+ el.selectedCreatorFilter = 'A';
47
+ await el.updateComplete;
48
+
49
+ expect(mockAnalyticsHandler.callCategory).to.equal('betaSearchService');
50
+ expect(mockAnalyticsHandler.callAction).to.equal('filterByCreator');
51
+ expect(mockAnalyticsHandler.callLabel).to.equal('start-A');
52
+
53
+ el.clearFilters();
54
+ await el.updateComplete;
55
+
56
+ expect(el.selectedTitleFilter).to.null;
57
+ expect(mockAnalyticsHandler.callCategory).to.equal('betaSearchService');
58
+ expect(mockAnalyticsHandler.callAction).to.equal('filterByCreator');
59
+ expect(mockAnalyticsHandler.callLabel).to.equal('clear-A');
60
+ });
61
+
62
+ it('filterBy title with analytics', async () => {
63
+ const mockAnalyticsHandler = new MockAnalyticsHandler();
64
+ const el = await fixture<CollectionBrowser>(
65
+ html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
66
+ </collection-browser>`
67
+ );
68
+
69
+ el.searchContext = 'beta-search-service';
70
+ el.selectedSort = 'title' as SortField;
71
+ el.selectedTitleFilter = 'A';
72
+ await el.updateComplete;
73
+
74
+ expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
75
+ expect(mockAnalyticsHandler.callAction).to.equal('filterByTitle');
76
+ expect(mockAnalyticsHandler.callLabel).to.equal('start-A');
77
+
78
+ el.clearFilters();
79
+ await el.updateComplete;
80
+
81
+ expect(el.selectedTitleFilter).to.null;
82
+ expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
83
+ expect(mockAnalyticsHandler.callAction).to.equal('filterByTitle');
84
+ expect(mockAnalyticsHandler.callLabel).to.equal('clear-A');
85
+ });
86
+
87
+ it('selected facets with analytics - not negative facets', async () => {
88
+ const mockAnalyticsHandler = new MockAnalyticsHandler();
89
+ const mediaTypeBucket = { count: 123, state: 'selected' } as FacetBucket;
90
+ const mockedSelectedFacets: SelectedFacets = {
91
+ subject: {},
92
+ lending: {},
93
+ mediatype: { data: mediaTypeBucket },
94
+ language: {},
95
+ creator: {},
96
+ collection: {},
97
+ year: {},
98
+ };
99
+
100
+ const el = await fixture<CollectionBrowser>(
101
+ html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
102
+ </collection-browser>`
103
+ );
104
+
105
+ el.searchContext = 'search-service';
106
+ el.selectedFacets = mockedSelectedFacets;
107
+ await el.updateComplete;
108
+
109
+ el.facetClickHandler('mediatype', true, false);
110
+ expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
111
+ expect(mockAnalyticsHandler.callAction).to.equal('facetSelected');
112
+ expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
113
+
114
+ el.facetClickHandler('mediatype', false, false);
115
+ expect(el.selectedFacets).to.equal(mockedSelectedFacets);
116
+ expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
117
+ expect(mockAnalyticsHandler.callAction).to.equal('facetDeselected');
118
+ expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
119
+ });
120
+
121
+ it('selected facets with analytics - negative facets', async () => {
122
+ const mockAnalyticsHandler = new MockAnalyticsHandler();
123
+ const mediaTypeBucket = { count: 123, state: 'selected' } as FacetBucket;
124
+ const mockedSelectedFacets: SelectedFacets = {
125
+ subject: {},
126
+ lending: {},
127
+ mediatype: { data: mediaTypeBucket },
128
+ language: {},
129
+ creator: {},
130
+ collection: {},
131
+ year: {},
132
+ };
133
+
134
+ const el = await fixture<CollectionBrowser>(
135
+ html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
136
+ </collection-browser>`
137
+ );
138
+
139
+ el.searchContext = 'beta-search-service';
140
+ el.selectedFacets = mockedSelectedFacets;
141
+ await el.updateComplete;
142
+
143
+ el.facetClickHandler('mediatype', true, true);
144
+ expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
145
+ expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeSelected');
146
+ expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
147
+
148
+ el.facetClickHandler('mediatype', false, true);
149
+ expect(el.selectedFacets).to.equal(mockedSelectedFacets);
150
+ expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
151
+ expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeDeselected');
152
+ expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
153
+ });
154
+
155
+ it('should render with a sort bar, facets, and infinite scroller', async () => {
156
+ const el = await fixture<CollectionBrowser>(
157
+ html`<collection-browser></collection-browser>`
158
+ );
159
+
160
+ el.baseQuery = 'hello';
161
+ await el.updateComplete;
162
+
163
+ const facets = el.shadowRoot?.querySelector('collection-facets');
164
+ const sortBar = el.shadowRoot?.querySelector('sort-filter-bar');
165
+ const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
166
+ expect(facets).to.exist;
167
+ expect(sortBar).to.exist;
168
+ expect(infiniteScroller).to.exist;
169
+ });
170
+
171
+ it('queries the search service when given a base query', async () => {
172
+ const searchService = new MockSearchService();
173
+
174
+ const el = await fixture<CollectionBrowser>(
175
+ html`<collection-browser .searchService=${searchService}>
176
+ </collection-browser>`
177
+ );
178
+
179
+ el.baseQuery = 'collection:foo';
180
+ await el.updateComplete;
181
+
182
+ expect(searchService.searchParams?.query).to.equal('collection:foo');
183
+ expect(
184
+ el.shadowRoot?.querySelector('#big-results-label')?.textContent
185
+ ).to.contains('Results');
186
+ });
187
+
188
+ it('queries the search service with a metadata search', async () => {
189
+ const searchService = new MockSearchService();
190
+
191
+ const el = await fixture<CollectionBrowser>(
192
+ html` <collection-browser
193
+ .searchService=${searchService}
194
+ .searchType=${SearchType.METADATA}
195
+ >
196
+ </collection-browser>`
197
+ );
198
+
199
+ el.baseQuery = 'collection:foo';
200
+ await el.updateComplete;
201
+
202
+ expect(searchService.searchParams?.query).to.equal('collection:foo');
203
+ expect(searchService.searchType).to.equal(SearchType.METADATA);
204
+ expect(
205
+ el.shadowRoot?.querySelector('#big-results-label')?.textContent
206
+ ).to.contains('Results');
207
+ });
208
+
209
+ it('queries the search service with a fulltext search', async () => {
210
+ const searchService = new MockSearchService();
211
+
212
+ const el = await fixture<CollectionBrowser>(
213
+ html` <collection-browser
214
+ .searchService=${searchService}
215
+ .searchType=${SearchType.FULLTEXT}
216
+ >
217
+ </collection-browser>`
218
+ );
219
+
220
+ el.baseQuery = 'collection:foo';
221
+ await el.updateComplete;
222
+
223
+ expect(searchService.searchParams?.query).to.equal('collection:foo');
224
+ expect(searchService.searchType).to.equal(SearchType.FULLTEXT);
225
+ expect(
226
+ el.shadowRoot?.querySelector('#big-results-label')?.textContent
227
+ ).to.contains('Results');
228
+ });
229
+
230
+ it('queries for collection names after a fetch', async () => {
231
+ const searchService = new MockSearchService();
232
+ const collectionNameCache = new MockCollectionNameCache();
233
+
234
+ const el = await fixture<CollectionBrowser>(
235
+ html`<collection-browser
236
+ .searchService=${searchService}
237
+ .collectionNameCache=${collectionNameCache}
238
+ >
239
+ </collection-browser>`
240
+ );
241
+
242
+ el.baseQuery = 'blahblah';
243
+ await el.updateComplete;
244
+
245
+ expect(collectionNameCache.preloadIdentifiersRequested).to.deep.equal([
246
+ 'foo',
247
+ 'bar',
248
+ 'baz',
249
+ 'boop',
250
+ ]);
251
+ });
252
+
253
+ it('keeps search results from fetch if no change to query or sort param', async () => {
254
+ const resultsSpy = sinon.spy();
255
+ const searchService = new MockSearchService({
256
+ asyncResponse: true,
257
+ resultsSpy,
258
+ });
259
+
260
+ const el = await fixture<CollectionBrowser>(
261
+ html`<collection-browser .searchService=${searchService}>
262
+ </collection-browser>`
263
+ );
264
+
265
+ el.baseQuery = 'with-sort';
266
+ el.sortParam = { field: 'foo', direction: 'asc' };
267
+ await el.updateComplete;
268
+
269
+ await el.fetchPage(2);
270
+
271
+ // If there is no change to the query or sort param during the fetch, the results
272
+ // should be read.
273
+ expect(resultsSpy.callCount).to.be.greaterThanOrEqual(1);
274
+ });
275
+
276
+ it('discards obsolete search results if sort params changed before arrival', async () => {
277
+ const resultsSpy = sinon.spy();
278
+ const searchService = new MockSearchService({
279
+ asyncResponse: true,
280
+ resultsSpy,
281
+ });
282
+
283
+ const el = await fixture<CollectionBrowser>(
284
+ html`<collection-browser .searchService=${searchService}>
285
+ </collection-browser>`
286
+ );
287
+
288
+ el.baseQuery = 'with-sort';
289
+ el.sortParam = { field: 'foo', direction: 'asc' };
290
+ await el.updateComplete;
291
+
292
+ const fetchPromise = el.fetchPage(2);
293
+ el.sortParam = { field: 'foo', direction: 'desc' };
294
+ await fetchPromise;
295
+
296
+ // If the different sort param causes the results to be discarded,
297
+ // the results array should never be read.
298
+ expect(resultsSpy.callCount).to.equal(0);
299
+ });
300
+
301
+ it('discards obsolete search results if sort param added before arrival', async () => {
302
+ const resultsSpy = sinon.spy();
303
+ const searchService = new MockSearchService({
304
+ asyncResponse: true,
305
+ resultsSpy,
306
+ });
307
+
308
+ const el = await fixture<CollectionBrowser>(
309
+ html`<collection-browser .searchService=${searchService}>
310
+ </collection-browser>`
311
+ );
312
+
313
+ el.baseQuery = 'single-result';
314
+ await el.updateComplete;
315
+
316
+ const fetchPromise = el.fetchPage(2);
317
+ el.sortParam = { field: 'foo', direction: 'asc' };
318
+ await fetchPromise;
319
+
320
+ // If the different sort param causes the results to be discarded,
321
+ // the results array should never be read.
322
+ expect(resultsSpy.callCount).to.equal(0);
323
+ });
324
+
325
+ it('discards obsolete search results if sort param cleared before arrival', async () => {
326
+ const resultsSpy = sinon.spy();
327
+ const searchService = new MockSearchService({
328
+ asyncResponse: true,
329
+ resultsSpy,
330
+ });
331
+
332
+ const el = await fixture<CollectionBrowser>(
333
+ html`<collection-browser .searchService=${searchService}>
334
+ </collection-browser>`
335
+ );
336
+
337
+ el.baseQuery = 'with-sort';
338
+ await el.updateComplete;
339
+
340
+ const fetchPromise = el.fetchPage(2);
341
+ el.sortParam = null;
342
+ await fetchPromise;
343
+
344
+ // If the different sort param causes the results to be discarded,
345
+ // the results array should never be read.
346
+ expect(resultsSpy.callCount).to.equal(0);
347
+ });
348
+
349
+ it('sets sort properties when user changes sort', async () => {
350
+ const el = await fixture<CollectionBrowser>(
351
+ html`<collection-browser></collection-browser>`
352
+ );
353
+
354
+ expect(el.selectedSort).to.equal(SortField.relevance);
355
+
356
+ el.baseQuery = 'foo';
357
+ await el.updateComplete;
358
+
359
+ const sortBar = el.shadowRoot?.querySelector('sort-filter-bar');
360
+ const sortSelector = sortBar?.shadowRoot?.querySelector(
361
+ '#desktop-sort-selector'
362
+ );
363
+ expect(sortSelector).to.exist;
364
+
365
+ // Click the title sorter
366
+ [...(sortSelector?.children as HTMLCollection & Iterable<any>)] // tsc doesn't know children is iterable
367
+ .find(child => child.textContent?.trim() === 'Title')
368
+ ?.querySelector('a[href]')
369
+ ?.click();
370
+
371
+ await el.updateComplete;
372
+
373
+ expect(el.selectedSort).to.equal(SortField.title);
374
+ });
375
+
376
+ it('scrolls to page', async () => {
377
+ const el = await fixture<CollectionBrowser>(
378
+ html`<collection-browser></collection-browser>`
379
+ );
380
+
381
+ const infiniteScroller = el.shadowRoot?.querySelector(
382
+ 'infinite-scroller'
383
+ ) as InfiniteScroller;
384
+ expect(infiniteScroller).to.exist;
385
+
386
+ const oldScrollToCell = infiniteScroller.scrollToCell;
387
+ const spy = sinon.spy();
388
+ infiniteScroller.scrollToCell = spy;
389
+
390
+ el.goToPage(1);
391
+
392
+ // Give it a second to scroll
393
+ await new Promise(res => {
394
+ setTimeout(res, 1000);
395
+ });
396
+
397
+ expect(spy.callCount).to.equal(1);
398
+
399
+ infiniteScroller.scrollToCell = oldScrollToCell;
400
+ });
401
+
402
+ it('refreshes when certain properties change - with some analytics event sampling', async () => {
403
+ const mockAnalyticsHandler = new MockAnalyticsHandler();
404
+ const searchService = new MockSearchService();
405
+ const collectionNameCache = new MockCollectionNameCache();
406
+ const el = await fixture<CollectionBrowser>(
407
+ html`<collection-browser
408
+ .analyticsHandler=${mockAnalyticsHandler}
409
+ .searchService=${searchService}
410
+ .collectionNameCache=${collectionNameCache}
411
+ ></collection-browser>`
412
+ );
413
+ const infiniteScrollerRefreshSpy = sinon.spy();
414
+
415
+ const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
416
+ (infiniteScroller as InfiniteScroller).reload = infiniteScrollerRefreshSpy;
417
+ expect(infiniteScrollerRefreshSpy.called).to.be.false;
418
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(0);
419
+
420
+ // testing: `loggedIn`
421
+ el.loggedIn = true;
422
+ await el.updateComplete;
423
+ expect(infiniteScrollerRefreshSpy.called).to.be.true;
424
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(1);
425
+
426
+ el.loggedIn = false;
427
+ await el.updateComplete;
428
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(2);
429
+
430
+ // testing: `displayMode`
431
+ el.displayMode = 'list-compact';
432
+ el.searchContext = 'beta-search';
433
+ await el.updateComplete;
434
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(3);
435
+
436
+ expect(mockAnalyticsHandler.callCategory).to.equal('beta-search');
437
+ expect(mockAnalyticsHandler.callAction).to.equal('displayMode');
438
+ expect(mockAnalyticsHandler.callLabel).to.equal('list-compact');
439
+
440
+ el.displayMode = 'list-detail';
441
+ await el.updateComplete;
442
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(4);
443
+
444
+ expect(mockAnalyticsHandler.callCategory).to.equal('beta-search');
445
+ expect(mockAnalyticsHandler.callAction).to.equal('displayMode');
446
+ expect(mockAnalyticsHandler.callLabel).to.equal('list-detail');
447
+
448
+ // testing: `baseNavigationUrl`
449
+ el.baseNavigationUrl = 'https://funtestsite.com';
450
+ await el.updateComplete;
451
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(5);
452
+
453
+ // testing: `baseImageUrl`
454
+ el.baseImageUrl = 'https://funtestsiteforimages.com';
455
+ await el.updateComplete;
456
+ expect(infiniteScrollerRefreshSpy.callCount).to.equal(6);
457
+ });
458
+
459
+ it('query the search service for single result', async () => {
460
+ const searchService = new MockSearchService();
461
+
462
+ const el = await fixture<CollectionBrowser>(
463
+ html`<collection-browser .searchService=${searchService}>
464
+ </collection-browser>`
465
+ );
466
+
467
+ el.baseQuery = 'single-result';
468
+ await el.updateComplete;
469
+
470
+ expect(
471
+ el.shadowRoot?.querySelector('#big-results-label')?.textContent
472
+ ).to.contains('Result');
473
+ });
474
+
475
+ it('`searchContext` prop helps describe where component is being used', async () => {
476
+ const el = await fixture<CollectionBrowser>(
477
+ html`<collection-browser></collection-browser>`
478
+ );
479
+
480
+ expect(el.searchContext).to.equal(analyticsCategories.default);
481
+
482
+ el.searchContext = 'unicorn-search';
483
+ await el.updateComplete;
484
+
485
+ expect(el.searchContext).to.equal('unicorn-search');
486
+
487
+ // property is reflected as attribute
488
+ expect(el.getAttribute('searchcontext')).to.equal('unicorn-search');
489
+ });
490
+ });