@thepalaceproject/circulation-admin 1.17.0 → 1.19.0-post.1

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.
@@ -0,0 +1,648 @@
1
+ import * as React from "react";
2
+ import { act, renderHook } from "@testing-library/react-hooks";
3
+ import { within } from "@testing-library/react";
4
+ import {
5
+ componentWithProviders,
6
+ renderWithProviders,
7
+ } from "../testUtils/withProviders";
8
+ import { QueryClient } from "@tanstack/react-query";
9
+ import { setupServer } from "msw/node";
10
+ import { rest } from "msw";
11
+ import {
12
+ ACK_RESPONSE_BUTTON_CONTENT,
13
+ ACK_RESPONSE_HEADING,
14
+ CANCEL_BUTTON_CONTENT,
15
+ CONFIRM_BUTTON_CONTENT,
16
+ CONFIRMATION_MODAL_HEADING,
17
+ useGenerateReport,
18
+ useReportInfo,
19
+ } from "../../../src/components/InventoryReportRequestModal";
20
+ import * as AdminAPI from "../../../src/api/admin";
21
+ import InventoryReportRequestModal, {
22
+ NO_COLLECTIONS_MESSAGE,
23
+ SOME_COLLECTIONS_MESSAGE,
24
+ UNKNOWN_COLLECTIONS_MESSAGE,
25
+ } from "../../../src/components/InventoryReportRequestModal";
26
+ import userEvent from "@testing-library/user-event";
27
+ import { InventoryReportInfo } from "../../../src/api/admin";
28
+
29
+ const MODAL_HEADING_LEVEL = 4;
30
+ const COLLECTION_NAME = "Collection A";
31
+ const INFO_SUCCESS_SOME_COLLECTIONS: InventoryReportInfo = Object.freeze({
32
+ collections: [{ id: 0, name: COLLECTION_NAME }],
33
+ });
34
+ const INFO_SUCCESS_NO_COLLECTIONS: InventoryReportInfo = Object.freeze({
35
+ collections: [],
36
+ });
37
+ const GENERATE_REPORT_SUCCESS = {
38
+ message: "We triggered report generation.",
39
+ };
40
+ const MOCK_SERVER_API_ENDPOINT_PATH =
41
+ "/admin/reports/inventory_report/:library_short_name";
42
+ const API_ENDPOINT_PARAMS: AdminAPI.InventoryReportRequestParams = {
43
+ library: "library-short-name",
44
+ };
45
+
46
+ const setupMockServer = () => {
47
+ return setupServer(
48
+ rest.get(MOCK_SERVER_API_ENDPOINT_PATH, async (_, res, ctx) => {
49
+ return res(ctx.status(200), ctx.json(INFO_SUCCESS_SOME_COLLECTIONS));
50
+ }),
51
+ rest.post(MOCK_SERVER_API_ENDPOINT_PATH, async (_, res, ctx) => {
52
+ return res(ctx.status(202), ctx.json(GENERATE_REPORT_SUCCESS));
53
+ })
54
+ );
55
+ };
56
+
57
+ describe("InventoryReportRequestModal", () => {
58
+ /* eslint-disable @typescript-eslint/no-empty-function */
59
+ const queryClient = new QueryClient({
60
+ defaultOptions: {
61
+ queries: {
62
+ retry: false,
63
+ },
64
+ },
65
+ logger: {
66
+ log: console.log,
67
+ warn: console.warn,
68
+ error: process.env.NODE_ENV === "test" ? () => {} : console.error,
69
+ },
70
+ });
71
+ /* eslint-enable @typescript-eslint/no-empty-function */
72
+
73
+ describe("query hooks call correct api methods", () => {
74
+ const wrapper = componentWithProviders({ queryClient });
75
+
76
+ describe("get report information", () => {
77
+ const mock_info_api = jest.spyOn(AdminAPI, "getInventoryReportInfo");
78
+
79
+ afterEach(() => {
80
+ jest.clearAllMocks();
81
+ queryClient.clear();
82
+ });
83
+ afterAll(() => mock_info_api.mockRestore());
84
+
85
+ it("report info query hook performs fetch, when enabled", async () => {
86
+ const show = true;
87
+
88
+ mock_info_api.mockResolvedValue(INFO_SUCCESS_SOME_COLLECTIONS);
89
+ const { result, waitFor } = renderHook(
90
+ () => useReportInfo(show, API_ENDPOINT_PARAMS),
91
+ { wrapper }
92
+ );
93
+ await waitFor(() => result.current.fetchStatus == "idle");
94
+ const { isSuccess, isError, error, collections } = result.current;
95
+
96
+ expect(mock_info_api).toHaveBeenCalledWith(API_ENDPOINT_PARAMS);
97
+
98
+ expect(isSuccess).toBe(true);
99
+ expect(isError).toBe(false);
100
+ expect(error).toBeNull();
101
+ expect(collections).toEqual(INFO_SUCCESS_SOME_COLLECTIONS.collections);
102
+ });
103
+
104
+ it("report info query hook doesn't fetch, when disabled", async () => {
105
+ const show = false;
106
+
107
+ mock_info_api.mockResolvedValue(INFO_SUCCESS_SOME_COLLECTIONS);
108
+ const { result, waitFor } = renderHook(
109
+ () => useReportInfo(show, API_ENDPOINT_PARAMS),
110
+ { wrapper }
111
+ );
112
+ await waitFor(() => result.current.fetchStatus == "idle");
113
+ const { isSuccess, isError, error, collections } = result.current;
114
+
115
+ expect(mock_info_api).not.toHaveBeenCalled();
116
+ expect(isSuccess).toBe(false);
117
+ expect(isError).toBe(false);
118
+ expect(error).toBeNull();
119
+ expect(collections).not.toBeDefined();
120
+ });
121
+
122
+ it("report info query hook returns no collections, when api throws error", async () => {
123
+ const show = true;
124
+
125
+ mock_info_api.mockImplementation(() => {
126
+ throw new Error("an error occurred");
127
+ });
128
+ const { result, waitFor } = renderHook(
129
+ () => useReportInfo(show, API_ENDPOINT_PARAMS),
130
+ { wrapper }
131
+ );
132
+ await waitFor(() => result.current.fetchStatus == "idle");
133
+ const { isSuccess, isError, error, collections } = result.current;
134
+
135
+ expect(mock_info_api).toHaveBeenCalledWith(API_ENDPOINT_PARAMS);
136
+ expect(isSuccess).toBe(false);
137
+ expect(isError).toBe(true);
138
+ expect((error as Error).message).toEqual("an error occurred");
139
+ expect(collections).not.toBeDefined();
140
+ });
141
+ });
142
+
143
+ describe("generate report", () => {
144
+ const mock_generate_api = jest.spyOn(AdminAPI, "requestInventoryReport");
145
+
146
+ const setResponseMessage = jest.fn();
147
+ const setShowConfirmationModal = jest.fn();
148
+ const setShowResponseModal = jest.fn();
149
+
150
+ afterEach(() => {
151
+ jest.clearAllMocks();
152
+ queryClient.clear();
153
+ });
154
+ afterAll(() => mock_generate_api.mockRestore());
155
+
156
+ it("handles api success", async () => {
157
+ mock_generate_api.mockResolvedValue(GENERATE_REPORT_SUCCESS);
158
+ const { result, waitFor } = renderHook(
159
+ () => {
160
+ const reportGenerator = useGenerateReport({
161
+ ...API_ENDPOINT_PARAMS,
162
+ setResponseMessage,
163
+ setShowResponseModal,
164
+ setShowConfirmationModal,
165
+ });
166
+ return { reportGenerator };
167
+ },
168
+ { wrapper }
169
+ );
170
+
171
+ expect(result.current.reportGenerator.isIdle).toBe(true);
172
+ expect(mock_generate_api).not.toHaveBeenCalled();
173
+ expect(setResponseMessage).not.toHaveBeenCalled();
174
+ expect(setShowResponseModal).not.toHaveBeenCalled();
175
+ expect(setShowConfirmationModal).not.toHaveBeenCalled();
176
+
177
+ act(() => result.current.reportGenerator.mutate());
178
+ await waitFor(
179
+ () =>
180
+ result.current.reportGenerator.isSuccess ||
181
+ result.current.reportGenerator.isError
182
+ );
183
+ const { isSuccess, isError, error } = result.current.reportGenerator;
184
+
185
+ expect(mock_generate_api).toHaveBeenCalledWith(API_ENDPOINT_PARAMS);
186
+
187
+ expect(isSuccess).toBe(true);
188
+ expect(isError).toBe(false);
189
+ expect(error).toBeNull();
190
+ expect(setResponseMessage).toHaveBeenCalledWith(
191
+ `✅ ${GENERATE_REPORT_SUCCESS.message}`
192
+ );
193
+ expect(setShowResponseModal).toHaveBeenCalledWith(true);
194
+ expect(setShowConfirmationModal).toHaveBeenCalledWith(false);
195
+ });
196
+
197
+ it("handles api error", async () => {
198
+ mock_generate_api.mockImplementation(() => {
199
+ throw new Error("an error occurred");
200
+ });
201
+ const { result, waitFor } = renderHook(
202
+ () => {
203
+ const reportGenerator = useGenerateReport({
204
+ ...API_ENDPOINT_PARAMS,
205
+ setResponseMessage,
206
+ setShowResponseModal,
207
+ setShowConfirmationModal,
208
+ });
209
+ return { reportGenerator };
210
+ },
211
+ { wrapper }
212
+ );
213
+
214
+ expect(result.current.reportGenerator.isIdle).toBe(true);
215
+ expect(mock_generate_api).not.toHaveBeenCalled();
216
+ expect(setResponseMessage).not.toHaveBeenCalled();
217
+ expect(setShowResponseModal).not.toHaveBeenCalled();
218
+ expect(setShowConfirmationModal).not.toHaveBeenCalled();
219
+
220
+ act(() => result.current.reportGenerator.mutate());
221
+ await waitFor(
222
+ () =>
223
+ result.current.reportGenerator.isSuccess ||
224
+ result.current.reportGenerator.isError
225
+ );
226
+ const { isSuccess, isError, error } = result.current.reportGenerator;
227
+
228
+ expect(mock_generate_api).toHaveBeenCalledWith(API_ENDPOINT_PARAMS);
229
+
230
+ expect(isSuccess).toBe(false);
231
+ expect(isError).toBe(true);
232
+ expect(error).not.toBeNull();
233
+ expect(setResponseMessage).toHaveBeenCalledWith(`❌ an error occurred`);
234
+ expect(setShowResponseModal).toHaveBeenCalledWith(true);
235
+ expect(setShowConfirmationModal).toHaveBeenCalledWith(false);
236
+ });
237
+ });
238
+ });
239
+
240
+ describe("mock server functionality", () => {
241
+ const server = setupMockServer();
242
+ beforeAll(() => server.listen());
243
+ afterAll(() => server.close());
244
+ afterEach(() => {
245
+ server.resetHandlers();
246
+ server.restoreHandlers();
247
+ });
248
+
249
+ it("returns the success value for successful report info (get) requests", async () => {
250
+ const result = await AdminAPI.getInventoryReportInfo(API_ENDPOINT_PARAMS);
251
+ expect(result).toEqual(INFO_SUCCESS_SOME_COLLECTIONS);
252
+ });
253
+ it("returns an error value for unsuccessful report info (get) requests", async () => {
254
+ server.use(
255
+ rest.get(MOCK_SERVER_API_ENDPOINT_PATH, (_, res, ctx) =>
256
+ res(ctx.status(404))
257
+ )
258
+ );
259
+ let error = undefined;
260
+ try {
261
+ await AdminAPI.getInventoryReportInfo(API_ENDPOINT_PARAMS);
262
+ } catch (e) {
263
+ error = await e;
264
+ }
265
+ expect(error?.message).toMatch("Request failed with status 404: GET ");
266
+ });
267
+
268
+ it("returns the expected value for generate report (post) requests", async () => {
269
+ const result = await AdminAPI.requestInventoryReport(API_ENDPOINT_PARAMS);
270
+ expect(result).toEqual(GENERATE_REPORT_SUCCESS);
271
+ });
272
+ it("returns an error value for unsuccessful generate report (post) requests", async () => {
273
+ server.use(
274
+ rest.post(MOCK_SERVER_API_ENDPOINT_PATH, (_, res, ctx) =>
275
+ res(ctx.status(404))
276
+ )
277
+ );
278
+ let error = undefined;
279
+ try {
280
+ await AdminAPI.requestInventoryReport(API_ENDPOINT_PARAMS);
281
+ } catch (e) {
282
+ error = await e;
283
+ }
284
+ expect(error?.message).toMatch("Request failed with status 404: POST ");
285
+ });
286
+ });
287
+
288
+ describe("component rendering", () => {
289
+ const onHide = jest.fn();
290
+ const server = setupMockServer();
291
+
292
+ beforeAll(() => server.listen());
293
+ afterAll(() => server.close());
294
+ afterEach(() => {
295
+ server.resetHandlers();
296
+ server.restoreHandlers();
297
+ onHide.mockReset();
298
+ queryClient.clear();
299
+ });
300
+
301
+ const LIBRARY = "library-short-name";
302
+ const email = "librarian@example.com";
303
+ const EMAIL_CONTEXT_PROVIDER_PROPS = { email };
304
+ const NO_EMAIL_CONTEXT_PROVIDER_PROPS = { email: undefined };
305
+
306
+ it("shows the modal when `show` is true", async () => {
307
+ const {
308
+ getAllByRole,
309
+ queryAllByRole,
310
+ rerender,
311
+ } = renderWithProviders(
312
+ <InventoryReportRequestModal
313
+ show={false}
314
+ onHide={onHide}
315
+ library={LIBRARY}
316
+ />,
317
+ { queryClient }
318
+ );
319
+ expect(queryAllByRole("dialog")).toHaveLength(0);
320
+
321
+ rerender(
322
+ <InventoryReportRequestModal
323
+ show={true}
324
+ onHide={onHide}
325
+ library={LIBRARY}
326
+ />
327
+ );
328
+ getAllByRole("dialog");
329
+ });
330
+
331
+ it("initially shows a request confirmation", () => {
332
+ const { getByRole } = renderWithProviders(
333
+ <InventoryReportRequestModal
334
+ show={true}
335
+ onHide={onHide}
336
+ library={LIBRARY}
337
+ />,
338
+ { queryClient }
339
+ );
340
+ const modalContent = getByRole("document");
341
+ const heading = within(modalContent).getByRole("heading", {
342
+ level: MODAL_HEADING_LEVEL,
343
+ });
344
+ const modalBody = modalContent.querySelector(".modal-body");
345
+
346
+ getByRole("button", { name: CONFIRM_BUTTON_CONTENT });
347
+ getByRole("button", { name: CANCEL_BUTTON_CONTENT });
348
+
349
+ expect(heading).toHaveTextContent(CONFIRMATION_MODAL_HEADING);
350
+ expect(modalBody).toHaveTextContent("inventory report will be generated");
351
+ });
352
+
353
+ it("shows admin email, when present, in request confirmation", () => {
354
+ let { getByRole } = renderWithProviders(
355
+ <InventoryReportRequestModal
356
+ show={true}
357
+ onHide={onHide}
358
+ library={LIBRARY}
359
+ />,
360
+ { queryClient, contextProviderProps: EMAIL_CONTEXT_PROVIDER_PROPS }
361
+ );
362
+ let modalBody = getByRole("document").querySelector(".modal-body");
363
+ expect(modalBody).toHaveTextContent(
364
+ "will be generated in the background and emailed to you at"
365
+ );
366
+ expect(modalBody).toHaveTextContent(email);
367
+
368
+ ({ getByRole } = renderWithProviders(
369
+ <InventoryReportRequestModal
370
+ show={true}
371
+ onHide={onHide}
372
+ library={LIBRARY}
373
+ />,
374
+ { queryClient, contextProviderProps: NO_EMAIL_CONTEXT_PROVIDER_PROPS }
375
+ ));
376
+ modalBody = getByRole("document").querySelector(".modal-body");
377
+ expect(modalBody).toHaveTextContent(
378
+ "will be generated in the background and emailed to you"
379
+ );
380
+ expect(modalBody).not.toHaveTextContent(email);
381
+ });
382
+
383
+ it("clicking 'cancel' hides the component", async () => {
384
+ const user = userEvent.setup();
385
+ let show = true;
386
+ onHide.mockImplementation(() => (show = false));
387
+
388
+ const {
389
+ getAllByRole,
390
+ getByRole,
391
+ queryAllByRole,
392
+ rerender,
393
+ } = renderWithProviders(
394
+ <InventoryReportRequestModal
395
+ show={show}
396
+ onHide={onHide}
397
+ library={LIBRARY}
398
+ />,
399
+ { queryClient }
400
+ );
401
+ getAllByRole("dialog");
402
+ expect(show).toBe(true);
403
+ expect(onHide).not.toHaveBeenCalled();
404
+
405
+ const cancelButton = getByRole("button", { name: CANCEL_BUTTON_CONTENT });
406
+ await user.click(cancelButton);
407
+
408
+ // `onHide` was called and modal elements are gone on the next render.
409
+ expect(onHide).toHaveBeenCalled();
410
+ expect(show).toBe(false);
411
+
412
+ rerender(
413
+ <InventoryReportRequestModal
414
+ show={show}
415
+ onHide={onHide}
416
+ library={LIBRARY}
417
+ />
418
+ );
419
+ expect(queryAllByRole("dialog")).toHaveLength(0);
420
+ });
421
+
422
+ it("updates confirmation message, if report info request arrives in time", async () => {
423
+ const {
424
+ getByRole,
425
+ rerender,
426
+ } = renderWithProviders(
427
+ <InventoryReportRequestModal
428
+ show={true}
429
+ onHide={onHide}
430
+ library={LIBRARY}
431
+ />,
432
+ { queryClient }
433
+ );
434
+
435
+ let modalBody = getByRole("document").querySelector(".modal-body");
436
+ expect(modalBody).toHaveTextContent(UNKNOWN_COLLECTIONS_MESSAGE);
437
+ expect(modalBody).not.toHaveTextContent(COLLECTION_NAME);
438
+
439
+ await new Promise(process.nextTick);
440
+ rerender(
441
+ <InventoryReportRequestModal
442
+ show={true}
443
+ onHide={onHide}
444
+ library={LIBRARY}
445
+ />
446
+ );
447
+
448
+ modalBody = getByRole("document").querySelector(".modal-body");
449
+ expect(modalBody).toHaveTextContent(SOME_COLLECTIONS_MESSAGE);
450
+ expect(modalBody).toHaveTextContent(COLLECTION_NAME);
451
+ });
452
+
453
+ it("disables report generation, if info indicates no collections", async () => {
454
+ server.use(
455
+ rest.get(MOCK_SERVER_API_ENDPOINT_PATH, async (_, res, ctx) => {
456
+ return res(ctx.status(200), ctx.json(INFO_SUCCESS_NO_COLLECTIONS));
457
+ })
458
+ );
459
+
460
+ const {
461
+ getByRole,
462
+ rerender,
463
+ } = renderWithProviders(
464
+ <InventoryReportRequestModal
465
+ show={true}
466
+ onHide={onHide}
467
+ library={LIBRARY}
468
+ />,
469
+ { queryClient }
470
+ );
471
+
472
+ let modalBody = getByRole("document").querySelector(".modal-body");
473
+ expect(modalBody).toHaveTextContent(UNKNOWN_COLLECTIONS_MESSAGE);
474
+ expect(modalBody).not.toHaveTextContent(COLLECTION_NAME);
475
+
476
+ let requestButton = getByRole("button", { name: CONFIRM_BUTTON_CONTENT });
477
+ let cancelButton = getByRole("button", { name: CANCEL_BUTTON_CONTENT });
478
+ expect(requestButton).toBeEnabled();
479
+ expect(cancelButton).toBeEnabled();
480
+
481
+ await new Promise(process.nextTick);
482
+ rerender(
483
+ <InventoryReportRequestModal
484
+ show={true}
485
+ onHide={onHide}
486
+ library={LIBRARY}
487
+ />
488
+ );
489
+
490
+ modalBody = getByRole("document").querySelector(".modal-body");
491
+ expect(modalBody).toHaveTextContent(NO_COLLECTIONS_MESSAGE);
492
+ expect(modalBody).not.toHaveTextContent(COLLECTION_NAME);
493
+
494
+ requestButton = getByRole("button", { name: CONFIRM_BUTTON_CONTENT });
495
+ cancelButton = getByRole("button", { name: CANCEL_BUTTON_CONTENT });
496
+ expect(requestButton).not.toBeEnabled();
497
+ expect(cancelButton).toBeEnabled();
498
+ });
499
+
500
+ it("displays minimal confirmation message, if report info request unsuccessful", async () => {
501
+ server.use(
502
+ rest.get(MOCK_SERVER_API_ENDPOINT_PATH, (_, res, ctx) =>
503
+ res.once(ctx.status(404))
504
+ )
505
+ );
506
+
507
+ const {
508
+ getByRole,
509
+ rerender,
510
+ } = renderWithProviders(
511
+ <InventoryReportRequestModal
512
+ show={true}
513
+ onHide={onHide}
514
+ library={LIBRARY}
515
+ />,
516
+ { queryClient }
517
+ );
518
+
519
+ let modalBody = getByRole("document").querySelector(".modal-body");
520
+ expect(modalBody).toHaveTextContent(UNKNOWN_COLLECTIONS_MESSAGE);
521
+ expect(modalBody).not.toHaveTextContent(COLLECTION_NAME);
522
+
523
+ await new Promise(process.nextTick);
524
+ rerender(
525
+ <InventoryReportRequestModal
526
+ show={true}
527
+ onHide={onHide}
528
+ library={LIBRARY}
529
+ />
530
+ );
531
+
532
+ modalBody = getByRole("document").querySelector(".modal-body");
533
+ expect(modalBody).toHaveTextContent(UNKNOWN_COLLECTIONS_MESSAGE);
534
+ expect(modalBody).not.toHaveTextContent(COLLECTION_NAME);
535
+ });
536
+
537
+ it("requests report generation, if request confirmed", async () => {
538
+ const user = userEvent.setup();
539
+
540
+ const {
541
+ getByRole,
542
+ rerender,
543
+ } = renderWithProviders(
544
+ <InventoryReportRequestModal
545
+ show={true}
546
+ onHide={onHide}
547
+ library={LIBRARY}
548
+ />,
549
+ { queryClient }
550
+ );
551
+
552
+ const confirmationButton = getByRole("button", {
553
+ name: CONFIRM_BUTTON_CONTENT,
554
+ });
555
+ let modalHeading = getByRole("heading", { level: MODAL_HEADING_LEVEL });
556
+ expect(modalHeading).toHaveTextContent(CONFIRMATION_MODAL_HEADING);
557
+
558
+ await user.click(confirmationButton);
559
+
560
+ rerender(
561
+ <InventoryReportRequestModal
562
+ show={true}
563
+ onHide={onHide}
564
+ library={LIBRARY}
565
+ />
566
+ );
567
+
568
+ getByRole("button", { name: ACK_RESPONSE_BUTTON_CONTENT });
569
+ modalHeading = getByRole("heading", { level: MODAL_HEADING_LEVEL });
570
+ expect(modalHeading).toHaveTextContent(ACK_RESPONSE_HEADING);
571
+ });
572
+
573
+ it("displays success message, when request is successful", async () => {
574
+ const user = userEvent.setup();
575
+
576
+ const {
577
+ getByRole,
578
+ rerender,
579
+ } = renderWithProviders(
580
+ <InventoryReportRequestModal
581
+ show={true}
582
+ onHide={onHide}
583
+ library={LIBRARY}
584
+ />,
585
+ { queryClient }
586
+ );
587
+
588
+ const confirmationButton = getByRole("button", {
589
+ name: CONFIRM_BUTTON_CONTENT,
590
+ });
591
+ await user.click(confirmationButton);
592
+
593
+ rerender(
594
+ <InventoryReportRequestModal
595
+ show={true}
596
+ onHide={onHide}
597
+ library={LIBRARY}
598
+ />
599
+ );
600
+
601
+ getByRole("button", { name: ACK_RESPONSE_BUTTON_CONTENT });
602
+ const modalBody = getByRole("document").querySelector(".modal-body");
603
+ expect(modalBody).toHaveTextContent(
604
+ `✅ ${GENERATE_REPORT_SUCCESS.message}`
605
+ );
606
+ });
607
+
608
+ it("displays error message, when request is unsuccessful", async () => {
609
+ server.use(
610
+ rest.post(MOCK_SERVER_API_ENDPOINT_PATH, (_, res, ctx) =>
611
+ res(ctx.status(404))
612
+ )
613
+ );
614
+ const user = userEvent.setup();
615
+
616
+ const {
617
+ getByRole,
618
+ rerender,
619
+ } = renderWithProviders(
620
+ <InventoryReportRequestModal
621
+ show={true}
622
+ onHide={onHide}
623
+ library={LIBRARY}
624
+ />,
625
+ { queryClient }
626
+ );
627
+
628
+ const confirmationButton = getByRole("button", {
629
+ name: CONFIRM_BUTTON_CONTENT,
630
+ });
631
+ await user.click(confirmationButton);
632
+
633
+ rerender(
634
+ <InventoryReportRequestModal
635
+ show={true}
636
+ onHide={onHide}
637
+ library={LIBRARY}
638
+ />
639
+ );
640
+
641
+ getByRole("button", { name: ACK_RESPONSE_BUTTON_CONTENT });
642
+ const modalBody = getByRole("document").querySelector(".modal-body");
643
+ expect(modalBody).toHaveTextContent(
644
+ "❌ Request failed with status 404: POST"
645
+ );
646
+ });
647
+ });
648
+ });