@thepalaceproject/circulation-admin 1.22.0-post.5 → 1.22.0-post.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"react-dom": "^16.8.6",
|
|
61
61
|
"react-redux": "^7.2.9",
|
|
62
62
|
"react-router": "^3.2.0",
|
|
63
|
-
"recharts": "^
|
|
63
|
+
"recharts": "^2.12.7",
|
|
64
64
|
"redux": "^4.2.1",
|
|
65
65
|
"redux-thunk": "^2.4.2",
|
|
66
66
|
"request": "^2.85.0",
|
|
@@ -119,6 +119,7 @@
|
|
|
119
119
|
"react-axe": "^3.3.0",
|
|
120
120
|
"react-test-renderer": "^16.14.0",
|
|
121
121
|
"redux-mock-store": "^1.5.4",
|
|
122
|
+
"resize-observer-polyfill": "^1.5.1",
|
|
122
123
|
"sass": "^1.64.2",
|
|
123
124
|
"sass-lint": "^1.13.1",
|
|
124
125
|
"sass-loader": "^13.2.0",
|
|
@@ -149,5 +150,5 @@
|
|
|
149
150
|
"*.{js,jsx,ts,tsx,css,md}": "prettier --write",
|
|
150
151
|
"*.{js,css,md}": "prettier --write"
|
|
151
152
|
},
|
|
152
|
-
"version": "1.22.0-post.
|
|
153
|
+
"version": "1.22.0-post.6"
|
|
153
154
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { render } from "@testing-library/react";
|
|
3
|
-
import LibraryStats
|
|
4
|
-
ALL_LIBRARIES_HEADING,
|
|
5
|
-
} from "../../../src/components/LibraryStats";
|
|
3
|
+
import { ALL_LIBRARIES_HEADING } from "../../../src/components/LibraryStats";
|
|
6
4
|
import { CustomTooltip } from "../../../src/components/StatsCollectionsBarChart";
|
|
7
5
|
import {
|
|
8
6
|
componentWithProviders,
|
|
@@ -28,6 +26,8 @@ import { api } from "../../../src/features/api/apiSlice";
|
|
|
28
26
|
|
|
29
27
|
const normalizedData = normalizeStatistics(statisticsApiResponseData);
|
|
30
28
|
|
|
29
|
+
global.ResizeObserver = require("resize-observer-polyfill");
|
|
30
|
+
|
|
31
31
|
describe("Dashboard Statistics", () => {
|
|
32
32
|
// NB: This adds test to the already existing tests in:
|
|
33
33
|
// - `src/components/__tests__/LibraryStats-test.tsx`.
|
|
@@ -274,7 +274,7 @@ describe("Dashboard Statistics", () => {
|
|
|
274
274
|
});
|
|
275
275
|
});
|
|
276
276
|
|
|
277
|
-
it("shows the right groups
|
|
277
|
+
it("shows the right groups with/out a library", () => {
|
|
278
278
|
const { getAllByRole } = renderWithProviders(<Stats />);
|
|
279
279
|
|
|
280
280
|
const groupHeadings = getAllByRole("heading", { level: 3 });
|
|
@@ -290,282 +290,354 @@ describe("Dashboard Statistics", () => {
|
|
|
290
290
|
});
|
|
291
291
|
});
|
|
292
292
|
});
|
|
293
|
-
});
|
|
294
293
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const fakeQuickSightHref = "https://example.com/fakeQS";
|
|
309
|
-
const baseContextProviderProps = {
|
|
310
|
-
csrfToken: "",
|
|
311
|
-
featureFlags: { reportsOnlyForSysadmins: false },
|
|
312
|
-
quicksightPagePath: fakeQuickSightHref,
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
const renderFor = (
|
|
316
|
-
onlySysadmins: boolean,
|
|
317
|
-
roles: { role: string; library?: string }[]
|
|
318
|
-
) => {
|
|
319
|
-
const contextProviderProps: ContextProviderProps = {
|
|
320
|
-
...baseContextProviderProps,
|
|
321
|
-
featureFlags: { reportsOnlyForSysadmins: onlySysadmins },
|
|
322
|
-
roles,
|
|
323
|
-
};
|
|
294
|
+
describe("shows the correct UI with/out sysadmin role", () => {
|
|
295
|
+
const systemAdmin = [{ role: "system" }];
|
|
296
|
+
const managerAll = [{ role: "manager-all" }];
|
|
297
|
+
const librarianAll = [{ role: "librarian-all" }];
|
|
298
|
+
|
|
299
|
+
const collectionNames = [
|
|
300
|
+
"New BiblioBoard Test",
|
|
301
|
+
"New Bibliotheca Test Collection",
|
|
302
|
+
"Palace Bookshelf",
|
|
303
|
+
"TEST Baker & Taylor",
|
|
304
|
+
"TEST Palace Marketplace",
|
|
305
|
+
];
|
|
324
306
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
307
|
+
it("tests BarChart component", () => {
|
|
308
|
+
const contextProviderProps: Partial<ContextProviderProps> = {
|
|
309
|
+
roles: systemAdmin,
|
|
310
|
+
dashboardCollectionsBarChart: { width: 800 },
|
|
311
|
+
};
|
|
312
|
+
const { container, getByRole } = renderWithProviders(
|
|
313
|
+
<Stats library={sampleLibraryKey} />,
|
|
314
|
+
{ contextProviderProps }
|
|
315
|
+
);
|
|
333
316
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return result;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
it("shows inventory reports only for sysadmins, if feature flag set", async () => {
|
|
346
|
-
// If the feature flag is set, the button should be visible only to sysadmins.
|
|
347
|
-
expect(renderFor(true, systemAdmin)).not.toBeNull();
|
|
348
|
-
expect(renderFor(true, managerAll)).toBeNull();
|
|
349
|
-
expect(renderFor(true, librarianAll)).toBeNull();
|
|
350
|
-
// If the feature flag is false, the button should be visible to all users.
|
|
351
|
-
expect(renderFor(false, systemAdmin)).not.toBeNull();
|
|
352
|
-
expect(renderFor(false, managerAll)).not.toBeNull();
|
|
353
|
-
expect(renderFor(false, librarianAll)).not.toBeNull();
|
|
354
|
-
});
|
|
355
|
-
});
|
|
317
|
+
const collectionsHeading = getByRole("heading", {
|
|
318
|
+
level: 3,
|
|
319
|
+
name: statGroupToHeading.collections,
|
|
320
|
+
});
|
|
321
|
+
const collectionsGroup = collectionsHeading.closest(".stat-group");
|
|
322
|
+
const barChartAxisTick = collectionsGroup.querySelectorAll(
|
|
323
|
+
".recharts-cartesian-axis-tick"
|
|
324
|
+
);
|
|
356
325
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
meteredLicenseTitles: 7974,
|
|
363
|
-
meteredLicensesAvailable: 75446,
|
|
364
|
-
meteredLicensesOwned: 301541,
|
|
365
|
-
openAccessTitles: 0,
|
|
366
|
-
titles: 7974,
|
|
367
|
-
unlimitedLicenseTitles: 0,
|
|
368
|
-
};
|
|
369
|
-
const perMediumInventory = {
|
|
370
|
-
Audio: {
|
|
371
|
-
availableTitles: 148,
|
|
372
|
-
licensedTitles: 165,
|
|
373
|
-
meteredLicenseTitles: 165,
|
|
374
|
-
meteredLicensesAvailable: 221,
|
|
375
|
-
meteredLicensesOwned: 392,
|
|
376
|
-
openAccessTitles: 0,
|
|
377
|
-
titles: 165,
|
|
378
|
-
unlimitedLicenseTitles: 0,
|
|
379
|
-
},
|
|
380
|
-
Book: {
|
|
381
|
-
availableTitles: 7805,
|
|
382
|
-
licensedTitles: 7809,
|
|
383
|
-
meteredLicenseTitles: 7809,
|
|
384
|
-
meteredLicensesAvailable: 75225,
|
|
385
|
-
meteredLicensesOwned: 301149,
|
|
386
|
-
openAccessTitles: 0,
|
|
387
|
-
titles: 7809,
|
|
388
|
-
unlimitedLicenseTitles: 0,
|
|
389
|
-
},
|
|
390
|
-
};
|
|
391
|
-
const defaultChartItemWithoutPerMediumInventory = {
|
|
392
|
-
name: defaultLabel,
|
|
393
|
-
...summaryInventory,
|
|
394
|
-
};
|
|
395
|
-
const defaultChartItemWithPerMediumInventory = {
|
|
396
|
-
...defaultChartItemWithoutPerMediumInventory,
|
|
397
|
-
_by_medium: perMediumInventory,
|
|
398
|
-
};
|
|
399
|
-
const defaultPayload = [
|
|
400
|
-
{
|
|
401
|
-
fill: "#606060",
|
|
402
|
-
dataKey: "meteredLicenseTitles",
|
|
403
|
-
name: "Metered License Titles",
|
|
404
|
-
color: "#606060",
|
|
405
|
-
value: 7974,
|
|
406
|
-
},
|
|
407
|
-
{
|
|
408
|
-
fill: "#404040",
|
|
409
|
-
dataKey: "unlimitedLicenseTitles",
|
|
410
|
-
name: "Unlimited License Titles",
|
|
411
|
-
color: "#404040",
|
|
412
|
-
value: 0,
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
fill: "#202020",
|
|
416
|
-
dataKey: "openAccessTitles",
|
|
417
|
-
name: "Open Access Titles",
|
|
418
|
-
color: "#202020",
|
|
419
|
-
value: 0,
|
|
420
|
-
},
|
|
421
|
-
];
|
|
422
|
-
|
|
423
|
-
const populateTooltipProps = ({
|
|
424
|
-
active = true,
|
|
425
|
-
label = defaultLabel,
|
|
426
|
-
payload = [],
|
|
427
|
-
chartItem = undefined,
|
|
428
|
-
}) => {
|
|
429
|
-
const constructedChartItem = !chartItem
|
|
430
|
-
? chartItem
|
|
431
|
-
: {
|
|
432
|
-
...chartItem,
|
|
433
|
-
name: label,
|
|
434
|
-
};
|
|
435
|
-
const constructedPayload = payload.map((entry) => ({
|
|
436
|
-
...entry,
|
|
437
|
-
payload: constructedChartItem,
|
|
438
|
-
}));
|
|
439
|
-
return {
|
|
440
|
-
active,
|
|
441
|
-
label,
|
|
442
|
-
payload: constructedPayload,
|
|
443
|
-
};
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Helper function to test passing tests for a tooltip
|
|
448
|
-
*
|
|
449
|
-
* @param tooltipProps - passed to the <CustomTooltip /> component
|
|
450
|
-
* @param expectedInventoryItemText - the expected inventory item text content
|
|
451
|
-
*/
|
|
452
|
-
const expectPassingTestsForActiveTooltip = ({
|
|
453
|
-
tooltipProps,
|
|
454
|
-
expectedInventoryItemText,
|
|
455
|
-
}) => {
|
|
456
|
-
const { container, getByRole } = render(
|
|
457
|
-
<CustomTooltip {...tooltipProps} />
|
|
458
|
-
);
|
|
459
|
-
const tooltipContent = container.querySelector(".customTooltip");
|
|
460
|
-
|
|
461
|
-
const detail = tooltipContent.querySelector(".customTooltipDetail");
|
|
462
|
-
const detailChildren = detail.children;
|
|
463
|
-
const heading = getByRole("heading", { level: 1, name: "Collection X" });
|
|
464
|
-
const items = tooltipContent.querySelectorAll("p.customTooltipItem");
|
|
465
|
-
const divider = detail.querySelector("hr");
|
|
466
|
-
|
|
467
|
-
expect(heading).toHaveTextContent("Collection X");
|
|
468
|
-
|
|
469
|
-
// Eight (8) metrics in the following order.
|
|
470
|
-
expect(items).toHaveLength(8);
|
|
471
|
-
// The expected inventory item labels array should be the same length.
|
|
472
|
-
expect(expectedInventoryItemText).toHaveLength(items.length);
|
|
473
|
-
// And the items should contain at least the expected text.
|
|
474
|
-
Array.from(items).forEach((item, index) => {
|
|
475
|
-
expect(item).toHaveTextContent(expectedInventoryItemText[index]);
|
|
476
|
-
});
|
|
326
|
+
// We expect the first ticks to be along the y-axis, which
|
|
327
|
+
// should have our collection names.
|
|
328
|
+
collectionNames.forEach((name, index) => {
|
|
329
|
+
expect(barChartAxisTick[index]).toHaveTextContent(name);
|
|
330
|
+
});
|
|
477
331
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
expect(detailChildren).toHaveLength(10);
|
|
481
|
-
expect(heading).toEqual(detailChildren[0]);
|
|
482
|
-
expect(items[0]).toEqual(detailChildren[1]);
|
|
483
|
-
expect(items[2]).toEqual(detailChildren[3]);
|
|
484
|
-
expect(divider).toEqual(detailChildren[4]);
|
|
485
|
-
expect(items[3]).toEqual(detailChildren[5]);
|
|
486
|
-
expect(items[7]).toEqual(detailChildren[9]);
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
it("should not render when active is false", () => {
|
|
490
|
-
// Recharts sticks some extra props
|
|
491
|
-
const tooltipProps = populateTooltipProps({
|
|
492
|
-
active: false,
|
|
493
|
-
chartItem: defaultChartItemWithPerMediumInventory,
|
|
494
|
-
payload: defaultPayload,
|
|
332
|
+
// Clean up the container after each render.
|
|
333
|
+
document.body.removeChild(container);
|
|
495
334
|
});
|
|
496
335
|
|
|
497
|
-
|
|
498
|
-
|
|
336
|
+
it("shows collection bar chart for sysadmins, but list for others", () => {
|
|
337
|
+
// We'll use this function to test multiple scenarios.
|
|
338
|
+
const testFor = (
|
|
339
|
+
expectBarChart: boolean,
|
|
340
|
+
roles: { role: string; library?: string }[]
|
|
341
|
+
) => {
|
|
342
|
+
const contextProviderProps: Partial<ContextProviderProps> = { roles };
|
|
343
|
+
const { container, getByRole } = renderWithProviders(
|
|
344
|
+
<Stats library={sampleLibraryKey} />,
|
|
345
|
+
{ contextProviderProps }
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const collectionsHeading = getByRole("heading", {
|
|
349
|
+
level: 3,
|
|
350
|
+
name: statGroupToHeading.collections,
|
|
351
|
+
});
|
|
352
|
+
const collectionsGroup = collectionsHeading.closest(".stat-group");
|
|
353
|
+
|
|
354
|
+
if (expectBarChart) {
|
|
355
|
+
collectionsGroup.querySelector(".recharts-responsive-container");
|
|
356
|
+
} else {
|
|
357
|
+
const list = collectionsGroup.querySelector("ul");
|
|
358
|
+
const items = list.querySelectorAll("li");
|
|
359
|
+
expect(items.length).toBe(collectionNames.length);
|
|
360
|
+
|
|
361
|
+
collectionNames.forEach((name: string) => {
|
|
362
|
+
expect(list).toHaveTextContent(name);
|
|
363
|
+
});
|
|
364
|
+
items.forEach((item, index) => {
|
|
365
|
+
expect(item).toHaveTextContent(collectionNames[index]);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Clean up the container after each render.
|
|
370
|
+
document.body.removeChild(container);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// If the feature flag is set, the button should be visible only to sysadmins.
|
|
374
|
+
testFor(true, systemAdmin);
|
|
375
|
+
testFor(false, managerAll);
|
|
376
|
+
testFor(false, librarianAll);
|
|
377
|
+
});
|
|
499
378
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
379
|
+
it("shows inventory reports only for sysadmins, if sysadmin-only flag set", () => {
|
|
380
|
+
const fakeQuickSightHref = "https://example.com/fakeQS";
|
|
381
|
+
|
|
382
|
+
// We'll use this function to test multiple scenarios.
|
|
383
|
+
const renderFor = (
|
|
384
|
+
onlySysadmins: boolean,
|
|
385
|
+
roles: { role: string; library?: string }[]
|
|
386
|
+
) => {
|
|
387
|
+
const contextProviderProps: Partial<ContextProviderProps> = {
|
|
388
|
+
featureFlags: { reportsOnlyForSysadmins: onlySysadmins },
|
|
389
|
+
roles,
|
|
390
|
+
quicksightPagePath: fakeQuickSightHref,
|
|
391
|
+
};
|
|
392
|
+
const { container, getByRole, queryByRole } = renderWithProviders(
|
|
393
|
+
<Stats library={sampleLibraryKey} />,
|
|
394
|
+
{
|
|
395
|
+
contextProviderProps,
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
// We should always render a Usage reports group when a library is specified.
|
|
400
|
+
getByRole("heading", {
|
|
401
|
+
level: 3,
|
|
402
|
+
name: statGroupToHeading.usageReports,
|
|
403
|
+
});
|
|
404
|
+
const usageReportLink = getByRole("link", { name: /View Usage/i });
|
|
405
|
+
expect(usageReportLink).toHaveAttribute("href", fakeQuickSightHref);
|
|
406
|
+
|
|
407
|
+
const result = queryByRole("button", { name: /Request Report/i });
|
|
408
|
+
|
|
409
|
+
// Clean up the container after each render.
|
|
410
|
+
document.body.removeChild(container);
|
|
411
|
+
return result;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// If the feature flag is set, the button should be visible only to sysadmins.
|
|
415
|
+
expect(renderFor(true, systemAdmin)).not.toBeNull();
|
|
416
|
+
expect(renderFor(true, managerAll)).toBeNull();
|
|
417
|
+
expect(renderFor(true, librarianAll)).toBeNull();
|
|
418
|
+
// If the feature flag is false, the button should be visible to all users.
|
|
419
|
+
expect(renderFor(false, systemAdmin)).not.toBeNull();
|
|
420
|
+
expect(renderFor(false, managerAll)).not.toBeNull();
|
|
421
|
+
expect(renderFor(false, librarianAll)).not.toBeNull();
|
|
507
422
|
});
|
|
423
|
+
});
|
|
508
424
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
425
|
+
describe("charting - custom tooltip", () => {
|
|
426
|
+
const defaultLabel = "Collection X";
|
|
427
|
+
const summaryInventory = {
|
|
428
|
+
availableTitles: 7953,
|
|
429
|
+
licensedTitles: 7974,
|
|
430
|
+
meteredLicenseTitles: 7974,
|
|
431
|
+
meteredLicensesAvailable: 75446,
|
|
432
|
+
meteredLicensesOwned: 301541,
|
|
433
|
+
openAccessTitles: 0,
|
|
434
|
+
titles: 7974,
|
|
435
|
+
unlimitedLicenseTitles: 0,
|
|
436
|
+
};
|
|
437
|
+
const perMediumInventory = {
|
|
438
|
+
Audio: {
|
|
439
|
+
availableTitles: 148,
|
|
440
|
+
licensedTitles: 165,
|
|
441
|
+
meteredLicenseTitles: 165,
|
|
442
|
+
meteredLicensesAvailable: 221,
|
|
443
|
+
meteredLicensesOwned: 392,
|
|
444
|
+
openAccessTitles: 0,
|
|
445
|
+
titles: 165,
|
|
446
|
+
unlimitedLicenseTitles: 0,
|
|
447
|
+
},
|
|
448
|
+
Book: {
|
|
449
|
+
availableTitles: 7805,
|
|
450
|
+
licensedTitles: 7809,
|
|
451
|
+
meteredLicenseTitles: 7809,
|
|
452
|
+
meteredLicensesAvailable: 75225,
|
|
453
|
+
meteredLicensesOwned: 301149,
|
|
454
|
+
openAccessTitles: 0,
|
|
455
|
+
titles: 7809,
|
|
456
|
+
unlimitedLicenseTitles: 0,
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
const defaultChartItemWithoutPerMediumInventory = {
|
|
460
|
+
name: defaultLabel,
|
|
461
|
+
...summaryInventory,
|
|
462
|
+
};
|
|
463
|
+
const defaultChartItemWithPerMediumInventory = {
|
|
464
|
+
...defaultChartItemWithoutPerMediumInventory,
|
|
465
|
+
_by_medium: perMediumInventory,
|
|
466
|
+
};
|
|
467
|
+
const defaultPayload = [
|
|
468
|
+
{
|
|
469
|
+
fill: "#606060",
|
|
470
|
+
dataKey: "meteredLicenseTitles",
|
|
471
|
+
name: "Metered License Titles",
|
|
472
|
+
color: "#606060",
|
|
473
|
+
value: 7974,
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
fill: "#404040",
|
|
477
|
+
dataKey: "unlimitedLicenseTitles",
|
|
478
|
+
name: "Unlimited License Titles",
|
|
479
|
+
color: "#404040",
|
|
480
|
+
value: 0,
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
fill: "#202020",
|
|
484
|
+
dataKey: "openAccessTitles",
|
|
485
|
+
name: "Open Access Titles",
|
|
486
|
+
color: "#202020",
|
|
487
|
+
value: 0,
|
|
488
|
+
},
|
|
518
489
|
];
|
|
519
490
|
|
|
520
|
-
|
|
491
|
+
const populateTooltipProps = ({
|
|
492
|
+
active = true,
|
|
493
|
+
label = defaultLabel,
|
|
494
|
+
payload = [],
|
|
495
|
+
chartItem = undefined,
|
|
496
|
+
}) => {
|
|
497
|
+
const constructedChartItem = !chartItem
|
|
498
|
+
? chartItem
|
|
499
|
+
: {
|
|
500
|
+
...chartItem,
|
|
501
|
+
name: label,
|
|
502
|
+
};
|
|
503
|
+
const constructedPayload = payload.map((entry) => ({
|
|
504
|
+
...entry,
|
|
505
|
+
payload: constructedChartItem,
|
|
506
|
+
}));
|
|
507
|
+
return {
|
|
508
|
+
active,
|
|
509
|
+
label,
|
|
510
|
+
payload: constructedPayload,
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Helper function to test passing tests for a tooltip
|
|
516
|
+
*
|
|
517
|
+
* @param tooltipProps - passed to the <CustomTooltip /> component
|
|
518
|
+
* @param expectedInventoryItemText - the expected inventory item text content
|
|
519
|
+
*/
|
|
520
|
+
const expectPassingTestsForActiveTooltip = ({
|
|
521
521
|
tooltipProps,
|
|
522
522
|
expectedInventoryItemText,
|
|
523
|
+
}) => {
|
|
524
|
+
const { container, getByRole } = render(
|
|
525
|
+
<CustomTooltip {...tooltipProps} />
|
|
526
|
+
);
|
|
527
|
+
const tooltipContent = container.querySelector(".customTooltip");
|
|
528
|
+
|
|
529
|
+
const detail = tooltipContent.querySelector(".customTooltipDetail");
|
|
530
|
+
const detailChildren = detail.children;
|
|
531
|
+
const heading = getByRole("heading", {
|
|
532
|
+
level: 1,
|
|
533
|
+
name: "Collection X",
|
|
534
|
+
});
|
|
535
|
+
const items = tooltipContent.querySelectorAll("p.customTooltipItem");
|
|
536
|
+
const divider = detail.querySelector("hr");
|
|
537
|
+
|
|
538
|
+
expect(heading).toHaveTextContent("Collection X");
|
|
539
|
+
|
|
540
|
+
// Eight (8) metrics in the following order.
|
|
541
|
+
expect(items).toHaveLength(8);
|
|
542
|
+
// The expected inventory item labels array should be the same length.
|
|
543
|
+
expect(expectedInventoryItemText).toHaveLength(items.length);
|
|
544
|
+
// And the items should contain at least the expected text.
|
|
545
|
+
Array.from(items).forEach((item, index) => {
|
|
546
|
+
expect(item).toHaveTextContent(expectedInventoryItemText[index]);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// The heading should be at the top and the divider (`hr`)
|
|
550
|
+
// should be between the third and fourth statistics.
|
|
551
|
+
expect(detailChildren).toHaveLength(10);
|
|
552
|
+
expect(heading).toEqual(detailChildren[0]);
|
|
553
|
+
expect(items[0]).toEqual(detailChildren[1]);
|
|
554
|
+
expect(items[2]).toEqual(detailChildren[3]);
|
|
555
|
+
expect(divider).toEqual(detailChildren[4]);
|
|
556
|
+
expect(items[3]).toEqual(detailChildren[5]);
|
|
557
|
+
expect(items[7]).toEqual(detailChildren[9]);
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
it("should not render when active is false", () => {
|
|
561
|
+
// Recharts sticks some extra props
|
|
562
|
+
const tooltipProps = populateTooltipProps({
|
|
563
|
+
active: false,
|
|
564
|
+
chartItem: defaultChartItemWithPerMediumInventory,
|
|
565
|
+
payload: defaultPayload,
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
const { container } = render(<CustomTooltip {...tooltipProps} />);
|
|
569
|
+
const tooltipContent = container.querySelectorAll(".customTooltip");
|
|
570
|
+
|
|
571
|
+
expect(tooltipContent).toHaveLength(0);
|
|
523
572
|
});
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
});
|
|
573
|
+
it("should render when active is true", () => {
|
|
574
|
+
const tooltipProps = populateTooltipProps({
|
|
575
|
+
active: true,
|
|
576
|
+
chartItem: defaultChartItemWithoutPerMediumInventory,
|
|
577
|
+
payload: defaultPayload,
|
|
578
|
+
});
|
|
531
579
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
580
|
+
const expectedInventoryItemText = [
|
|
581
|
+
"Titles:",
|
|
582
|
+
"Available Titles:",
|
|
583
|
+
"Metered License Titles:",
|
|
584
|
+
"Licensed Titles:",
|
|
585
|
+
"Metered Licenses Available:",
|
|
586
|
+
"Metered Licenses Owned:",
|
|
587
|
+
"Open Access Titles:",
|
|
588
|
+
"Unlimited License Titles:",
|
|
589
|
+
];
|
|
542
590
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
591
|
+
expectPassingTestsForActiveTooltip({
|
|
592
|
+
tooltipProps,
|
|
593
|
+
expectedInventoryItemText,
|
|
594
|
+
});
|
|
546
595
|
});
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
596
|
+
it("should render without per-medium inventory", () => {
|
|
597
|
+
const tooltipProps = populateTooltipProps({
|
|
598
|
+
active: true,
|
|
599
|
+
chartItem: defaultChartItemWithoutPerMediumInventory,
|
|
600
|
+
payload: defaultPayload,
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
const expectedInventoryItemText = [
|
|
604
|
+
"Titles: 7,974",
|
|
605
|
+
"Available Titles: 7,953",
|
|
606
|
+
"Metered License Titles: 7,974",
|
|
607
|
+
"Licensed Titles: 7,974",
|
|
608
|
+
"Metered Licenses Available: 75,446",
|
|
609
|
+
"Metered Licenses Owned: 301,541",
|
|
610
|
+
"Open Access Titles: 0",
|
|
611
|
+
"Unlimited License Titles: 0",
|
|
612
|
+
];
|
|
613
|
+
|
|
614
|
+
expectPassingTestsForActiveTooltip({
|
|
615
|
+
tooltipProps,
|
|
616
|
+
expectedInventoryItemText,
|
|
617
|
+
});
|
|
553
618
|
});
|
|
619
|
+
it("should render additional detail with per-medium inventory", () => {
|
|
620
|
+
const tooltipProps = populateTooltipProps({
|
|
621
|
+
active: true,
|
|
622
|
+
chartItem: defaultChartItemWithPerMediumInventory,
|
|
623
|
+
payload: defaultPayload,
|
|
624
|
+
});
|
|
554
625
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
626
|
+
const expectedInventoryItemText = [
|
|
627
|
+
"Titles: 7,974 (Audio: 165, Book: 7,809)",
|
|
628
|
+
"Available Titles: 7,953 (Audio: 148, Book: 7,805)",
|
|
629
|
+
"Metered License Titles: 7,974 (Audio: 165, Book: 7,809)",
|
|
630
|
+
"Licensed Titles: 7,974 (Audio: 165, Book: 7,809)",
|
|
631
|
+
"Metered Licenses Available: 75,446 (Audio: 221, Book: 75,225)",
|
|
632
|
+
"Metered Licenses Owned: 301,541 (Audio: 392, Book: 301,149)",
|
|
633
|
+
"Open Access Titles: 0",
|
|
634
|
+
"Unlimited License Titles: 0",
|
|
635
|
+
];
|
|
565
636
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
637
|
+
expectPassingTestsForActiveTooltip({
|
|
638
|
+
tooltipProps,
|
|
639
|
+
expectedInventoryItemText,
|
|
640
|
+
});
|
|
569
641
|
});
|
|
570
642
|
});
|
|
571
643
|
});
|
|
@@ -23,7 +23,7 @@ const defaultReduxStore = store;
|
|
|
23
23
|
|
|
24
24
|
// The `csrfToken` context provider prop is required, so we provide
|
|
25
25
|
// a default value here, so it can be easily merged with other props.
|
|
26
|
-
const
|
|
26
|
+
const requiredContextProviderProps: ContextProviderProps = {
|
|
27
27
|
csrfToken: "",
|
|
28
28
|
featureFlags: defaultFeatureFlags,
|
|
29
29
|
};
|
|
@@ -49,7 +49,7 @@ export const componentWithProviders = ({
|
|
|
49
49
|
queryClient = new QueryClient(),
|
|
50
50
|
}: TestProviderWrapperOptions = {}): React.FunctionComponent => {
|
|
51
51
|
const effectiveContextProviderProps = {
|
|
52
|
-
...
|
|
52
|
+
...requiredContextProviderProps,
|
|
53
53
|
...contextProviderProps,
|
|
54
54
|
...reduxProviderProps.store, // Context and Redux Provider stores must match.
|
|
55
55
|
};
|