@thepalaceproject/circulation-admin 1.43.0 → 1.44.0-post.4

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 (133) hide show
  1. package/CLAUDE.md +28 -7
  2. package/README.md +11 -5
  3. package/dist/circulation-admin.js +1 -1
  4. package/eslint.config.mjs +9 -1
  5. package/jest.config.js +22 -8
  6. package/package.json +6 -20
  7. package/tests/jest/actions.test.ts +962 -0
  8. package/tests/jest/components/AccountPage.test.tsx +41 -0
  9. package/tests/jest/components/AdvancedSearchBooleanFilter.test.tsx +231 -0
  10. package/tests/jest/components/AdvancedSearchBuilder.test.tsx +93 -20
  11. package/tests/jest/components/AdvancedSearchFilter.test.tsx +142 -0
  12. package/tests/jest/components/AdvancedSearchFilterInput.test.tsx +212 -0
  13. package/tests/jest/components/AdvancedSearchFilterViewer.test.tsx +52 -0
  14. package/tests/jest/components/AdvancedSearchValueFilter.test.tsx +123 -0
  15. package/tests/jest/components/Announcement.test.tsx +76 -0
  16. package/tests/jest/components/AnnouncementForm.test.tsx +229 -0
  17. package/tests/jest/components/AnnouncementsSection.test.tsx +146 -0
  18. package/tests/jest/components/Autocomplete.test.tsx +67 -0
  19. package/tests/jest/components/BookCoverEditor.test.tsx +393 -0
  20. package/tests/jest/components/BookDetails.test.tsx +133 -0
  21. package/tests/jest/components/BookDetailsContainer.test.tsx +116 -0
  22. package/tests/jest/components/BookDetailsEditor.test.tsx +275 -0
  23. package/tests/jest/components/BookDetailsTabContainer.test.tsx +237 -0
  24. package/tests/jest/components/BookEditForm.test.tsx +352 -0
  25. package/tests/jest/components/BookEditor.test.tsx +20 -21
  26. package/tests/jest/components/CatalogPage.test.tsx +158 -0
  27. package/tests/jest/components/CatalogServices.test.tsx +100 -0
  28. package/tests/jest/components/ChangePasswordForm.test.tsx +163 -0
  29. package/tests/jest/components/CirculationEventsDownloadForm.test.tsx +41 -0
  30. package/tests/jest/components/Classifications.test.tsx +166 -0
  31. package/tests/jest/components/ClassificationsForm.test.tsx +458 -0
  32. package/tests/jest/components/ClassificationsTable.test.tsx +57 -0
  33. package/tests/jest/components/Collections.test.tsx +335 -7
  34. package/tests/jest/components/ColorPicker.test.tsx +58 -0
  35. package/tests/jest/components/ComplaintForm.test.tsx +171 -0
  36. package/tests/jest/components/Complaints.test.tsx +259 -0
  37. package/tests/jest/components/ConfigPage.test.tsx +58 -0
  38. package/tests/jest/components/ConfigTabContainer.test.tsx +196 -0
  39. package/tests/jest/components/ContextProvider.test.tsx +138 -0
  40. package/tests/jest/components/Contributors.test.tsx +157 -0
  41. package/tests/jest/components/CustomListEditor.test.tsx +367 -0
  42. package/tests/jest/components/CustomListEntriesEditor.test.tsx +1240 -0
  43. package/tests/jest/components/CustomListPage.test.tsx +57 -0
  44. package/tests/jest/components/CustomListSearch.test.tsx +275 -0
  45. package/tests/jest/components/CustomLists.test.tsx +621 -4
  46. package/tests/jest/components/CustomListsForBook.test.tsx +353 -0
  47. package/tests/jest/components/CustomListsSidebar.test.tsx +251 -0
  48. package/tests/jest/components/DashboardPage.test.tsx +76 -0
  49. package/tests/jest/components/DebugAuthentication.test.tsx +1 -5
  50. package/tests/jest/components/DiagnosticsServiceTabs.test.tsx +141 -0
  51. package/tests/jest/components/DiagnosticsServiceType.test.tsx +75 -0
  52. package/tests/jest/components/DiagnosticsTabContainer.test.tsx +147 -0
  53. package/tests/jest/components/DiscoveryServices.test.tsx +154 -7
  54. package/tests/jest/components/EditableConfigList.test.tsx +606 -9
  55. package/tests/jest/components/EditableInput.test.tsx +250 -1
  56. package/tests/jest/components/EditorField.test.tsx +95 -0
  57. package/tests/jest/components/EntryPointsContainer.test.tsx +97 -0
  58. package/tests/jest/components/EntryPointsTabs.test.tsx +88 -0
  59. package/tests/jest/components/ErrorMessage.test.tsx +97 -0
  60. package/tests/jest/components/Footer.test.tsx +141 -0
  61. package/tests/jest/components/GenreForm.test.tsx +152 -0
  62. package/tests/jest/components/Header.test.tsx +421 -0
  63. package/tests/jest/components/IndividualAdminEditForm.test.tsx +506 -1
  64. package/tests/jest/components/IndividualAdmins.test.tsx +124 -8
  65. package/tests/jest/components/InputList.test.tsx +493 -0
  66. package/tests/jest/components/InventoryReportRequestModal.test.tsx +16 -42
  67. package/tests/jest/components/JsonField.test.tsx +20 -0
  68. package/tests/jest/components/Lane.test.tsx +132 -10
  69. package/tests/jest/components/LaneCustomListsEditor.test.tsx +450 -0
  70. package/tests/jest/components/LaneEditor.test.tsx +377 -13
  71. package/tests/jest/components/LanePage.test.tsx +68 -0
  72. package/tests/jest/components/Lanes.test.tsx +446 -0
  73. package/tests/jest/components/LanesSidebar.test.tsx +621 -0
  74. package/tests/jest/components/LanguageField.test.tsx +40 -0
  75. package/tests/jest/components/Libraries.test.tsx +48 -0
  76. package/tests/jest/components/LibraryEditForm.test.tsx +383 -0
  77. package/tests/jest/components/LibraryRegistration.test.tsx +354 -0
  78. package/tests/jest/components/LibraryRegistrationForm.test.tsx +203 -0
  79. package/tests/jest/components/LoadButton.test.tsx +49 -0
  80. package/tests/jest/components/ManagePatrons.test.tsx +73 -0
  81. package/tests/jest/components/ManagePatronsForm.test.tsx +180 -0
  82. package/tests/jest/components/ManagePatronsTabContainer.test.tsx +143 -0
  83. package/tests/jest/components/MetadataServices.test.tsx +95 -0
  84. package/tests/jest/components/NeighborhoodAnalyticsForm.test.tsx +167 -0
  85. package/tests/jest/components/PairedMenus.test.tsx +220 -0
  86. package/tests/jest/components/PatronAuthServices.test.tsx +114 -0
  87. package/tests/jest/components/PatronBlockingRulesEditor.test.tsx +3 -1
  88. package/tests/jest/components/PatronInfo.test.tsx +54 -0
  89. package/tests/jest/components/ProtocolFormField.test.tsx +479 -7
  90. package/tests/jest/components/ResetAdobeId.test.tsx +302 -0
  91. package/tests/jest/components/SaveButton.test.tsx +47 -0
  92. package/tests/jest/components/SelfTestResult.test.tsx +164 -0
  93. package/tests/jest/components/SelfTests.test.tsx +601 -0
  94. package/tests/jest/components/SelfTestsCategory.test.tsx +200 -0
  95. package/tests/jest/components/SelfTestsTabContainer.test.tsx +216 -0
  96. package/tests/jest/components/ServiceEditForm.test.tsx +1092 -0
  97. package/tests/jest/components/ServiceWithRegistrationsEditForm.test.tsx +110 -0
  98. package/tests/jest/components/SetupPage.test.tsx +41 -0
  99. package/tests/jest/components/SingleStatListItem.test.tsx +62 -0
  100. package/tests/jest/components/SitewideAnnouncements.test.tsx +134 -0
  101. package/tests/jest/components/Stats.test.tsx +4 -15
  102. package/tests/jest/components/TabContainer.test.tsx +68 -0
  103. package/tests/jest/components/TextWithEditMode.test.tsx +218 -0
  104. package/tests/jest/components/Timestamp.test.tsx +74 -0
  105. package/tests/jest/components/ToolTip.test.tsx +46 -0
  106. package/tests/jest/components/TroubleshootingCategoryPage.test.tsx +69 -0
  107. package/tests/jest/components/TroubleshootingPage.test.tsx +94 -0
  108. package/tests/jest/components/TroubleshootingTabContainer.test.tsx +68 -0
  109. package/tests/jest/components/UpdatingLoader.test.tsx +36 -0
  110. package/tests/jest/components/WelcomePage.test.tsx +43 -0
  111. package/tests/jest/components/WithEditButton.test.tsx +55 -0
  112. package/tests/jest/components/WithRemoveButton.test.tsx +95 -0
  113. package/tests/jest/editorAdapter.test.ts +245 -0
  114. package/tests/jest/features/book.test.ts +75 -80
  115. package/tests/jest/fixtures/classificationsData.ts +45 -0
  116. package/tests/jest/fixtures/genreData.ts +811 -0
  117. package/tests/jest/index.test.tsx +50 -0
  118. package/tests/jest/models/Admin.test.ts +206 -0
  119. package/tests/jest/reducers/bookCoverPreview.test.ts +81 -0
  120. package/tests/jest/reducers/classifications.test.ts +161 -0
  121. package/tests/jest/reducers/collections.test.ts +96 -0
  122. package/tests/jest/reducers/complaints.test.ts +166 -0
  123. package/tests/jest/reducers/createFetchEditReducer.test.ts +220 -0
  124. package/tests/jest/reducers/createRegisterLibraryReducer.test.ts +51 -0
  125. package/tests/jest/reducers/customListDetails.test.ts +120 -0
  126. package/tests/jest/reducers/customListEditor.test.ts +2823 -0
  127. package/tests/jest/reducers/managePatrons.test.ts +71 -0
  128. package/tests/jest/testUtils/formDataShim.test.ts +135 -0
  129. package/tests/jest/testUtils/formDataShim.ts +112 -0
  130. package/tests/jest/utils/sharedFunctions.test.ts +121 -0
  131. package/tsconfig.json +3 -4
  132. package/testReporter.js +0 -29
  133. package/tests/jest/README.md +0 -6
