@thepalaceproject/circulation-admin 0.0.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.
Files changed (72) hide show
  1. package/.eslintrc +59 -0
  2. package/.node-version +1 -0
  3. package/.nvmrc +1 -0
  4. package/.prettierrc.json +10 -0
  5. package/.sass-lint.yml +37 -0
  6. package/CHANGELOG.md +946 -0
  7. package/README.md +155 -0
  8. package/dist/060b2710bdbbe3dfe48b58d59bd5f1fb.svg +288 -0
  9. package/dist/0db1520f47986b6c755a.svg +1 -0
  10. package/dist/1e59d2330b4c6deb84b3.ttf +0 -0
  11. package/dist/20fd1704ea223900efa9.woff2 +0 -0
  12. package/dist/4692b9ec53fd5972caa2.ttf +0 -0
  13. package/dist/5be1347c682810f199c7.eot +0 -0
  14. package/dist/6563aa3790be8329e4f2.svg +1 -0
  15. package/dist/82b1212e45a2bc35dd73.woff +0 -0
  16. package/dist/8b43027f47b20503057d.eot +0 -0
  17. package/dist/PalaceCollectionManagerLogo.svg +122 -0
  18. package/dist/be810be3a3e14c682a25.woff2 +0 -0
  19. package/dist/c1e38fd9e0e74ba58f7a2b77ef29fdd3.svg +2671 -0
  20. package/dist/circulation-admin.css +6841 -0
  21. package/dist/circulation-admin.js +2 -0
  22. package/dist/circulation-admin.js.LICENSE.txt +153 -0
  23. package/dist/f691f37e57f04c152e23.woff +0 -0
  24. package/jest.config.js +15 -0
  25. package/jest.polyfills.js +12 -0
  26. package/nightwatch.json +58 -0
  27. package/package.json +155 -0
  28. package/pull_request_template.md +22 -0
  29. package/requirements-ci.txt +1 -0
  30. package/testReporter.js +31 -0
  31. package/tests/__data__/statisticsApiResponseData.ts +327 -0
  32. package/tests/__mocks__/fileMock.js +1 -0
  33. package/tests/__mocks__/styleMock.js +1 -0
  34. package/tests/browser/README.md +19 -0
  35. package/tests/browser/assertions/noError.js +38 -0
  36. package/tests/browser/commands/goHome.js +13 -0
  37. package/tests/browser/commands/signIn.js +18 -0
  38. package/tests/browser/globals.js.sample +5 -0
  39. package/tests/browser/navigate.js +294 -0
  40. package/tests/browser/pages/book.js +21 -0
  41. package/tests/browser/pages/catalog.js +24 -0
  42. package/tests/browser/pages/login.js +11 -0
  43. package/tests/browser/redirect.js +104 -0
  44. package/tests/browser/signInFailure.js +22 -0
  45. package/tests/jest/README.md +6 -0
  46. package/tests/jest/api/admin.test.ts +60 -0
  47. package/tests/jest/businessRules/roleBasedAccess.test.ts +250 -0
  48. package/tests/jest/components/AdvancedSearchBuilder.test.tsx +38 -0
  49. package/tests/jest/components/BookEditor.test.tsx +240 -0
  50. package/tests/jest/components/CirculationEventsDownload.test.tsx +65 -0
  51. package/tests/jest/components/CustomLists.test.tsx +203 -0
  52. package/tests/jest/components/EditableInput.test.tsx +64 -0
  53. package/tests/jest/components/IndividualAdminEditForm.test.tsx +128 -0
  54. package/tests/jest/components/InventoryReportRequestModal.test.tsx +652 -0
  55. package/tests/jest/components/Lane.test.tsx +78 -0
  56. package/tests/jest/components/LaneEditor.test.tsx +148 -0
  57. package/tests/jest/components/ProtocolFormField.test.tsx +37 -0
  58. package/tests/jest/components/QuicksightDashboard.test.tsx +67 -0
  59. package/tests/jest/components/Stats.test.tsx +699 -0
  60. package/tests/jest/context/AppContext.test.tsx +113 -0
  61. package/tests/jest/features/book.test.ts +396 -0
  62. package/tests/jest/jest-setup.ts +1 -0
  63. package/tests/jest/sample/sample.test.js +3 -0
  64. package/tests/jest/testUtils/renderWithContext.tsx +38 -0
  65. package/tests/jest/testUtils/withProviders.tsx +92 -0
  66. package/tests/jest/utils/NoCacheDataFetcher.test.ts +75 -0
  67. package/tsconfig.json +25 -0
  68. package/tslint.json +56 -0
  69. package/webpack.common.js +72 -0
  70. package/webpack.dev-server.config.js +215 -0
  71. package/webpack.dev.config.js +9 -0
  72. package/webpack.prod.config.js +8 -0
@@ -0,0 +1,78 @@
1
+ import * as React from "react";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { stub } from "sinon";
4
+ import { LaneData } from "../../../src/interfaces";
5
+ import Lane from "../../../src/components/Lane";
6
+
7
+ // Mock the Link component from React Router, so we can verify that it gets rendered with the
8
+ // expected props. This serves as an example of how to do something analogous to Enzyme's shallow
9
+ // rendering, when we don't want/need to render the whole component tree down to HTML elements to
10
+ // test something. This technique is useful for testing components in isolation (unit testing),
11
+ // instead of the integration testing that RTL focuses on.
12
+
13
+ jest.mock("react-router", () => ({
14
+ ...jest.requireActual("react-router"),
15
+ Link: (props) => (
16
+ <div data-testid="Link" data-to={props.to}>
17
+ {props.children}
18
+ </div>
19
+ ),
20
+ }));
21
+
22
+ const renderLanes = stub();
23
+ const toggleLaneVisibility = stub();
24
+
25
+ function createLaneData(displayName: string, isAutomated: boolean): LaneData {
26
+ return {
27
+ id: 1,
28
+ display_name: displayName,
29
+ visible: true,
30
+ count: 5,
31
+ sublanes: [],
32
+ // The absence/presence of custom list ids determines if a lane is automated or custom.
33
+ custom_list_ids: isAutomated ? [] : [1],
34
+ inherit_parent_restrictions: true,
35
+ };
36
+ }
37
+
38
+ describe("Lane", () => {
39
+ it("renders an edit link on a custom lane", () => {
40
+ const laneData = createLaneData("Custom Lane", false);
41
+
42
+ render(
43
+ <Lane
44
+ lane={laneData}
45
+ active={false}
46
+ library="test_library"
47
+ orderChanged={false}
48
+ renderLanes={renderLanes}
49
+ toggleLaneVisibility={toggleLaneVisibility}
50
+ />
51
+ );
52
+
53
+ const editLink = screen.getAllByTestId("Link")[0];
54
+
55
+ expect(editLink).toHaveAttribute("data-to", expect.stringMatching(/edit/i));
56
+ expect(editLink).toHaveTextContent(/edit/i);
57
+ });
58
+
59
+ it("renders an edit link on an automated lane", async () => {
60
+ const laneData = createLaneData("Automated Lane", true);
61
+
62
+ render(
63
+ <Lane
64
+ lane={laneData}
65
+ active={false}
66
+ library="test_library"
67
+ orderChanged={false}
68
+ renderLanes={renderLanes}
69
+ toggleLaneVisibility={toggleLaneVisibility}
70
+ />
71
+ );
72
+
73
+ const editLink = screen.getAllByTestId("Link")[0];
74
+
75
+ expect(editLink).toHaveAttribute("data-to", expect.stringMatching(/edit/i));
76
+ expect(editLink).toHaveTextContent(/edit/i);
77
+ });
78
+ });
@@ -0,0 +1,148 @@
1
+ import * as React from "react";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { stub } from "sinon";
4
+ import { LaneData } from "../../../src/interfaces";
5
+ import LaneEditor from "../../../src/components/LaneEditor";
6
+
7
+ // Mock the LaneCustomListsEditor so we can verify that it is or isn't rendered. This serves as an
8
+ // example of how to do something analogous to Enzyme's shallow rendering, when we don't want/need
9
+ // to render the whole component tree down to HTML elements to test something. This technique is
10
+ // useful for testing components in isolation (unit testing), instead of the integration testing
11
+ // that RTL focuses on.
12
+
13
+ jest.mock("../../../src/components/LaneCustomListsEditor", () => ({
14
+ __esModule: true,
15
+ default: (props) => <div data-testid="LaneCustomListsEditor" />,
16
+ }));
17
+
18
+ const customListsData = [
19
+ { id: 1, name: "list 1", entries: [], is_owner: true, is_shared: false },
20
+ ];
21
+
22
+ const editLane = stub().returns(
23
+ new Promise<void>((resolve) => resolve())
24
+ );
25
+
26
+ const deleteLane = stub().returns(
27
+ new Promise<void>((resolve) => resolve())
28
+ );
29
+
30
+ const toggleLaneVisibility = stub();
31
+
32
+ function createLaneData(displayName: string, isAutomated: boolean): LaneData {
33
+ return {
34
+ id: 1,
35
+ display_name: displayName,
36
+ visible: true,
37
+ count: 5,
38
+ sublanes: [
39
+ {
40
+ id: 2,
41
+ display_name: `Sublane of ${displayName}`,
42
+ visible: true,
43
+ count: 3,
44
+ sublanes: [],
45
+ custom_list_ids: [1],
46
+ inherit_parent_restrictions: false,
47
+ },
48
+ ],
49
+ // The absence/presence of custom list ids determines if a lane is automated or custom.
50
+ custom_list_ids: isAutomated ? [] : [1],
51
+ inherit_parent_restrictions: true,
52
+ };
53
+ }
54
+
55
+ describe("LaneEditor", () => {
56
+ describe("for a custom lane", () => {
57
+ const laneData = createLaneData("Custom Lane", false);
58
+
59
+ beforeEach(() => {
60
+ render(
61
+ <LaneEditor
62
+ library="library"
63
+ lane={laneData}
64
+ customLists={customListsData}
65
+ editOrCreate="edit"
66
+ editLane={editLane}
67
+ deleteLane={deleteLane}
68
+ findParentOfLane={stub().returns(laneData)}
69
+ toggleLaneVisibility={toggleLaneVisibility}
70
+ />
71
+ );
72
+ });
73
+
74
+ it("renders a delete button", () => {
75
+ expect(screen.getByRole("button", { name: /delete/i })).not.toBeNull();
76
+ });
77
+
78
+ it("renders an inherit parent restrictions checkbox", () => {
79
+ expect(
80
+ screen.getByRole("checkbox", {
81
+ name: /inherit restrictions from parent/i,
82
+ })
83
+ ).not.toBeNull();
84
+ });
85
+
86
+ it("renders a custom lists editor", () => {
87
+ expect(screen.getByTestId("LaneCustomListsEditor")).not.toBeNull();
88
+ });
89
+ });
90
+
91
+ describe("for an automated lane", () => {
92
+ const laneData = createLaneData("Automated Lane", true);
93
+
94
+ beforeEach(() => {
95
+ render(
96
+ <LaneEditor
97
+ library="library"
98
+ lane={laneData}
99
+ customLists={customListsData}
100
+ editOrCreate="edit"
101
+ editLane={editLane}
102
+ deleteLane={deleteLane}
103
+ findParentOfLane={stub().returns(laneData)}
104
+ toggleLaneVisibility={toggleLaneVisibility}
105
+ />
106
+ );
107
+ });
108
+
109
+ it("does not render a delete button", () => {
110
+ expect(screen.queryByRole("button", { name: /delete/i })).toBeNull();
111
+ });
112
+
113
+ it("does not render an inherit parent restrictions checkbox", () => {
114
+ expect(
115
+ screen.queryByRole("checkbox", {
116
+ name: /inherit restrictions from parent/i,
117
+ })
118
+ ).toBeNull();
119
+ });
120
+
121
+ it("does not render a custom lists editor", () => {
122
+ expect(screen.queryByTestId("LaneCustomListsEditor")).toBeNull();
123
+ });
124
+
125
+ it("renders an explanation that the lane contents can't be edited", () => {
126
+ expect(screen.getByText(/contents cannot be edited/i)).not.toBeNull();
127
+ });
128
+ });
129
+
130
+ it("doesn't render a custom lists editor while a lane is being loaded for editing", () => {
131
+ const laneData = null;
132
+
133
+ render(
134
+ <LaneEditor
135
+ library="library"
136
+ lane={laneData}
137
+ customLists={customListsData}
138
+ editOrCreate="edit"
139
+ editLane={editLane}
140
+ deleteLane={deleteLane}
141
+ findParentOfLane={stub().returns(laneData)}
142
+ toggleLaneVisibility={toggleLaneVisibility}
143
+ />
144
+ );
145
+
146
+ expect(screen.queryByTestId("LaneCustomListsEditor")).toBeNull();
147
+ });
148
+ });
@@ -0,0 +1,37 @@
1
+ import * as React from "react";
2
+ import { render, screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import ProtocolFormField from "../../../src/components/ProtocolFormField";
5
+
6
+ // NB: This file adds / duplicates existing tests from:
7
+ // - `src/components/__tests__/ProtocolFormField-test.tsx`.
8
+ //
9
+ // Those tests should eventually be migrated here and
10
+ // adapted to the Jest/React Testing Library paradigm.
11
+
12
+ describe("ProtocolFormField", () => {
13
+ it("renders date-picker setting", async () => {
14
+ const user = userEvent.setup();
15
+ const emptyValue = "";
16
+ const testDate = "2022-01-01";
17
+ const datePickerLabel = "A date setting field";
18
+ const fieldDescription = "Description of the setting";
19
+ const setting = {
20
+ key: "setting",
21
+ label: datePickerLabel,
22
+ description: `<p>${fieldDescription}</p>`,
23
+ type: "date-picker",
24
+ };
25
+
26
+ render(<ProtocolFormField setting={setting} disabled={false} />);
27
+ const input = screen.getByLabelText(datePickerLabel) as HTMLInputElement;
28
+
29
+ expect(input.value).toBe(emptyValue);
30
+
31
+ // Enter a date.
32
+ await user.click(input);
33
+ await user.keyboard(`${testDate}{enter}`);
34
+
35
+ expect(input.value).toBe(testDate);
36
+ });
37
+ });
@@ -0,0 +1,67 @@
1
+ import * as React from "react";
2
+ import { screen, waitFor } from "@testing-library/react";
3
+
4
+ import QuicksightDashboard from "../../../src/components/QuicksightDashboard";
5
+ import { LibrariesData } from "../../../src/interfaces";
6
+ import buildStore from "../../../src/store";
7
+ import { setupServer } from "msw/node";
8
+ import { http, HttpResponse } from "msw";
9
+ import renderWithContext from "../testUtils/renderWithContext";
10
+ import { renderWithProviders } from "../testUtils/withProviders";
11
+ import QuicksightDashboardPage from "../../../src/components/QuicksightDashboardPage";
12
+
13
+ const libraries: LibrariesData = { libraries: [{ uuid: "my-uuid" }] };
14
+ const dashboardId = "test";
15
+ const embedUrl = "http://embedUrl";
16
+ const dashboardUrlData = { embedUrl: embedUrl };
17
+
18
+ describe("QuicksightDashboard", () => {
19
+ const server = setupServer(
20
+ http.get("/admin/libraries", () => HttpResponse.json(libraries)),
21
+ http.get(`/admin/quicksight_embed/${dashboardId}`, ({ request }) => {
22
+ const url = new URL(request.url);
23
+ const libraryUuids = url.searchParams.get("libraryUuids");
24
+
25
+ if (libraryUuids === libraries["libraries"][0]["uuid"]) {
26
+ return HttpResponse.json(dashboardUrlData);
27
+ }
28
+ })
29
+ );
30
+
31
+ beforeAll(() => {
32
+ server.listen();
33
+ });
34
+
35
+ afterAll(() => {
36
+ server.close();
37
+ });
38
+
39
+ it("embed url is retrieved and set in iframe", async () => {
40
+ renderWithProviders(
41
+ <QuicksightDashboard dashboardId={dashboardId} store={buildStore()} />
42
+ );
43
+
44
+ await waitFor(() => {
45
+ expect(screen.getAllByTitle("Library Dashboard")[0]).toHaveAttribute(
46
+ "src",
47
+ embedUrl
48
+ );
49
+ });
50
+ });
51
+
52
+ it("header renders without navigation links ", () => {
53
+ renderWithProviders(<QuicksightDashboardPage params={{ library: null }} />);
54
+
55
+ // Make sure we see the QuicksSight iFrame.
56
+ expect(screen.getByTitle("Library Dashboard")).toBeInTheDocument();
57
+ // Make sure we have the branding image.
58
+ expect(
59
+ screen.getByAltText("Palace Collection Manager")
60
+ ).toBeInTheDocument();
61
+
62
+ // Make sure we do not see other navigation links.
63
+ ["Dashboard", "System Configuration"].forEach((name) => {
64
+ expect(screen.queryByText(name)).not.toBeInTheDocument();
65
+ });
66
+ });
67
+ });