@@ -0,0 +1,2823 @@
1
+ import reducer, {
2
+ getCustomListEditorFormData,
3
+ getCustomListEditorSearchUrl,
4
+ initialState,
5
+ } from "../../../src/reducers/customListEditor";
6
+
7
+ import ActionCreator from "../../../src/actions";
8
+
9
+ describe("custom list editor reducer", () => {
10
+ describe("on SET_FEATURE_FLAGS", () => {
11
+ it("sets isAutoUpdateEnabled to true if the enableAutoList feature flag is true", () => {
12
+ const state = {
13
+ ...initialState,
14
+ isAutoUpdateEnabled: false,
15
+ };
16
+
17
+ const nextState = reducer(state, {
18
+ type: ActionCreator.SET_FEATURE_FLAGS,
19
+ value: {
20
+ enableSomethingElse: false,
21
+ enableAutoList: true,
22
+ },
23
+ });
24
+
25
+ expect(nextState.isAutoUpdateEnabled).toBe(true);
26
+ });
27
+
28
+ it("sets isAutoUpdateEnabled to false if the enableAutoList feature flag is false", () => {
29
+ const state = {
30
+ ...initialState,
31
+ isAutoUpdateEnabled: true,
32
+ };
33
+
34
+ const nextState = reducer(state, {
35
+ type: ActionCreator.SET_FEATURE_FLAGS,
36
+ value: {
37
+ enableSomethingElse: false,
38
+ enableAutoList: false,
39
+ },
40
+ });
41
+
42
+ expect(nextState.isAutoUpdateEnabled).toBe(false);
43
+ });
44
+
45
+ it("keeps isAutoUpdateEnabled at the current value if the enableAutoList feature flag is not present", () => {
46
+ const state = {
47
+ ...initialState,
48
+ isAutoUpdateEnabled: true,
49
+ };
50
+
51
+ const nextState = reducer(state, {
52
+ type: ActionCreator.SET_FEATURE_FLAGS,
53
+ value: {
54
+ enableSomethingElse: true,
55
+ },
56
+ });
57
+
58
+ expect(nextState.isAutoUpdateEnabled).toBe(true);
59
+ });
60
+ });
61
+
62
+ describe("on UPDATE_FEATURE_FLAG", () => {
63
+ it("sets isAutoUpdateEnabled to true if the flag name is enableAutoList and the value is true", () => {
64
+ const state = {
65
+ ...initialState,
66
+ isAutoUpdateEnabled: false,
67
+ };
68
+
69
+ const nextState = reducer(state, {
70
+ type: ActionCreator.UPDATE_FEATURE_FLAG,
71
+ name: "enableAutoList",
72
+ value: true,
73
+ });
74
+
75
+ expect(nextState.isAutoUpdateEnabled).toBe(true);
76
+ });
77
+
78
+ it("sets isAutoUpdateEnabled to false if the flag name is enableAutoList and the value is false", () => {
79
+ const state = {
80
+ ...initialState,
81
+ isAutoUpdateEnabled: true,
82
+ };
83
+
84
+ const nextState = reducer(state, {
85
+ type: ActionCreator.UPDATE_FEATURE_FLAG,
86
+ name: "enableAutoList",
87
+ value: false,
88
+ });
89
+
90
+ expect(nextState.isAutoUpdateEnabled).toBe(false);
91
+ });
92
+
93
+ it("keeps isAutoUpdateEnabled at the current value if the flag name is not enableAutoList", () => {
94
+ const state = {
95
+ ...initialState,
96
+ isAutoUpdateEnabled: true,
97
+ };
98
+
99
+ const nextState = reducer(state, {
100
+ type: ActionCreator.UPDATE_FEATURE_FLAG,
101
+ name: "enableSomethingElse",
102
+ value: false,
103
+ });
104
+
105
+ expect(nextState.isAutoUpdateEnabled).toBe(true);
106
+ });
107
+ });
108
+
109
+ describe("on OPEN_CUSTOM_LIST_EDITOR", () => {
110
+ const state = undefined;
111
+
112
+ const listData = {
113
+ custom_lists: [
114
+ {
115
+ collections: [
116
+ {
117
+ id: 16,
118
+ name: "TEST Baker & Taylor",
119
+ protocol: "Axis 360",
120
+ },
121
+ ],
122
+ entry_count: 150,
123
+ id: 17,
124
+ name: "Baker & Taylor Axis360 Test",
125
+ },
126
+ {
127
+ collections: [],
128
+ entry_count: 15,
129
+ id: 12,
130
+ name: "Cooking",
131
+ },
132
+ {
133
+ collections: [],
134
+ entry_count: 16,
135
+ id: 19,
136
+ name: "LCP PDF Test",
137
+ },
138
+ ],
139
+ };
140
+
141
+ it("sets the id, and obtains the name, collections, and baselineTotalCount from the list data", () => {
142
+ const nextState = reducer(state, {
143
+ type: ActionCreator.OPEN_CUSTOM_LIST_EDITOR,
144
+ id: "17",
145
+ data: listData,
146
+ });
147
+
148
+ expect(nextState.id).toBe(17);
149
+ expect(nextState.entries.baselineTotalCount).toBe(150);
150
+ expect(nextState.properties.current).toStrictEqual(
151
+ nextState.properties.baseline
152
+ );
153
+
154
+ expect(nextState.properties.baseline).toStrictEqual({
155
+ name: "Baker & Taylor Axis360 Test",
156
+ collections: [16],
157
+ autoUpdate: false,
158
+ });
159
+
160
+ expect(nextState.error).toBe(null);
161
+ });
162
+
163
+ it("sets an error message when no list with the id in the action exists in the data", () => {
164
+ const nextState = reducer(state, {
165
+ type: ActionCreator.OPEN_CUSTOM_LIST_EDITOR,
166
+ id: "999",
167
+ data: listData,
168
+ });
169
+
170
+ expect(nextState.id).toBe(999);
171
+ expect(nextState.error).toBe("Custom list not found for ID: 999");
172
+ });
173
+
174
+ it("sets the id to null when the id in the action is null", () => {
175
+ const nextState = reducer(state, {
176
+ type: ActionCreator.OPEN_CUSTOM_LIST_EDITOR,
177
+ id: null,
178
+ data: listData,
179
+ });
180
+
181
+ expect(nextState.id).toBe(null);
182
+ expect(nextState.error).toBe(null);
183
+ });
184
+ });
185
+
186
+ describe(`on ${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`, () => {
187
+ const listData = {
188
+ custom_lists: [
189
+ {
190
+ collections: [
191
+ {
192
+ id: 16,
193
+ name: "TEST Baker & Taylor",
194
+ protocol: "Axis 360",
195
+ },
196
+ ],
197
+ entry_count: 150,
198
+ id: 17,
199
+ name: "Baker & Taylor Axis360 Test",
200
+ },
201
+ {
202
+ collections: [],
203
+ entry_count: 15,
204
+ id: 12,
205
+ name: "Cooking",
206
+ },
207
+ {
208
+ collections: [
209
+ {
210
+ id: 14,
211
+ name: "New BiblioBoard Test",
212
+ protocol: "OPDS for Distributors",
213
+ },
214
+ ],
215
+ entry_count: 13337,
216
+ id: 18,
217
+ is_owner: true,
218
+ is_shared: false,
219
+ name: "New BiblioBoard",
220
+ },
221
+ {
222
+ collections: [],
223
+ id: 31,
224
+ name: "Auto Updating List",
225
+ auto_update: true,
226
+ auto_update_query:
227
+ '{"query":{"and":[{"and":[{"or":[{"key":"genre","value":"Horror"},{"key":"genre","value":"Fantasy"}]},{"key":"language","value":"eng"},{"key":"classification","value":"mystery"}]},{"not":[{"or":[{"key":"author","op":"contains","value":"bracken"},{"key":"title","value":"wicked appetite"}]}]}]}}',
228
+ },
229
+ {
230
+ collections: [],
231
+ id: 42,
232
+ name: "Another Auto Updating List",
233
+ auto_update: true,
234
+ auto_update_facets: '{"media":"Audio","order":"title"}',
235
+ },
236
+ ],
237
+ };
238
+
239
+ it("obtains the name, ownership flag, sharing flag, collections, and baselineTotalCount from the list data for the current id", () => {
240
+ const state = {
241
+ ...initialState,
242
+ id: 18,
243
+ };
244
+
245
+ const nextState = reducer(state, {
246
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
247
+ data: listData,
248
+ });
249
+
250
+ expect(nextState.id).toBe(18);
251
+ expect(nextState.isOwner).toBe(true);
252
+ expect(nextState.isShared).toBe(false);
253
+ expect(nextState.entries.baselineTotalCount).toBe(13337);
254
+ expect(nextState.properties.current).toStrictEqual(
255
+ nextState.properties.baseline
256
+ );
257
+
258
+ expect(nextState.properties.baseline).toStrictEqual({
259
+ name: "New BiblioBoard",
260
+ collections: [14],
261
+ autoUpdate: false,
262
+ });
263
+
264
+ expect(nextState.error).toBe(null);
265
+ });
266
+
267
+ it("sets isLoaded to true when a list with the current id exists in the data", () => {
268
+ const state = {
269
+ ...initialState,
270
+ id: 18,
271
+ };
272
+
273
+ const nextState = reducer(state, {
274
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
275
+ data: listData,
276
+ });
277
+
278
+ expect(nextState.isLoaded).toBe(true);
279
+ });
280
+
281
+ it("sets an error message when no list with the current id exists in the data", () => {
282
+ const state = {
283
+ ...initialState,
284
+ id: 999,
285
+ };
286
+
287
+ const nextState = reducer(state, {
288
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
289
+ data: listData,
290
+ });
291
+
292
+ expect(nextState.error).toBe("Custom list not found for ID: 999");
293
+ });
294
+
295
+ it("updates the advanced search builders when there is a saved search query", () => {
296
+ const state = {
297
+ ...initialState,
298
+ id: 31,
299
+ };
300
+
301
+ const nextState = reducer(state, {
302
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
303
+ data: listData,
304
+ });
305
+
306
+ expect(
307
+ nextState.searchParams.current.advanced.include.query
308
+ ).toStrictEqual({
309
+ id: "1",
310
+ and: [
311
+ {
312
+ id: "2",
313
+ or: [
314
+ {
315
+ id: "3",
316
+ key: "genre",
317
+ op: "eq",
318
+ value: "Horror",
319
+ },
320
+ {
321
+ id: "4",
322
+ key: "genre",
323
+ op: "eq",
324
+ value: "Fantasy",
325
+ },
326
+ ],
327
+ },
328
+ {
329
+ id: "5",
330
+ key: "language",
331
+ op: "eq",
332
+ value: "eng",
333
+ },
334
+ {
335
+ id: "6",
336
+ key: "classification",
337
+ op: "eq",
338
+ value: "mystery",
339
+ },
340
+ ],
341
+ });
342
+
343
+ expect(
344
+ nextState.searchParams.current.advanced.exclude.query
345
+ ).toStrictEqual({
346
+ id: "8",
347
+ or: [
348
+ {
349
+ id: "9",
350
+ key: "author",
351
+ op: "contains",
352
+ value: "bracken",
353
+ },
354
+ {
355
+ id: "10",
356
+ key: "title",
357
+ op: "eq",
358
+ value: "wicked appetite",
359
+ },
360
+ ],
361
+ });
362
+ });
363
+
364
+ it("updates the search params when there are saved search facets", () => {
365
+ const state = {
366
+ ...initialState,
367
+ id: 42,
368
+ };
369
+
370
+ const nextState = reducer(state, {
371
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
372
+ data: listData,
373
+ });
374
+
375
+ expect(nextState.searchParams.current.entryPoint).toBe("Audio");
376
+ expect(nextState.searchParams.current.sort).toBe("title");
377
+ });
378
+
379
+ it("ignores the action if its isAfterShare property is true", () => {
380
+ const state = {
381
+ ...initialState,
382
+ id: 18,
383
+ };
384
+
385
+ const nextState = reducer(state, {
386
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
387
+ data: listData,
388
+ isAfterShare: true,
389
+ });
390
+
391
+ expect(nextState).toBe(state);
392
+ });
393
+
394
+ it("sets isSearchModified and isModified to false", () => {
395
+ const state = {
396
+ ...initialState,
397
+ id: 42,
398
+ isSearchModified: true,
399
+ isModified: true,
400
+ };
401
+
402
+ const nextState = reducer(state, {
403
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
404
+ data: listData,
405
+ });
406
+
407
+ expect(nextState.isSearchModified).toBe(false);
408
+ expect(nextState.isModified).toBe(false);
409
+ });
410
+
411
+ describe("when auto update is enabled", () => {
412
+ it("defaults the autoUpdate property to true for a new list", () => {
413
+ const state = {
414
+ ...initialState,
415
+ isAutoUpdateEnabled: true,
416
+ };
417
+
418
+ const nextState = reducer(state, {
419
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
420
+ data: listData,
421
+ });
422
+
423
+ expect(nextState.properties.current.autoUpdate).toBe(true);
424
+ });
425
+
426
+ it("sets the autoUpdate property to true if the auto_update setting in the data is true", () => {
427
+ const state = {
428
+ ...initialState,
429
+ id: 31,
430
+ isAutoUpdateEnabled: true,
431
+ };
432
+
433
+ const nextState = reducer(state, {
434
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
435
+ data: listData,
436
+ });
437
+
438
+ expect(nextState.properties.current.autoUpdate).toBe(true);
439
+ });
440
+
441
+ it("sets the autoUpdate property to false if the auto_update setting in the data is not present", () => {
442
+ const state = {
443
+ ...initialState,
444
+ id: 12,
445
+ isAutoUpdateEnabled: true,
446
+ };
447
+
448
+ const nextState = reducer(state, {
449
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
450
+ data: listData,
451
+ });
452
+
453
+ expect(nextState.properties.current.autoUpdate).toBe(false);
454
+ });
455
+ });
456
+
457
+ describe("when auto update is disabled", () => {
458
+ it("defaults the autoUpdate property to false for a new list", () => {
459
+ const state = {
460
+ ...initialState,
461
+ };
462
+
463
+ const nextState = reducer(state, {
464
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
465
+ data: listData,
466
+ });
467
+
468
+ expect(nextState.properties.current.autoUpdate).toBe(false);
469
+ });
470
+
471
+ it("sets the autoUpdate property to false if the auto_update setting in the data is not present", () => {
472
+ const state = {
473
+ ...initialState,
474
+ id: 16,
475
+ };
476
+
477
+ const nextState = reducer(state, {
478
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
479
+ data: listData,
480
+ });
481
+
482
+ expect(nextState.properties.current.autoUpdate).toBe(false);
483
+ });
484
+
485
+ it("sets the autoUpdate property to false even if the list data has auto_update set to true", () => {
486
+ const state = {
487
+ ...initialState,
488
+ id: 31,
489
+ };
490
+
491
+ const nextState = reducer(state, {
492
+ type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
493
+ data: listData,
494
+ });
495
+
496
+ expect(nextState.properties.current.autoUpdate).toBe(false);
497
+ });
498
+ });
499
+ });
500
+
501
+ describe(`on ${ActionCreator.CUSTOM_LIST_DETAILS}_${ActionCreator.LOAD}`, () => {
502
+ const listDetailsData = {
503
+ books: [
504
+ { id: "book1", title: "A Farewell to Arms" },
505
+ { id: "book2", title: "Little Women" },
506
+ ],
507
+ };
508
+
509
+ it("updates the baseline entries with the books in the list details data", () => {
510
+ const state = {
511
+ ...initialState,
512
+ };
513
+
514
+ const nextState = reducer(state, {
515
+ type: `${ActionCreator.CUSTOM_LIST_DETAILS}_${ActionCreator.LOAD}`,
516
+ data: listDetailsData,
517
+ });
518
+
519
+ expect(nextState.entries.baseline).toStrictEqual(listDetailsData.books);
520
+ });
521
+
522
+ it("cleans up local changes, since the server already got them on save", () => {
523
+ const state = {
524
+ ...initialState,
525
+ entries: {
526
+ ...initialState.entries,
527
+ // It doesn't really matter what the added/removed books are, in
528
+ // this case, just that there is something there for the reducer
529
+ // to clean up.
530
+ added: {
531
+ // An already saved added book.
532
+ book1: { id: "book1", title: "A Farewell to Arms" },
533
+ },
534
+ removed: {
535
+ // An already saved removed book.
536
+ an_already_removed_book: true as const,
537
+ },
538
+ },
539
+ };
540
+
541
+ const nextState = reducer(state, {
542
+ type: `${ActionCreator.CUSTOM_LIST_DETAILS}_${ActionCreator.LOAD}`,
543
+ data: listDetailsData,
544
+ });
545
+
546
+ expect(nextState.entries.added).toStrictEqual({});
547
+ expect(nextState.entries.removed).toStrictEqual({});
548
+
549
+ expect(nextState.entries.baseline).toStrictEqual(listDetailsData.books);
550
+ expect(nextState.entries.current).toStrictEqual(listDetailsData.books);
551
+ expect(nextState.entries.currentTotalCount).toBe(2);
552
+ });
553
+ });
554
+
555
+ describe(`on ${ActionCreator.CUSTOM_LIST_DETAILS_MORE}_${ActionCreator.LOAD}`, () => {
556
+ const listDetailsData = {
557
+ books: [
558
+ { id: "book1", title: "A Farewell to Arms" },
559
+ { id: "book2", title: "Little Women" },
560
+ ],
561
+ };
562
+
563
+ it("appends the books in the list details data to the baseline entries", () => {
564
+ const state = {
565
+ ...initialState,
566
+ entries: {
567
+ ...initialState.entries,
568
+ baseline: [
569
+ { id: "book91", title: "Huckleberry Finn" },
570
+ { id: "book90", title: "Wuthering Heights" },
571
+ ],
572
+ },
573
+ };
574
+
575
+ const nextState = reducer(state, {
576
+ type: `${ActionCreator.CUSTOM_LIST_DETAILS_MORE}_${ActionCreator.LOAD}`,
577
+ data: listDetailsData,
578
+ });
579
+
580
+ expect(nextState.entries.baseline).toStrictEqual([
581
+ { id: "book91", title: "Huckleberry Finn" },
582
+ { id: "book90", title: "Wuthering Heights" },
583
+ { id: "book1", title: "A Farewell to Arms" },
584
+ { id: "book2", title: "Little Women" },
585
+ ]);
586
+ });
587
+
588
+ it("applies the current delta to the new baseline entries", () => {
589
+ const state = {
590
+ ...initialState,
591
+ entries: {
592
+ ...initialState.entries,
593
+ baseline: [
594
+ { id: "book91", title: "Huckleberry Finn" },
595
+ { id: "book90", title: "Wuthering Heights" },
596
+ ],
597
+ baselineTotalCount: 4,
598
+ added: {
599
+ book98: { id: "book98", title: "The Bell Jar" },
600
+ },
601
+ removed: {
602
+ book1: true as const,
603
+ book90: true as const,
604
+ },
605
+ },
606
+ };
607
+
608
+ const nextState = reducer(state, {
609
+ type: `${ActionCreator.CUSTOM_LIST_DETAILS_MORE}_${ActionCreator.LOAD}`,
610
+ data: listDetailsData,
611
+ });
612
+
613
+ expect(nextState.entries.current).toStrictEqual([
614
+ { id: "book98", title: "The Bell Jar" },
615
+ { id: "book91", title: "Huckleberry Finn" },
616
+ { id: "book2", title: "Little Women" },
617
+ ]);
618
+
619
+ expect(nextState.entries.currentTotalCount).toBe(3); // 4 + 1 - 2
620
+ });
621
+ });
622
+
623
+ describe("on UPDATE_CUSTOM_LIST_EDITOR_PROPERTY", () => {
624
+ const state = {
625
+ ...initialState,
626
+ };
627
+
628
+ it("updates the current properties with the name/value", () => {
629
+ const nextState = reducer(state, {
630
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_PROPERTY,
631
+ name: "name",
632
+ value: "Awesome List",
633
+ });
634
+
635
+ expect(nextState.properties.current.name).toBe("Awesome List");
636
+ });
637
+
638
+ it("updates isValid and isModified", () => {
639
+ let nextState;
640
+
641
+ nextState = reducer(state, {
642
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_PROPERTY,
643
+ name: "name",
644
+ value: "Awesome List",
645
+ });
646
+
647
+ expect(nextState.isModified).toBe(true);
648
+ expect(nextState.isValid).toBe(false);
649
+
650
+ nextState = reducer(nextState, {
651
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_PROPERTY,
652
+ name: "collections",
653
+ value: [12],
654
+ });
655
+
656
+ expect(nextState.isModified).toBe(true);
657
+ expect(nextState.isValid).toBe(true);
658
+
659
+ nextState = reducer(nextState, {
660
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_PROPERTY,
661
+ name: "name",
662
+ value: "",
663
+ });
664
+
665
+ expect(nextState.isModified).toBe(true);
666
+ expect(nextState.isValid).toBe(false);
667
+
668
+ nextState = reducer(nextState, {
669
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_PROPERTY,
670
+ name: "collections",
671
+ value: [],
672
+ });
673
+
674
+ expect(nextState.isModified).toBe(false);
675
+ expect(nextState.isValid).toBe(false);
676
+
677
+ nextState = reducer(state, {
678
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_PROPERTY,
679
+ name: "autoUpdate",
680
+ value: true,
681
+ });
682
+
683
+ expect(nextState.isModified).toBe(true);
684
+ expect(nextState.isValid).toBe(false);
685
+ });
686
+ });
687
+
688
+ describe("on TOGGLE_CUSTOM_LIST_EDITOR_COLLECTION", () => {
689
+ it("adds the id to the current collection property if it doesn't exist", () => {
690
+ const state = {
691
+ ...initialState,
692
+ };
693
+
694
+ const nextState = reducer(state, {
695
+ type: ActionCreator.TOGGLE_CUSTOM_LIST_EDITOR_COLLECTION,
696
+ id: 13,
697
+ });
698
+
699
+ expect(nextState.properties.current.collections).toStrictEqual([13]);
700
+ });
701
+
702
+ it("removes the id from the current collection property if it exists", () => {
703
+ const state = {
704
+ ...initialState,
705
+ properties: {
706
+ ...initialState.properties,
707
+ current: {
708
+ ...initialState.properties.current,
709
+ collections: [10, 11, 12],
710
+ },
711
+ },
712
+ };
713
+
714
+ const nextState = reducer(state, {
715
+ type: ActionCreator.TOGGLE_CUSTOM_LIST_EDITOR_COLLECTION,
716
+ id: 11,
717
+ });
718
+
719
+ expect(nextState.properties.current.collections).toStrictEqual([10, 12]);
720
+ });
721
+
722
+ it("updates isValid and isModified", () => {
723
+ const state = {
724
+ ...initialState,
725
+ properties: {
726
+ ...initialState.properties,
727
+ current: {
728
+ ...initialState.properties.current,
729
+ name: "List 1",
730
+ collections: [],
731
+ },
732
+ },
733
+ isValid: false,
734
+ isModified: false,
735
+ };
736
+
737
+ const nextState = reducer(state, {
738
+ type: ActionCreator.TOGGLE_CUSTOM_LIST_EDITOR_COLLECTION,
739
+ id: 11,
740
+ });
741
+
742
+ expect(nextState.isValid).toBe(true);
743
+ expect(nextState.isModified).toBe(true);
744
+ });
745
+ });
746
+
747
+ describe("on UPDATE_CUSTOM_LIST_EDITOR_SEARCH_PARAM", () => {
748
+ const state = {
749
+ ...initialState,
750
+ properties: {
751
+ ...initialState.properties,
752
+ current: {
753
+ ...initialState.properties.current,
754
+ autoUpdate: true,
755
+ },
756
+ },
757
+ };
758
+
759
+ it("updates searchParams with the name/value", () => {
760
+ let nextState;
761
+
762
+ nextState = reducer(state, {
763
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_SEARCH_PARAM,
764
+ name: "entryPoint",
765
+ value: "Book",
766
+ });
767
+
768
+ expect(nextState.searchParams.current.entryPoint).toBe("Book");
769
+
770
+ nextState = reducer(state, {
771
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_SEARCH_PARAM,
772
+ name: "terms",
773
+ value: "foo bar",
774
+ });
775
+
776
+ expect(nextState.searchParams.current.terms).toBe("foo bar");
777
+
778
+ nextState = reducer(state, {
779
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_SEARCH_PARAM,
780
+ name: "sort",
781
+ value: "title",
782
+ });
783
+
784
+ expect(nextState.searchParams.current.sort).toBe("title");
785
+
786
+ nextState = reducer(state, {
787
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_SEARCH_PARAM,
788
+ name: "language",
789
+ value: "eng",
790
+ });
791
+
792
+ expect(nextState.searchParams.current.language).toBe("eng");
793
+ });
794
+
795
+ it("updates isValid, isModified, and isSearchModified", () => {
796
+ const nextState = reducer(state, {
797
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_SEARCH_PARAM,
798
+ name: "entryPoint",
799
+ value: "Book",
800
+ });
801
+
802
+ expect(nextState.isSearchModified).toBe(true);
803
+ expect(nextState.isModified).toBe(true);
804
+ expect(nextState.isValid).toBe(false);
805
+ });
806
+ });
807
+
808
+ describe("on ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY", () => {
809
+ const valueQuery = {
810
+ key: "title",
811
+ op: "contains",
812
+ value: "Frankenstein",
813
+ };
814
+
815
+ it("should add the query to the currently selected query", () => {
816
+ const state = {
817
+ ...initialState,
818
+ properties: {
819
+ ...initialState.properties,
820
+ current: {
821
+ ...initialState.properties.current,
822
+ autoUpdate: true,
823
+ },
824
+ },
825
+ searchParams: {
826
+ ...initialState.searchParams,
827
+ current: {
828
+ ...initialState.searchParams.current,
829
+ advanced: {
830
+ ...initialState.searchParams.current.advanced,
831
+ include: {
832
+ ...initialState.searchParams.current.advanced.include,
833
+ query: {
834
+ id: "90",
835
+ and: [
836
+ {
837
+ id: "91",
838
+ key: "title",
839
+ value: "foo",
840
+ },
841
+ {
842
+ id: "92",
843
+ key: "title",
844
+ value: "bar",
845
+ },
846
+ ],
847
+ },
848
+ selectedQueryId: "90",
849
+ },
850
+ },
851
+ },
852
+ },
853
+ };
854
+
855
+ const nextState = reducer(state, {
856
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
857
+ builderName: "include",
858
+ query: valueQuery,
859
+ });
860
+
861
+ expect(
862
+ nextState.searchParams.current.advanced.include.query
863
+ ).toStrictEqual({
864
+ id: "90",
865
+ and: [
866
+ {
867
+ id: "91",
868
+ key: "title",
869
+ value: "foo",
870
+ },
871
+ {
872
+ id: "92",
873
+ key: "title",
874
+ value: "bar",
875
+ },
876
+ {
877
+ id: "33",
878
+ ...valueQuery,
879
+ },
880
+ ],
881
+ });
882
+
883
+ expect(
884
+ nextState.searchParams.current.advanced.include.selectedQueryId
885
+ ).toBe("90");
886
+ });
887
+
888
+ it("should add the query as the root query and select it, if there is no existing root query", () => {
889
+ const state = {
890
+ ...initialState,
891
+ };
892
+
893
+ const nextState = reducer(state, {
894
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
895
+ builderName: "include",
896
+ query: valueQuery,
897
+ });
898
+
899
+ expect(
900
+ nextState.searchParams.current.advanced.include.query
901
+ ).toStrictEqual({
902
+ id: "34",
903
+ ...valueQuery,
904
+ });
905
+
906
+ expect(
907
+ nextState.searchParams.current.advanced.include.selectedQueryId
908
+ ).toBe("34");
909
+ });
910
+
911
+ it("should add the query to the root query, if there is no selected query", () => {
912
+ const state = {
913
+ ...initialState,
914
+ searchParams: {
915
+ ...initialState.searchParams,
916
+ current: {
917
+ ...initialState.searchParams.current,
918
+ advanced: {
919
+ ...initialState.searchParams.current.advanced,
920
+ include: {
921
+ ...initialState.searchParams.current.advanced.include,
922
+ query: {
923
+ id: "90",
924
+ and: [
925
+ {
926
+ id: "91",
927
+ key: "title",
928
+ value: "foo",
929
+ },
930
+ {
931
+ id: "92",
932
+ key: "title",
933
+ value: "bar",
934
+ },
935
+ ],
936
+ },
937
+ },
938
+ },
939
+ },
940
+ },
941
+ };
942
+
943
+ const nextState = reducer(state, {
944
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
945
+ builderName: "include",
946
+ query: valueQuery,
947
+ });
948
+
949
+ expect(
950
+ nextState.searchParams.current.advanced.include.query
951
+ ).toStrictEqual({
952
+ id: "90",
953
+ and: [
954
+ {
955
+ id: "91",
956
+ key: "title",
957
+ value: "foo",
958
+ },
959
+ {
960
+ id: "92",
961
+ key: "title",
962
+ value: "bar",
963
+ },
964
+ {
965
+ id: "35",
966
+ ...valueQuery,
967
+ },
968
+ ],
969
+ });
970
+
971
+ expect(
972
+ nextState.searchParams.current.advanced.include.selectedQueryId
973
+ ).toBe(null);
974
+ });
975
+
976
+ it("should create a boolean AND query if a new query is added to a non-boolean root query in the include builder", () => {
977
+ const state = {
978
+ ...initialState,
979
+ searchParams: {
980
+ ...initialState.searchParams,
981
+ current: {
982
+ ...initialState.searchParams.current,
983
+ advanced: {
984
+ ...initialState.searchParams.current.advanced,
985
+ include: {
986
+ ...initialState.searchParams.current.advanced.include,
987
+ query: {
988
+ id: "91",
989
+ key: "title",
990
+ value: "foo",
991
+ },
992
+ selectedQueryId: "91",
993
+ },
994
+ },
995
+ },
996
+ },
997
+ };
998
+
999
+ const nextState = reducer(state, {
1000
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1001
+ builderName: "include",
1002
+ query: valueQuery,
1003
+ });
1004
+
1005
+ expect(
1006
+ nextState.searchParams.current.advanced.include.query
1007
+ ).toStrictEqual({
1008
+ id: "91",
1009
+ and: [
1010
+ {
1011
+ id: "37",
1012
+ key: "title",
1013
+ value: "foo",
1014
+ },
1015
+ {
1016
+ id: "36",
1017
+ ...valueQuery,
1018
+ },
1019
+ ],
1020
+ });
1021
+
1022
+ expect(
1023
+ nextState.searchParams.current.advanced.include.selectedQueryId
1024
+ ).toBe("91");
1025
+ });
1026
+
1027
+ it("should create a boolean OR query if a new query is added to a non-boolean root query in the exclude builder", () => {
1028
+ const state = {
1029
+ ...initialState,
1030
+ searchParams: {
1031
+ ...initialState.searchParams,
1032
+ current: {
1033
+ ...initialState.searchParams.current,
1034
+ advanced: {
1035
+ ...initialState.searchParams.current.advanced,
1036
+ exclude: {
1037
+ ...initialState.searchParams.current.advanced.exclude,
1038
+ query: {
1039
+ id: "91",
1040
+ key: "title",
1041
+ value: "foo",
1042
+ },
1043
+ selectedQueryId: "91",
1044
+ },
1045
+ },
1046
+ },
1047
+ },
1048
+ };
1049
+
1050
+ const nextState = reducer(state, {
1051
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1052
+ builderName: "exclude",
1053
+ query: valueQuery,
1054
+ });
1055
+
1056
+ expect(
1057
+ nextState.searchParams.current.advanced.exclude.query
1058
+ ).toStrictEqual({
1059
+ id: "91",
1060
+ or: [
1061
+ {
1062
+ id: "39",
1063
+ key: "title",
1064
+ value: "foo",
1065
+ },
1066
+ {
1067
+ id: "38",
1068
+ ...valueQuery,
1069
+ },
1070
+ ],
1071
+ });
1072
+
1073
+ expect(
1074
+ nextState.searchParams.current.advanced.exclude.selectedQueryId
1075
+ ).toBe("91");
1076
+ });
1077
+
1078
+ it("should create a boolean query that is the opposite of the parent if a new query is added to a non-boolean query", () => {
1079
+ const state = {
1080
+ ...initialState,
1081
+ searchParams: {
1082
+ ...initialState.searchParams,
1083
+ current: {
1084
+ ...initialState.searchParams.current,
1085
+ advanced: {
1086
+ ...initialState.searchParams.current.advanced,
1087
+ include: {
1088
+ ...initialState.searchParams.current.advanced.include,
1089
+ query: {
1090
+ id: "90",
1091
+ and: [
1092
+ {
1093
+ id: "91",
1094
+ key: "title",
1095
+ value: "foo",
1096
+ },
1097
+ {
1098
+ id: "92",
1099
+ key: "title",
1100
+ value: "bar",
1101
+ },
1102
+ ],
1103
+ },
1104
+ selectedQueryId: "92",
1105
+ },
1106
+ },
1107
+ },
1108
+ },
1109
+ };
1110
+
1111
+ const nextState = reducer(state, {
1112
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1113
+ builderName: "include",
1114
+ query: valueQuery,
1115
+ });
1116
+
1117
+ expect(
1118
+ nextState.searchParams.current.advanced.include.query
1119
+ ).toStrictEqual({
1120
+ id: "90",
1121
+ and: [
1122
+ {
1123
+ id: "91",
1124
+ key: "title",
1125
+ value: "foo",
1126
+ },
1127
+ {
1128
+ id: "92",
1129
+ or: [
1130
+ {
1131
+ id: "41",
1132
+ key: "title",
1133
+ value: "bar",
1134
+ },
1135
+ {
1136
+ id: "40",
1137
+ ...valueQuery,
1138
+ },
1139
+ ],
1140
+ },
1141
+ ],
1142
+ });
1143
+
1144
+ expect(
1145
+ nextState.searchParams.current.advanced.include.selectedQueryId
1146
+ ).toBe("92");
1147
+ });
1148
+
1149
+ it("updates isValid, isModified, and isSearchModified", () => {
1150
+ const state = {
1151
+ ...initialState,
1152
+ properties: {
1153
+ ...initialState.properties,
1154
+ current: {
1155
+ ...initialState.properties.current,
1156
+ name: "List 1",
1157
+ autoUpdate: true,
1158
+ },
1159
+ },
1160
+ };
1161
+
1162
+ const nextState = reducer(state, {
1163
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1164
+ builderName: "include",
1165
+ query: valueQuery,
1166
+ });
1167
+
1168
+ expect(nextState.isSearchModified).toBe(true);
1169
+ expect(nextState.isModified).toBe(true);
1170
+ expect(nextState.isValid).toBe(true);
1171
+ });
1172
+ });
1173
+
1174
+ describe("on UPDATE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY_BOOLEAN", () => {
1175
+ const include = {
1176
+ query: {
1177
+ id: "90",
1178
+ and: [
1179
+ {
1180
+ id: "91",
1181
+ key: "title",
1182
+ value: "foo",
1183
+ },
1184
+ {
1185
+ id: "92",
1186
+ key: "title",
1187
+ value: "bar",
1188
+ },
1189
+ ],
1190
+ },
1191
+ selectedQueryId: "92",
1192
+ };
1193
+
1194
+ const state = {
1195
+ ...initialState,
1196
+ searchParams: {
1197
+ ...initialState.searchParams,
1198
+ baseline: {
1199
+ ...initialState.searchParams.baseline,
1200
+ advanced: {
1201
+ ...initialState.searchParams.baseline.advanced,
1202
+ include: {
1203
+ ...initialState.searchParams.baseline.advanced.include,
1204
+ ...include,
1205
+ },
1206
+ },
1207
+ },
1208
+ current: {
1209
+ ...initialState.searchParams.current,
1210
+ advanced: {
1211
+ ...initialState.searchParams.current.advanced,
1212
+ include: {
1213
+ ...initialState.searchParams.current.advanced.include,
1214
+ ...include,
1215
+ },
1216
+ },
1217
+ },
1218
+ },
1219
+ };
1220
+
1221
+ it("should change the boolean operator on the specified query", () => {
1222
+ const nextState = reducer(state, {
1223
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY_BOOLEAN,
1224
+ builderName: "include",
1225
+ id: "90",
1226
+ bool: "or",
1227
+ });
1228
+
1229
+ expect(
1230
+ nextState.searchParams.current.advanced.include.query
1231
+ ).toStrictEqual({
1232
+ id: "90",
1233
+ or: [
1234
+ {
1235
+ id: "91",
1236
+ key: "title",
1237
+ value: "foo",
1238
+ },
1239
+ {
1240
+ id: "92",
1241
+ key: "title",
1242
+ value: "bar",
1243
+ },
1244
+ ],
1245
+ });
1246
+ });
1247
+
1248
+ it("should do nothing if the id does not refer to a boolean query", () => {
1249
+ const nextState = reducer(state, {
1250
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY_BOOLEAN,
1251
+ builderName: "include",
1252
+ id: "92",
1253
+ bool: "or",
1254
+ });
1255
+
1256
+ expect(nextState).toStrictEqual(state);
1257
+ });
1258
+
1259
+ it("should do nothing if the id does not refer any query", () => {
1260
+ const nextState = reducer(state, {
1261
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY_BOOLEAN,
1262
+ builderName: "include",
1263
+ id: "234",
1264
+ bool: "or",
1265
+ });
1266
+
1267
+ expect(nextState).toStrictEqual(state);
1268
+ });
1269
+
1270
+ it("updates isValid, isModified, and isSearchModified", () => {
1271
+ const namedState = {
1272
+ ...state,
1273
+ properties: {
1274
+ ...initialState.properties,
1275
+ current: {
1276
+ ...initialState.properties.current,
1277
+ name: "List 1",
1278
+ autoUpdate: true,
1279
+ },
1280
+ },
1281
+ };
1282
+
1283
+ const nextState = reducer(namedState, {
1284
+ type: ActionCreator.UPDATE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY_BOOLEAN,
1285
+ builderName: "include",
1286
+ id: "90",
1287
+ bool: "or",
1288
+ });
1289
+
1290
+ expect(nextState.isSearchModified).toBe(true);
1291
+ expect(nextState.isModified).toBe(true);
1292
+ expect(nextState.isValid).toBe(true);
1293
+ });
1294
+ });
1295
+
1296
+ describe("on MOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY", () => {
1297
+ const state = {
1298
+ ...initialState,
1299
+ searchParams: {
1300
+ ...initialState.searchParams,
1301
+ current: {
1302
+ ...initialState.searchParams.current,
1303
+ advanced: {
1304
+ ...initialState.searchParams.current.advanced,
1305
+ include: {
1306
+ ...initialState.searchParams.current.advanced.include,
1307
+ query: {
1308
+ id: "90",
1309
+ and: [
1310
+ {
1311
+ id: "91",
1312
+ or: [
1313
+ {
1314
+ id: "92",
1315
+ key: "title",
1316
+ value: "foo",
1317
+ },
1318
+ {
1319
+ id: "93",
1320
+ key: "title",
1321
+ value: "bar",
1322
+ },
1323
+ {
1324
+ id: "94",
1325
+ key: "title",
1326
+ value: "baz",
1327
+ },
1328
+ ],
1329
+ },
1330
+ {
1331
+ id: "95",
1332
+ or: [
1333
+ {
1334
+ id: "96",
1335
+ key: "author",
1336
+ value: "alice",
1337
+ },
1338
+ {
1339
+ id: "97",
1340
+ key: "author",
1341
+ value: "ben",
1342
+ },
1343
+ ],
1344
+ },
1345
+ ],
1346
+ },
1347
+ selectedQueryId: "92",
1348
+ },
1349
+ },
1350
+ },
1351
+ },
1352
+ };
1353
+
1354
+ it("should add the specified query to the target, and remove it from its current parent", () => {
1355
+ const nextState = reducer(state, {
1356
+ type: ActionCreator.MOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1357
+ builderName: "include",
1358
+ id: "92",
1359
+ targetId: "95",
1360
+ });
1361
+
1362
+ expect(
1363
+ nextState.searchParams.current.advanced.include.query
1364
+ ).toStrictEqual({
1365
+ id: "90",
1366
+ and: [
1367
+ {
1368
+ id: "91",
1369
+ or: [
1370
+ {
1371
+ id: "93",
1372
+ key: "title",
1373
+ value: "bar",
1374
+ },
1375
+ {
1376
+ id: "94",
1377
+ key: "title",
1378
+ value: "baz",
1379
+ },
1380
+ ],
1381
+ },
1382
+ {
1383
+ id: "95",
1384
+ or: [
1385
+ {
1386
+ id: "96",
1387
+ key: "author",
1388
+ value: "alice",
1389
+ },
1390
+ {
1391
+ id: "97",
1392
+ key: "author",
1393
+ value: "ben",
1394
+ },
1395
+ {
1396
+ id: "43",
1397
+ key: "title",
1398
+ value: "foo",
1399
+ },
1400
+ ],
1401
+ },
1402
+ ],
1403
+ });
1404
+ });
1405
+
1406
+ it("updates isValid, isModified, isSearchModified", () => {
1407
+ const namedState = {
1408
+ ...state,
1409
+ properties: {
1410
+ ...initialState.properties,
1411
+ current: {
1412
+ ...initialState.properties.current,
1413
+ name: "List 1",
1414
+ autoUpdate: true,
1415
+ },
1416
+ },
1417
+ };
1418
+
1419
+ const nextState = reducer(namedState, {
1420
+ type: ActionCreator.MOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1421
+ builderName: "include",
1422
+ id: "92",
1423
+ targetId: "95",
1424
+ });
1425
+
1426
+ expect(nextState.isSearchModified).toBe(true);
1427
+ expect(nextState.isModified).toBe(true);
1428
+ expect(nextState.isValid).toBe(true);
1429
+ });
1430
+ });
1431
+
1432
+ describe("on REMOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY", () => {
1433
+ it("should remove the specified query", () => {
1434
+ const state = {
1435
+ ...initialState,
1436
+ searchParams: {
1437
+ ...initialState.searchParams,
1438
+ current: {
1439
+ ...initialState.searchParams.current,
1440
+ advanced: {
1441
+ ...initialState.searchParams.current.advanced,
1442
+ include: {
1443
+ ...initialState.searchParams.current.advanced.include,
1444
+ query: {
1445
+ id: "90",
1446
+ and: [
1447
+ {
1448
+ id: "91",
1449
+ key: "title",
1450
+ value: "foo",
1451
+ },
1452
+ {
1453
+ id: "92",
1454
+ key: "title",
1455
+ value: "bar",
1456
+ },
1457
+ {
1458
+ id: "93",
1459
+ key: "title",
1460
+ value: "baz",
1461
+ },
1462
+ ],
1463
+ },
1464
+ selectedQueryId: "92",
1465
+ },
1466
+ },
1467
+ },
1468
+ },
1469
+ };
1470
+
1471
+ const nextState = reducer(state, {
1472
+ type: ActionCreator.REMOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1473
+ builderName: "include",
1474
+ id: "92",
1475
+ });
1476
+
1477
+ expect(
1478
+ nextState.searchParams.current.advanced.include.query
1479
+ ).toStrictEqual({
1480
+ id: "90",
1481
+ and: [
1482
+ {
1483
+ id: "91",
1484
+ key: "title",
1485
+ value: "foo",
1486
+ },
1487
+ {
1488
+ id: "93",
1489
+ key: "title",
1490
+ value: "baz",
1491
+ },
1492
+ ],
1493
+ });
1494
+
1495
+ expect(
1496
+ nextState.searchParams.current.advanced.include.selectedQueryId
1497
+ ).toBe("90");
1498
+ });
1499
+
1500
+ it("should remove the parent boolean, if there is only one remaining child after the specified query is removed", () => {
1501
+ const state = {
1502
+ ...initialState,
1503
+ searchParams: {
1504
+ ...initialState.searchParams,
1505
+ current: {
1506
+ ...initialState.searchParams.current,
1507
+ advanced: {
1508
+ ...initialState.searchParams.current.advanced,
1509
+ include: {
1510
+ ...initialState.searchParams.current.advanced.include,
1511
+ query: {
1512
+ id: "90",
1513
+ and: [
1514
+ {
1515
+ id: "91",
1516
+ key: "title",
1517
+ value: "foo",
1518
+ },
1519
+ {
1520
+ id: "92",
1521
+ key: "title",
1522
+ value: "bar",
1523
+ },
1524
+ ],
1525
+ },
1526
+ selectedQueryId: "92",
1527
+ },
1528
+ },
1529
+ },
1530
+ },
1531
+ };
1532
+
1533
+ const nextState = reducer(state, {
1534
+ type: ActionCreator.REMOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1535
+ builderName: "include",
1536
+ id: "92",
1537
+ });
1538
+
1539
+ expect(
1540
+ nextState.searchParams.current.advanced.include.query
1541
+ ).toStrictEqual({
1542
+ id: "91",
1543
+ key: "title",
1544
+ value: "foo",
1545
+ });
1546
+
1547
+ expect(
1548
+ nextState.searchParams.current.advanced.include.selectedQueryId
1549
+ ).toBe(undefined);
1550
+ });
1551
+
1552
+ it("updates isValid, isModified, and isSearchModified", () => {
1553
+ const state = {
1554
+ ...initialState,
1555
+ properties: {
1556
+ ...initialState.properties,
1557
+ current: {
1558
+ ...initialState.properties.current,
1559
+ name: "List 1",
1560
+ },
1561
+ },
1562
+ searchParams: {
1563
+ ...initialState.searchParams,
1564
+ baseline: {
1565
+ ...initialState.searchParams.baseline,
1566
+ advanced: {
1567
+ ...initialState.searchParams.baseline.advanced,
1568
+ include: {
1569
+ ...initialState.searchParams.baseline.advanced.include,
1570
+ query: {
1571
+ id: "92",
1572
+ key: "title",
1573
+ value: "bar",
1574
+ },
1575
+ selectedQueryId: "92",
1576
+ },
1577
+ },
1578
+ },
1579
+ current: {
1580
+ ...initialState.searchParams.current,
1581
+ advanced: {
1582
+ ...initialState.searchParams.current.advanced,
1583
+ include: {
1584
+ ...initialState.searchParams.current.advanced.include,
1585
+ query: {
1586
+ id: "92",
1587
+ key: "title",
1588
+ value: "bar",
1589
+ },
1590
+ selectedQueryId: "92",
1591
+ },
1592
+ },
1593
+ },
1594
+ },
1595
+ isModified: false,
1596
+ isValid: true,
1597
+ };
1598
+
1599
+ const nextState = reducer(state, {
1600
+ type: ActionCreator.REMOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1601
+ builderName: "include",
1602
+ id: "92",
1603
+ });
1604
+
1605
+ expect(nextState.isSearchModified).toBe(true);
1606
+ expect(nextState.isModified).toBe(true);
1607
+ expect(nextState.isValid).toBe(false);
1608
+ });
1609
+ });
1610
+
1611
+ describe("on SELECT_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY", () => {
1612
+ it("should select the specified query", () => {
1613
+ const state = {
1614
+ ...initialState,
1615
+ searchParams: {
1616
+ ...initialState.searchParams,
1617
+ current: {
1618
+ ...initialState.searchParams.current,
1619
+ advanced: {
1620
+ ...initialState.searchParams.current.advanced,
1621
+ include: {
1622
+ ...initialState.searchParams.current.advanced.include,
1623
+ query: {
1624
+ id: "90",
1625
+ and: [
1626
+ {
1627
+ id: "91",
1628
+ key: "title",
1629
+ value: "foo",
1630
+ },
1631
+ {
1632
+ id: "92",
1633
+ key: "title",
1634
+ value: "bar",
1635
+ },
1636
+ ],
1637
+ },
1638
+ selectedQueryId: "92",
1639
+ },
1640
+ },
1641
+ },
1642
+ },
1643
+ };
1644
+
1645
+ const nextState = reducer(state, {
1646
+ type: ActionCreator.SELECT_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1647
+ builderName: "include",
1648
+ id: "91",
1649
+ });
1650
+
1651
+ expect(
1652
+ nextState.searchParams.current.advanced.include.selectedQueryId
1653
+ ).toBe("91");
1654
+ });
1655
+
1656
+ it("should remove the parent boolean, if there is only one remaining child after the specified query is removed", () => {
1657
+ const state = {
1658
+ ...initialState,
1659
+ searchParams: {
1660
+ ...initialState.searchParams,
1661
+ current: {
1662
+ ...initialState.searchParams.current,
1663
+ advanced: {
1664
+ ...initialState.searchParams.current.advanced,
1665
+ include: {
1666
+ ...initialState.searchParams.current.advanced.include,
1667
+ query: {
1668
+ id: "90",
1669
+ and: [
1670
+ {
1671
+ id: "91",
1672
+ key: "title",
1673
+ value: "foo",
1674
+ },
1675
+ {
1676
+ id: "92",
1677
+ key: "title",
1678
+ value: "bar",
1679
+ },
1680
+ ],
1681
+ },
1682
+ selectedQueryId: "92",
1683
+ },
1684
+ },
1685
+ },
1686
+ },
1687
+ };
1688
+
1689
+ const nextState = reducer(state, {
1690
+ type: ActionCreator.REMOVE_CUSTOM_LIST_EDITOR_ADV_SEARCH_QUERY,
1691
+ builderName: "include",
1692
+ id: "92",
1693
+ });
1694
+
1695
+ expect(
1696
+ nextState.searchParams.current.advanced.include.query
1697
+ ).toStrictEqual({
1698
+ id: "91",
1699
+ key: "title",
1700
+ value: "foo",
1701
+ });
1702
+
1703
+ expect(
1704
+ nextState.searchParams.current.advanced.include.selectedQueryId
1705
+ ).toBe(undefined);
1706
+ });
1707
+ });
1708
+
1709
+ describe("on ADD_CUSTOM_LIST_EDITOR_ENTRY", () => {
1710
+ const searchResultData = {
1711
+ books: [
1712
+ {
1713
+ id: "book1",
1714
+ title: "A Farewell to Arms",
1715
+ authors: ["Ernest Hemingway"],
1716
+ url: "http://some/url",
1717
+ language: "english",
1718
+ },
1719
+ {
1720
+ id: "book2",
1721
+ title: "Little Women",
1722
+ authors: ["Louisa May Alcott"],
1723
+ url: "http://some/url",
1724
+ language: "english",
1725
+ },
1726
+ ],
1727
+ };
1728
+
1729
+ it("should add the book to entries added", () => {
1730
+ const state = {
1731
+ ...initialState,
1732
+ };
1733
+
1734
+ const nextState = reducer(state, {
1735
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ENTRY,
1736
+ id: "book2",
1737
+ data: searchResultData,
1738
+ });
1739
+
1740
+ expect(nextState.entries.added).toHaveProperty("book2", {
1741
+ id: "book2",
1742
+ title: "Little Women",
1743
+ authors: ["Louisa May Alcott"],
1744
+ url: "http://some/url",
1745
+ language: "english",
1746
+ medium: "",
1747
+ });
1748
+ });
1749
+
1750
+ it("should not add the book to entries added if it already exists in entries baseline", () => {
1751
+ const state = {
1752
+ ...initialState,
1753
+ entries: {
1754
+ ...initialState.entries,
1755
+ baseline: [{ id: "book2", title: "Little Women" }],
1756
+ },
1757
+ };
1758
+
1759
+ const nextState = reducer(state, {
1760
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ENTRY,
1761
+ id: "book2",
1762
+ data: searchResultData,
1763
+ });
1764
+
1765
+ expect(nextState.entries.added).not.toHaveProperty("book2");
1766
+ });
1767
+
1768
+ it("should remove the book from entries removed, if it is present", () => {
1769
+ const state = {
1770
+ ...initialState,
1771
+ entries: {
1772
+ ...initialState.entries,
1773
+ removed: {
1774
+ book2: true as const,
1775
+ },
1776
+ },
1777
+ };
1778
+
1779
+ const nextState = reducer(state, {
1780
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ENTRY,
1781
+ id: "book2",
1782
+ data: searchResultData,
1783
+ });
1784
+
1785
+ expect(nextState.entries.removed).not.toHaveProperty("book2");
1786
+ });
1787
+
1788
+ it("should apply the new delta to the baseline and update entries current", () => {
1789
+ const state = {
1790
+ ...initialState,
1791
+ entries: {
1792
+ ...initialState.entries,
1793
+ baseline: [
1794
+ { id: "book91", title: "Huckleberry Finn" },
1795
+ { id: "book90", title: "Wuthering Heights" },
1796
+ ],
1797
+ baselineTotalCount: 12,
1798
+ },
1799
+ };
1800
+
1801
+ const nextState = reducer(state, {
1802
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ENTRY,
1803
+ id: "book2",
1804
+ data: searchResultData,
1805
+ });
1806
+
1807
+ expect(nextState.entries.current).toStrictEqual([
1808
+ {
1809
+ id: "book2",
1810
+ title: "Little Women",
1811
+ authors: ["Louisa May Alcott"],
1812
+ url: "http://some/url",
1813
+ language: "english",
1814
+ medium: "",
1815
+ },
1816
+ { id: "book91", title: "Huckleberry Finn" },
1817
+ { id: "book90", title: "Wuthering Heights" },
1818
+ ]);
1819
+
1820
+ expect(nextState.entries.currentTotalCount).toBe(13); // 12 + 1
1821
+ });
1822
+
1823
+ it("should update isValid and isModified", () => {
1824
+ const state = {
1825
+ ...initialState,
1826
+ properties: {
1827
+ ...initialState.properties,
1828
+ current: {
1829
+ ...initialState.properties.current,
1830
+ name: "Awesome List",
1831
+ autoUpdate: false,
1832
+ },
1833
+ },
1834
+ isValid: false,
1835
+ isModified: false,
1836
+ };
1837
+
1838
+ const nextState = reducer(state, {
1839
+ type: ActionCreator.ADD_CUSTOM_LIST_EDITOR_ENTRY,
1840
+ id: "book2",
1841
+ data: searchResultData,
1842
+ });
1843
+
1844
+ expect(nextState.isValid).toBe(true);
1845
+ expect(nextState.isModified).toBe(true);
1846
+ });
1847
+ });
1848
+
1849
+ describe("on ADD_ALL_CUSTOM_LIST_EDITOR_ENTRIES", () => {
1850
+ const searchResultData = {
1851
+ books: [
1852
+ {
1853
+ id: "book1",
1854
+ title: "A Farewell to Arms",
1855
+ authors: ["Ernest Hemingway"],
1856
+ url: "http://some/url",
1857
+ language: "english",
1858
+ },
1859
+ {
1860
+ id: "book2",
1861
+ title: "Little Women",
1862
+ authors: ["Louisa May Alcott"],
1863
+ url: "http://some/url",
1864
+ language: "english",
1865
+ },
1866
+ ],
1867
+ };
1868
+
1869
+ it("should add all books in the search results data to entries added", () => {
1870
+ const state = {
1871
+ ...initialState,
1872
+ };
1873
+
1874
+ const nextState = reducer(state, {
1875
+ type: ActionCreator.ADD_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
1876
+ data: searchResultData,
1877
+ });
1878
+
1879
+ expect(nextState.entries.added).toStrictEqual({
1880
+ book1: {
1881
+ id: "book1",
1882
+ title: "A Farewell to Arms",
1883
+ authors: ["Ernest Hemingway"],
1884
+ url: "http://some/url",
1885
+ language: "english",
1886
+ medium: "",
1887
+ },
1888
+ book2: {
1889
+ id: "book2",
1890
+ title: "Little Women",
1891
+ authors: ["Louisa May Alcott"],
1892
+ url: "http://some/url",
1893
+ language: "english",
1894
+ medium: "",
1895
+ },
1896
+ });
1897
+ });
1898
+
1899
+ it("should not add a book to entries added if it already exists in entries baseline", () => {
1900
+ const state = {
1901
+ ...initialState,
1902
+ entries: {
1903
+ ...initialState.entries,
1904
+ baseline: [{ id: "book2", title: "Little Women" }],
1905
+ },
1906
+ };
1907
+
1908
+ const nextState = reducer(state, {
1909
+ type: ActionCreator.ADD_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
1910
+ data: searchResultData,
1911
+ });
1912
+
1913
+ expect(nextState.entries.added).toHaveProperty("book1");
1914
+ expect(nextState.entries.added).not.toHaveProperty("book2");
1915
+ });
1916
+
1917
+ it("should remove a book from entries removed, if it is present", () => {
1918
+ const state = {
1919
+ ...initialState,
1920
+ entries: {
1921
+ ...initialState.entries,
1922
+ removed: {
1923
+ book2: true as const,
1924
+ },
1925
+ },
1926
+ };
1927
+
1928
+ const nextState = reducer(state, {
1929
+ type: ActionCreator.ADD_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
1930
+ data: searchResultData,
1931
+ });
1932
+
1933
+ expect(nextState.entries.removed).not.toHaveProperty("book2");
1934
+ });
1935
+
1936
+ it("should apply the new delta to the baseline and update entries current", () => {
1937
+ const state = {
1938
+ ...initialState,
1939
+ entries: {
1940
+ ...initialState.entries,
1941
+ baseline: [
1942
+ { id: "book91", title: "Huckleberry Finn" },
1943
+ { id: "book90", title: "Wuthering Heights" },
1944
+ ],
1945
+ baselineTotalCount: 12,
1946
+ },
1947
+ };
1948
+
1949
+ const nextState = reducer(state, {
1950
+ type: ActionCreator.ADD_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
1951
+ data: searchResultData,
1952
+ });
1953
+
1954
+ expect(nextState.entries.current).toStrictEqual([
1955
+ {
1956
+ id: "book2",
1957
+ title: "Little Women",
1958
+ authors: ["Louisa May Alcott"],
1959
+ url: "http://some/url",
1960
+ language: "english",
1961
+ medium: "",
1962
+ },
1963
+ {
1964
+ id: "book1",
1965
+ title: "A Farewell to Arms",
1966
+ authors: ["Ernest Hemingway"],
1967
+ url: "http://some/url",
1968
+ language: "english",
1969
+ medium: "",
1970
+ },
1971
+ { id: "book91", title: "Huckleberry Finn" },
1972
+ { id: "book90", title: "Wuthering Heights" },
1973
+ ]);
1974
+
1975
+ expect(nextState.entries.currentTotalCount).toBe(14); // 12 + 2
1976
+ });
1977
+
1978
+ it("should update isValid and isModified", () => {
1979
+ const state = {
1980
+ ...initialState,
1981
+ properties: {
1982
+ ...initialState.properties,
1983
+ current: {
1984
+ ...initialState.properties.current,
1985
+ name: "Awesome List",
1986
+ autoUpdate: false,
1987
+ },
1988
+ },
1989
+ isValid: false,
1990
+ isModified: false,
1991
+ };
1992
+
1993
+ const nextState = reducer(state, {
1994
+ type: ActionCreator.ADD_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
1995
+ data: searchResultData,
1996
+ });
1997
+
1998
+ expect(nextState.isValid).toBe(true);
1999
+ expect(nextState.isModified).toBe(true);
2000
+ });
2001
+ });
2002
+
2003
+ describe("on DELETE_CUSTOM_LIST_EDITOR_ENTRY", () => {
2004
+ it("should add the book to entries removed", () => {
2005
+ const state = {
2006
+ ...initialState,
2007
+ };
2008
+
2009
+ const nextState = reducer(state, {
2010
+ type: ActionCreator.DELETE_CUSTOM_LIST_EDITOR_ENTRY,
2011
+ id: "book1",
2012
+ });
2013
+
2014
+ expect(nextState.entries.removed).toHaveProperty("book1", true);
2015
+ });
2016
+
2017
+ it("should delete the book from entries added, if it is present", () => {
2018
+ const state = {
2019
+ ...initialState,
2020
+ entries: {
2021
+ ...initialState.entries,
2022
+ added: {
2023
+ book1: {
2024
+ id: "book1",
2025
+ title: "A Farewell to Arms",
2026
+ authors: ["Ernest Hemingway"],
2027
+ url: "http://some/url",
2028
+ language: "english",
2029
+ medium: "",
2030
+ },
2031
+ },
2032
+ },
2033
+ };
2034
+
2035
+ const nextState = reducer(state, {
2036
+ type: ActionCreator.DELETE_CUSTOM_LIST_EDITOR_ENTRY,
2037
+ id: "book1",
2038
+ });
2039
+
2040
+ expect(nextState.entries.added).not.toHaveProperty("book1");
2041
+ expect(nextState.entries.removed).not.toHaveProperty("book1");
2042
+ });
2043
+
2044
+ it("should apply the new delta to the baseline and update entries current", () => {
2045
+ const state = {
2046
+ ...initialState,
2047
+ entries: {
2048
+ ...initialState.entries,
2049
+ baseline: [
2050
+ { id: "book91", title: "Huckleberry Finn" },
2051
+ { id: "book90", title: "Wuthering Heights" },
2052
+ ],
2053
+ baselineTotalCount: 12,
2054
+ },
2055
+ };
2056
+
2057
+ const nextState = reducer(state, {
2058
+ type: ActionCreator.DELETE_CUSTOM_LIST_EDITOR_ENTRY,
2059
+ id: "book91",
2060
+ });
2061
+
2062
+ expect(nextState.entries.current).toStrictEqual([
2063
+ { id: "book90", title: "Wuthering Heights" },
2064
+ ]);
2065
+
2066
+ expect(nextState.entries.currentTotalCount).toBe(11); // 12 - 1
2067
+ });
2068
+
2069
+ it("should update isValid and isModified", () => {
2070
+ const state = {
2071
+ ...initialState,
2072
+ properties: {
2073
+ ...initialState.properties,
2074
+ baseline: {
2075
+ ...initialState.properties.baseline,
2076
+ name: "Awesome List",
2077
+ },
2078
+ current: {
2079
+ ...initialState.properties.current,
2080
+ name: "Awesome List",
2081
+ },
2082
+ },
2083
+ entries: {
2084
+ ...initialState.entries,
2085
+ baseline: [{ id: "book91", title: "Huckleberry Finn" }],
2086
+ baselineTotalCount: 1,
2087
+ current: [{ id: "book91", title: "Huckleberry Finn" }],
2088
+ currentTotalCount: 1,
2089
+ },
2090
+ isValid: true,
2091
+ isModified: false,
2092
+ };
2093
+
2094
+ const nextState = reducer(state, {
2095
+ type: ActionCreator.DELETE_CUSTOM_LIST_EDITOR_ENTRY,
2096
+ id: "book91",
2097
+ });
2098
+
2099
+ expect(nextState.isValid).toBe(false);
2100
+ expect(nextState.isModified).toBe(true);
2101
+ });
2102
+ });
2103
+
2104
+ describe("on DELETE_ALL_CUSTOM_LIST_EDITOR_ENTRIES", () => {
2105
+ it("should add all books in baseline entries to entries removed", () => {
2106
+ const state = {
2107
+ ...initialState,
2108
+ entries: {
2109
+ ...initialState.entries,
2110
+ baseline: [
2111
+ { id: "book91", title: "Huckleberry Finn" },
2112
+ { id: "book90", title: "Wuthering Heights" },
2113
+ ],
2114
+ },
2115
+ };
2116
+
2117
+ const nextState = reducer(state, {
2118
+ type: ActionCreator.DELETE_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
2119
+ });
2120
+
2121
+ expect(nextState.entries.removed).toHaveProperty("book91", true);
2122
+ expect(nextState.entries.removed).toHaveProperty("book90", true);
2123
+ });
2124
+
2125
+ it("should empty entries added", () => {
2126
+ const state = {
2127
+ ...initialState,
2128
+ entries: {
2129
+ ...initialState.entries,
2130
+ added: {
2131
+ book1: {
2132
+ id: "book1",
2133
+ title: "A Farewell to Arms",
2134
+ authors: ["Ernest Hemingway"],
2135
+ url: "http://some/url",
2136
+ language: "english",
2137
+ medium: "",
2138
+ },
2139
+ },
2140
+ },
2141
+ };
2142
+
2143
+ const nextState = reducer(state, {
2144
+ type: ActionCreator.DELETE_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
2145
+ });
2146
+
2147
+ expect(nextState.entries.added).toStrictEqual({});
2148
+ });
2149
+
2150
+ it("should apply the new delta to the baseline and update entries current", () => {
2151
+ const state = {
2152
+ ...initialState,
2153
+ entries: {
2154
+ ...initialState.entries,
2155
+ baseline: [
2156
+ { id: "book91", title: "Huckleberry Finn" },
2157
+ { id: "book90", title: "Wuthering Heights" },
2158
+ ],
2159
+ baselineTotalCount: 12,
2160
+ },
2161
+ };
2162
+
2163
+ const nextState = reducer(state, {
2164
+ type: ActionCreator.DELETE_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
2165
+ });
2166
+
2167
+ expect(nextState.entries.current).toHaveLength(0);
2168
+ expect(nextState.entries.currentTotalCount).toBe(10); // 12 - 2
2169
+ });
2170
+
2171
+ it("should update isValid and isModified", () => {
2172
+ const state = {
2173
+ ...initialState,
2174
+ properties: {
2175
+ ...initialState.properties,
2176
+ baseline: {
2177
+ ...initialState.properties.baseline,
2178
+ name: "Awesome List",
2179
+ },
2180
+ current: {
2181
+ ...initialState.properties.current,
2182
+ name: "Awesome List",
2183
+ },
2184
+ },
2185
+ entries: {
2186
+ ...initialState.entries,
2187
+ baseline: [{ id: "book91", title: "Huckleberry Finn" }],
2188
+ baselineTotalCount: 1,
2189
+ current: [{ id: "book91", title: "Huckleberry Finn" }],
2190
+ currentTotalCount: 1,
2191
+ },
2192
+ isValid: true,
2193
+ isModified: false,
2194
+ };
2195
+
2196
+ const nextState = reducer(state, {
2197
+ type: ActionCreator.DELETE_ALL_CUSTOM_LIST_EDITOR_ENTRIES,
2198
+ });
2199
+
2200
+ expect(nextState.isValid).toBe(false);
2201
+ expect(nextState.isModified).toBe(true);
2202
+ });
2203
+ });
2204
+
2205
+ describe("on RESET_CUSTOM_LIST_EDITOR", () => {
2206
+ it("should restore baseline properties", () => {
2207
+ const state = {
2208
+ ...initialState,
2209
+ properties: {
2210
+ ...initialState.properties,
2211
+ baseline: {
2212
+ ...initialState.properties.baseline,
2213
+ name: "Original Title",
2214
+ collections: [1, 2],
2215
+ },
2216
+ current: {
2217
+ ...initialState.properties.current,
2218
+ name: "Something Else",
2219
+ collections: [3],
2220
+ },
2221
+ },
2222
+ };
2223
+
2224
+ const nextState = reducer(state, {
2225
+ type: ActionCreator.RESET_CUSTOM_LIST_EDITOR,
2226
+ });
2227
+
2228
+ expect(nextState.properties.current).toHaveProperty(
2229
+ "name",
2230
+ "Original Title"
2231
+ );
2232
+
2233
+ expect(nextState.properties.current).toHaveProperty(
2234
+ "collections",
2235
+ [1, 2]
2236
+ );
2237
+ });
2238
+
2239
+ it("should clear entries added and removed", () => {
2240
+ const state = {
2241
+ ...initialState,
2242
+ entries: {
2243
+ ...initialState.entries,
2244
+ added: {
2245
+ book90: { id: "book90", title: "Wuthering Heights" },
2246
+ book91: { id: "book91", title: "Huckleberry Finn" },
2247
+ },
2248
+ removed: {
2249
+ book1: true as const,
2250
+ },
2251
+ },
2252
+ };
2253
+
2254
+ const nextState = reducer(state, {
2255
+ type: ActionCreator.RESET_CUSTOM_LIST_EDITOR,
2256
+ });
2257
+
2258
+ expect(nextState.entries.added).toStrictEqual({});
2259
+ expect(nextState.entries.removed).toStrictEqual({});
2260
+ });
2261
+
2262
+ it("should apply the new delta to the baseline and update entries current", () => {
2263
+ const state = {
2264
+ ...initialState,
2265
+ entries: {
2266
+ ...initialState.entries,
2267
+ baseline: [
2268
+ { id: "book91", title: "Huckleberry Finn" },
2269
+ { id: "book90", title: "Wuthering Heights" },
2270
+ ],
2271
+ baselineTotalCount: 12,
2272
+ added: {
2273
+ book2: {
2274
+ id: "book2",
2275
+ title: "Little Women",
2276
+ authors: ["Louisa May Alcott"],
2277
+ url: "http://some/url",
2278
+ language: "english",
2279
+ medium: "",
2280
+ },
2281
+ },
2282
+ removed: {
2283
+ book1: true as const,
2284
+ book3: true as const,
2285
+ },
2286
+ current: [
2287
+ { id: "book2", title: "Little Women" },
2288
+ { id: "book91", title: "Huckleberry Finn" },
2289
+ { id: "book90", title: "Wuthering Heights" },
2290
+ ],
2291
+ currentTotalCount: 11,
2292
+ },
2293
+ };
2294
+
2295
+ const nextState = reducer(state, {
2296
+ type: ActionCreator.RESET_CUSTOM_LIST_EDITOR,
2297
+ });
2298
+
2299
+ expect(nextState.entries.current).toStrictEqual([
2300
+ { id: "book91", title: "Huckleberry Finn" },
2301
+ { id: "book90", title: "Wuthering Heights" },
2302
+ ]);
2303
+
2304
+ expect(nextState.entries.currentTotalCount).toBe(12);
2305
+ });
2306
+
2307
+ it("should update isValid and isModified", () => {
2308
+ const state = {
2309
+ ...initialState,
2310
+ properties: {
2311
+ ...initialState.properties,
2312
+ baseline: {
2313
+ ...initialState.properties.baseline,
2314
+ name: "Original Title",
2315
+ collections: [1, 2],
2316
+ },
2317
+ current: {
2318
+ ...initialState.properties.current,
2319
+ name: "Something Else",
2320
+ collections: [],
2321
+ },
2322
+ isValid: false,
2323
+ isModified: true,
2324
+ },
2325
+ };
2326
+
2327
+ const nextState = reducer(state, {
2328
+ type: ActionCreator.RESET_CUSTOM_LIST_EDITOR,
2329
+ });
2330
+
2331
+ expect(nextState.isValid).toBe(true);
2332
+ expect(nextState.isModified).toBe(false);
2333
+ });
2334
+ });
2335
+
2336
+ describe("on CUSTOM_LIST_SHARE_REQUEST", () => {
2337
+ it("should set isSharePending to true if the listId in the action is the id in state", () => {
2338
+ const state = {
2339
+ ...initialState,
2340
+ id: 24,
2341
+ };
2342
+
2343
+ const nextState = reducer(state, {
2344
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.REQUEST}`,
2345
+ listId: 24,
2346
+ });
2347
+
2348
+ expect(nextState.isSharePending).toBe(true);
2349
+ });
2350
+
2351
+ it("should do nothing if the listId in the action is not the id in state", () => {
2352
+ const state = {
2353
+ ...initialState,
2354
+ id: 24,
2355
+ };
2356
+
2357
+ const nextState = reducer(state, {
2358
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.REQUEST}`,
2359
+ listId: 77,
2360
+ });
2361
+
2362
+ expect(nextState).toBe(state);
2363
+ });
2364
+ });
2365
+
2366
+ describe("on CUSTOM_LIST_SHARE_SUCCESS", () => {
2367
+ it("should set isSharePending to false if the listId in the action is the id in state", () => {
2368
+ const state = {
2369
+ ...initialState,
2370
+ id: 24,
2371
+ isSharePending: true,
2372
+ };
2373
+
2374
+ const nextState = reducer(state, {
2375
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.SUCCESS}`,
2376
+ listId: 24,
2377
+ });
2378
+
2379
+ expect(nextState.isSharePending).toBe(false);
2380
+ });
2381
+
2382
+ it("should set isShared to the value in the list data if the listId in the action is the id in state", () => {
2383
+ const state = {
2384
+ ...initialState,
2385
+ id: 24,
2386
+ isSharePending: true,
2387
+ };
2388
+
2389
+ const nextState = reducer(state, {
2390
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.SUCCESS}`,
2391
+ listId: 24,
2392
+ data: {
2393
+ custom_lists: [
2394
+ {
2395
+ id: 24,
2396
+ is_shared: true,
2397
+ },
2398
+ ],
2399
+ },
2400
+ });
2401
+
2402
+ expect(nextState.isShared).toBe(true);
2403
+ });
2404
+
2405
+ it("should do nothing if the listId in the action is not the id in state", () => {
2406
+ const state = {
2407
+ ...initialState,
2408
+ id: 24,
2409
+ isSharePending: true,
2410
+ };
2411
+
2412
+ const nextState = reducer(state, {
2413
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.SUCCESS}`,
2414
+ listId: 77,
2415
+ });
2416
+
2417
+ expect(nextState).toBe(state);
2418
+ });
2419
+ });
2420
+
2421
+ describe("on CUSTOM_LIST_SHARE_FAILURE", () => {
2422
+ it("should set isSharePending to false if the listId in the action is the id in state", () => {
2423
+ const state = {
2424
+ ...initialState,
2425
+ id: 24,
2426
+ isSharePending: true,
2427
+ };
2428
+
2429
+ const nextState = reducer(state, {
2430
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.FAILURE}`,
2431
+ listId: 24,
2432
+ error: {},
2433
+ });
2434
+
2435
+ expect(nextState.isSharePending).toBe(false);
2436
+ });
2437
+
2438
+ it("should set error to the action's error message if listId in the action is the id in state", () => {
2439
+ const state = {
2440
+ ...initialState,
2441
+ id: 24,
2442
+ isSharePending: true,
2443
+ };
2444
+
2445
+ const nextState = reducer(state, {
2446
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.FAILURE}`,
2447
+ listId: 24,
2448
+ error: {
2449
+ message: "Something is very wrong",
2450
+ },
2451
+ });
2452
+
2453
+ expect(nextState.error).toBe("Something is very wrong");
2454
+ });
2455
+
2456
+ it("should do nothing if the listId in the action is not the id in state", () => {
2457
+ const state = {
2458
+ ...initialState,
2459
+ id: 24,
2460
+ isSharePending: true,
2461
+ };
2462
+
2463
+ const nextState = reducer(state, {
2464
+ type: `${ActionCreator.CUSTOM_LIST_SHARE}_${ActionCreator.FAILURE}`,
2465
+ listId: 77,
2466
+ });
2467
+
2468
+ expect(nextState).toBe(state);
2469
+ });
2470
+ });
2471
+
2472
+ describe("getCustomListEditorFormData", () => {
2473
+ it("should generate multipart form data from the current properties and entries", () => {
2474
+ const state = {
2475
+ ...initialState,
2476
+ id: 123,
2477
+ properties: {
2478
+ ...initialState.properties,
2479
+ current: {
2480
+ ...initialState.properties.current,
2481
+ name: "My New List",
2482
+ collections: [1, 2],
2483
+ autoUpdate: false,
2484
+ },
2485
+ },
2486
+ entries: {
2487
+ ...initialState.entries,
2488
+ baseline: [
2489
+ { id: "book91", title: "Huckleberry Finn" },
2490
+ { id: "book90", title: "Wuthering Heights" },
2491
+ ],
2492
+ current: [
2493
+ { id: "book2", title: "Little Women" },
2494
+ { id: "book91", title: "Huckleberry Finn" },
2495
+ ],
2496
+ removed: {
2497
+ book90: true as const,
2498
+ },
2499
+ },
2500
+ };
2501
+
2502
+ const formData = getCustomListEditorFormData(state);
2503
+
2504
+ expect(formData.get("id")).toBe("123");
2505
+ expect(formData.get("name")).toBe("My New List");
2506
+ expect(formData.get("collections")).toBe("[1,2]");
2507
+ // The form data entries should have only the ids of the appropriate entries.
2508
+ expect(formData.get("entries")).toBe('[{"id":"book2"}]');
2509
+ expect(formData.get("deletedEntries")).toBe('[{"id":"book90"}]');
2510
+ });
2511
+
2512
+ it("should include an auto update query if the list is auto updating", () => {
2513
+ const state = {
2514
+ ...initialState,
2515
+ id: 123,
2516
+ properties: {
2517
+ ...initialState.properties,
2518
+ current: {
2519
+ ...initialState.properties.current,
2520
+ name: "My New List",
2521
+ collections: [1, 2],
2522
+ autoUpdate: true,
2523
+ },
2524
+ },
2525
+ searchParams: {
2526
+ ...initialState.searchParams,
2527
+ current: {
2528
+ ...initialState.searchParams.current,
2529
+ advanced: {
2530
+ ...initialState.searchParams.current.advanced,
2531
+ include: {
2532
+ ...initialState.searchParams.current.advanced.include,
2533
+ query: {
2534
+ id: "0",
2535
+ key: "title",
2536
+ op: "eq",
2537
+ value: "Little Women",
2538
+ },
2539
+ },
2540
+ },
2541
+ },
2542
+ },
2543
+ entries: {
2544
+ ...initialState.entries,
2545
+ baseline: [
2546
+ { id: "book91", title: "Huckleberry Finn" },
2547
+ { id: "book90", title: "Wuthering Heights" },
2548
+ ],
2549
+ current: [
2550
+ { id: "book2", title: "Little Women" },
2551
+ { id: "book91", title: "Huckleberry Finn" },
2552
+ ],
2553
+ removed: {
2554
+ book90: true as const,
2555
+ },
2556
+ },
2557
+ };
2558
+
2559
+ const formData = getCustomListEditorFormData(state);
2560
+
2561
+ expect(formData.get("id")).toBe("123");
2562
+ expect(formData.get("name")).toBe("My New List");
2563
+ expect(formData.get("collections")).toBe("[1,2]");
2564
+ expect(formData.get("auto_update")).toBe("true");
2565
+ expect(formData.get("auto_update_query")).toBe(
2566
+ '{"query":{"key":"title","value":"Little Women"}}'
2567
+ );
2568
+ });
2569
+
2570
+ it("should include auto update facets if the list is auto updating", () => {
2571
+ const state = {
2572
+ ...initialState,
2573
+ id: 123,
2574
+ properties: {
2575
+ ...initialState.properties,
2576
+ current: {
2577
+ ...initialState.properties.current,
2578
+ name: "My New List",
2579
+ autoUpdate: true,
2580
+ },
2581
+ },
2582
+ searchParams: {
2583
+ ...initialState.searchParams,
2584
+ current: {
2585
+ ...initialState.searchParams.current,
2586
+ entryPoint: "Audio",
2587
+ sort: "title",
2588
+ advanced: {
2589
+ ...initialState.searchParams.current.advanced,
2590
+ include: {
2591
+ ...initialState.searchParams.current.advanced.include,
2592
+ query: {
2593
+ id: "0",
2594
+ key: "title",
2595
+ op: "eq",
2596
+ value: "Little Women",
2597
+ },
2598
+ },
2599
+ },
2600
+ },
2601
+ },
2602
+ };
2603
+
2604
+ const formData = getCustomListEditorFormData(state);
2605
+
2606
+ expect(formData.get("auto_update_facets")).toBe(
2607
+ '{"media":"Audio","order":"title"}'
2608
+ );
2609
+ });
2610
+
2611
+ it('should not include media in auto update facets if entryPoint is "All"', () => {
2612
+ const state = {
2613
+ ...initialState,
2614
+ id: 123,
2615
+ properties: {
2616
+ ...initialState.properties,
2617
+ current: {
2618
+ ...initialState.properties.current,
2619
+ name: "My New List",
2620
+ autoUpdate: true,
2621
+ },
2622
+ },
2623
+ searchParams: {
2624
+ ...initialState.searchParams,
2625
+ current: {
2626
+ ...initialState.searchParams.current,
2627
+ entryPoint: "All",
2628
+ sort: "title",
2629
+ advanced: {
2630
+ ...initialState.searchParams.current.advanced,
2631
+ include: {
2632
+ ...initialState.searchParams.current.advanced.include,
2633
+ query: {
2634
+ id: "0",
2635
+ key: "title",
2636
+ op: "eq",
2637
+ value: "Little Women",
2638
+ },
2639
+ },
2640
+ },
2641
+ },
2642
+ },
2643
+ };
2644
+
2645
+ const formData = getCustomListEditorFormData(state);
2646
+
2647
+ expect(formData.get("auto_update_facets")).toBe('{"order":"title"}');
2648
+ });
2649
+
2650
+ it("should not include order in auto update facets if sort is null", () => {
2651
+ const state = {
2652
+ ...initialState,
2653
+ id: 123,
2654
+ properties: {
2655
+ ...initialState.properties,
2656
+ current: {
2657
+ ...initialState.properties.current,
2658
+ name: "My New List",
2659
+ autoUpdate: true,
2660
+ },
2661
+ },
2662
+ searchParams: {
2663
+ ...initialState.searchParams,
2664
+ current: {
2665
+ ...initialState.searchParams.current,
2666
+ entryPoint: "Book",
2667
+ sort: null,
2668
+ advanced: {
2669
+ ...initialState.searchParams.current.advanced,
2670
+ include: {
2671
+ ...initialState.searchParams.current.advanced.include,
2672
+ query: {
2673
+ id: "0",
2674
+ key: "title",
2675
+ op: "eq",
2676
+ value: "Little Women",
2677
+ },
2678
+ },
2679
+ },
2680
+ },
2681
+ },
2682
+ };
2683
+
2684
+ const formData = getCustomListEditorFormData(state);
2685
+
2686
+ expect(formData.get("auto_update_facets")).toBe('{"media":"Book"}');
2687
+ });
2688
+ });
2689
+
2690
+ describe("getCustomListEditorSearchUrl", () => {
2691
+ it("should generate a search url from the search params", () => {
2692
+ const state = {
2693
+ ...initialState,
2694
+ searchParams: {
2695
+ ...initialState.searchParams,
2696
+ current: {
2697
+ entryPoint: "Book",
2698
+ terms: "foo bar baz",
2699
+ sort: "title",
2700
+ language: "all",
2701
+ advanced: {
2702
+ include: {
2703
+ query: null,
2704
+ selectedQueryId: null,
2705
+ clearFilters: null,
2706
+ },
2707
+ exclude: {
2708
+ query: null,
2709
+ selectedQueryId: null,
2710
+ clearFilters: null,
2711
+ },
2712
+ },
2713
+ },
2714
+ },
2715
+ };
2716
+
2717
+ const library = "lib";
2718
+ const url = getCustomListEditorSearchUrl(state, library);
2719
+
2720
+ expect(url).toBe(
2721
+ "/lib/search?language=all&media=Book&order=title&q=foo%20bar%20baz"
2722
+ );
2723
+ });
2724
+
2725
+ it('should omit the media param if entryPoint is "All"', () => {
2726
+ const state = {
2727
+ ...initialState,
2728
+ searchParams: {
2729
+ ...initialState.searchParams,
2730
+ current: {
2731
+ entryPoint: "All",
2732
+ terms: "foo bar baz",
2733
+ sort: "title",
2734
+ language: "all",
2735
+ advanced: {
2736
+ include: {
2737
+ query: null,
2738
+ selectedQueryId: null,
2739
+ clearFilters: null,
2740
+ },
2741
+ exclude: {
2742
+ query: null,
2743
+ selectedQueryId: null,
2744
+ clearFilters: null,
2745
+ },
2746
+ },
2747
+ },
2748
+ },
2749
+ };
2750
+
2751
+ const library = "lib";
2752
+ const url = getCustomListEditorSearchUrl(state, library);
2753
+
2754
+ expect(url).toBe(
2755
+ "/lib/search?language=all&order=title&q=foo%20bar%20baz"
2756
+ );
2757
+ });
2758
+
2759
+ it("should omit the order param if sort is null", () => {
2760
+ const state = {
2761
+ ...initialState,
2762
+ searchParams: {
2763
+ ...initialState.searchParams,
2764
+ current: {
2765
+ entryPoint: "All",
2766
+ terms: "foo bar baz",
2767
+ sort: null,
2768
+ language: "all",
2769
+ advanced: {
2770
+ include: {
2771
+ query: null,
2772
+ selectedQueryId: null,
2773
+ clearFilters: null,
2774
+ },
2775
+ exclude: {
2776
+ query: null,
2777
+ selectedQueryId: null,
2778
+ clearFilters: null,
2779
+ },
2780
+ },
2781
+ },
2782
+ },
2783
+ };
2784
+
2785
+ const library = "lib";
2786
+ const url = getCustomListEditorSearchUrl(state, library);
2787
+
2788
+ expect(url).toBe("/lib/search?language=all&q=foo%20bar%20baz");
2789
+ });
2790
+
2791
+ it("should omit the language param if language is null", () => {
2792
+ const state = {
2793
+ ...initialState,
2794
+ searchParams: {
2795
+ ...initialState.searchParams,
2796
+ current: {
2797
+ entryPoint: "All",
2798
+ terms: "foo bar baz",
2799
+ sort: null,
2800
+ language: null,
2801
+ advanced: {
2802
+ include: {
2803
+ query: null,
2804
+ selectedQueryId: null,
2805
+ clearFilters: null,
2806
+ },
2807
+ exclude: {
2808
+ query: null,
2809
+ selectedQueryId: null,
2810
+ clearFilters: null,
2811
+ },
2812
+ },
2813
+ },
2814
+ },
2815
+ };
2816
+
2817
+ const library = "lib";
2818
+ const url = getCustomListEditorSearchUrl(state, library);
2819
+
2820
+ expect(url).toBe("/lib/search?q=foo%20bar%20baz");
2821
+ });
2822
+ });
2823
+ });