@thepalaceproject/circulation-admin 1.43.0-post.10 → 1.43.0-post.14

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 (37) hide show
  1. package/package.json +1 -1
  2. package/tests/jest/components/Announcement.test.tsx +76 -0
  3. package/tests/jest/components/Autocomplete.test.tsx +67 -0
  4. package/tests/jest/components/BookCoverEditor.test.tsx +393 -0
  5. package/tests/jest/components/BookDetailsEditor.test.tsx +275 -0
  6. package/tests/jest/components/BookEditForm.test.tsx +352 -0
  7. package/tests/jest/components/CatalogPage.test.tsx +158 -0
  8. package/tests/jest/components/Classifications.test.tsx +166 -0
  9. package/tests/jest/components/ClassificationsForm.test.tsx +458 -0
  10. package/tests/jest/components/ClassificationsTable.test.tsx +57 -0
  11. package/tests/jest/components/ColorPicker.test.tsx +58 -0
  12. package/tests/jest/components/ComplaintForm.test.tsx +171 -0
  13. package/tests/jest/components/Complaints.test.tsx +259 -0
  14. package/tests/jest/components/ContextProvider.test.tsx +138 -0
  15. package/tests/jest/components/Contributors.test.tsx +157 -0
  16. package/tests/jest/components/CustomListEditor.test.tsx +367 -0
  17. package/tests/jest/components/CustomListEntriesEditor.test.tsx +1240 -0
  18. package/tests/jest/components/CustomLists.test.tsx +621 -4
  19. package/tests/jest/components/CustomListsForBook.test.tsx +315 -0
  20. package/tests/jest/components/DiagnosticsServiceTabs.test.tsx +141 -0
  21. package/tests/jest/components/DiagnosticsServiceType.test.tsx +75 -0
  22. package/tests/jest/components/EditorField.test.tsx +95 -0
  23. package/tests/jest/components/GenreForm.test.tsx +152 -0
  24. package/tests/jest/components/InputList.test.tsx +493 -0
  25. package/tests/jest/components/Lane.test.tsx +130 -7
  26. package/tests/jest/components/LaneCustomListsEditor.test.tsx +450 -0
  27. package/tests/jest/components/LaneEditor.test.tsx +367 -2
  28. package/tests/jest/components/Lanes.test.tsx +446 -0
  29. package/tests/jest/components/LanesSidebar.test.tsx +621 -0
  30. package/tests/jest/components/LibraryEditForm.test.tsx +383 -0
  31. package/tests/jest/components/LibraryRegistrationForm.test.tsx +203 -0
  32. package/tests/jest/components/PairedMenus.test.tsx +220 -0
  33. package/tests/jest/components/PatronAuthServices.test.tsx +114 -0
  34. package/tests/jest/components/ResetAdobeId.test.tsx +302 -0
  35. package/tests/jest/components/SitewideAnnouncements.test.tsx +134 -0
  36. package/tests/jest/components/TroubleshootingCategoryPage.test.tsx +69 -0
  37. package/tests/jest/components/TroubleshootingPage.test.tsx +94 -0
@@ -0,0 +1,134 @@
1
+ import * as React from "react";
2
+ import { installFormDataShim, FormDataShim } from "../testUtils/formDataShim";
3
+ import { screen, waitFor } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+
6
+ import { renderWithProviders } from "../testUtils/withProviders";
7
+ import buildStore from "../../../src/store";
8
+ // Render the CONNECTED default export so that mapStateToProps / mapDispatchToProps
9
+ // are exercised. The panel fetches its announcements on mount; the fetched data
10
+ // flows back in through the Redux store.
11
+ import SitewideAnnouncements from "../../../src/components/SitewideAnnouncements";
12
+
13
+ const data = {
14
+ announcements: [
15
+ {
16
+ id: "dcf036d9-106b-426c-838f-ce7c57d53801",
17
+ content: "There is nothing to see here.",
18
+ start: "2022-08-31",
19
+ finish: "2022-10-31",
20
+ },
21
+ ],
22
+ settings: [
23
+ {
24
+ category: "Announcements",
25
+ description: "Announcements will be displayed to authenticated patrons.",
26
+ key: "global_announcements",
27
+ label: "Scheduled announcements",
28
+ level: 3,
29
+ type: "announcements",
30
+ },
31
+ ],
32
+ };
33
+ installFormDataShim();
34
+
35
+ const jsonResponse = (body: unknown) =>
36
+ new Response(JSON.stringify(body), {
37
+ status: 200,
38
+ headers: { "Content-Type": "application/json" },
39
+ });
40
+
41
+ const renderConnected = (
42
+ element: React.ReactElement,
43
+ appConfigSettings: Record<string, unknown> = {}
44
+ ) =>
45
+ renderWithProviders(element, {
46
+ reduxProviderProps: { store: buildStore() },
47
+ appConfigSettings,
48
+ });
49
+
50
+ describe("SitewideAnnouncements", () => {
51
+ afterEach(() => {
52
+ jest.restoreAllMocks();
53
+ });
54
+
55
+ it("renders a form containing the announcements section", async () => {
56
+ jest
57
+ .spyOn(globalThis, "fetch")
58
+ .mockImplementation(async () => jsonResponse(data));
59
+ const { container } = renderConnected(
60
+ <SitewideAnnouncements csrfToken="token" />
61
+ );
62
+
63
+ // Once the on-mount fetch resolves, the form renders with the announcement
64
+ // supplied through the store (proving the AnnouncementsSection received the
65
+ // data as its value).
66
+ expect(
67
+ await screen.findByText("There is nothing to see here.")
68
+ ).toBeInTheDocument();
69
+ expect(screen.getByText("Scheduled Announcements:")).toBeInTheDocument();
70
+ expect(container.querySelector("form")).toBeInTheDocument();
71
+ });
72
+
73
+ it("renders a loading indicator instead of a form while data is loading", () => {
74
+ // A never-resolving fetch keeps the panel in its fetching state.
75
+ jest
76
+ .spyOn(globalThis, "fetch")
77
+ .mockImplementation(() => new Promise(() => {}));
78
+ const { container } = renderConnected(
79
+ <SitewideAnnouncements csrfToken="token" />
80
+ );
81
+
82
+ expect(container.querySelector(".loading")).toBeInTheDocument();
83
+ expect(container.querySelector("form")).not.toBeInTheDocument();
84
+ });
85
+
86
+ it("submits the announcements to editItem when the form is submitted", async () => {
87
+ const user = userEvent.setup();
88
+ const fetchSpy = jest
89
+ .spyOn(globalThis, "fetch")
90
+ .mockImplementation(async (_url, opts?: RequestInit) => {
91
+ if (opts?.method === "POST") {
92
+ return new Response("success", { status: 200 });
93
+ }
94
+ return jsonResponse(data);
95
+ });
96
+
97
+ // System admin so the settings' required permission level is satisfied and
98
+ // the submit button is enabled.
99
+ renderConnected(<SitewideAnnouncements csrfToken="token" />, {
100
+ roles: [{ role: "system" }],
101
+ });
102
+
103
+ await screen.findByText("There is nothing to see here.");
104
+
105
+ await user.click(screen.getByRole("button", { name: "Submit" }));
106
+
107
+ // The submit dispatches editSitewideAnnouncements, which POSTs the form.
108
+ await waitFor(() => {
109
+ const postCall = fetchSpy.mock.calls.find(
110
+ ([, opts]) => (opts as RequestInit)?.method === "POST"
111
+ );
112
+ expect(postCall).toBeDefined();
113
+ });
114
+
115
+ const postCall = fetchSpy.mock.calls.find(
116
+ ([, opts]) => (opts as RequestInit)?.method === "POST"
117
+ );
118
+ const body = (postCall[1] as RequestInit).body as unknown as FormDataShim;
119
+ expect(JSON.parse(body.get("announcements"))).toStrictEqual(
120
+ data.announcements
121
+ );
122
+ });
123
+
124
+ it("disables the submit button when the admin lacks the required permission level", async () => {
125
+ jest
126
+ .spyOn(globalThis, "fetch")
127
+ .mockImplementation(async () => jsonResponse(data));
128
+ // No roles => admin level 1, below the settings' required level of 3.
129
+ renderConnected(<SitewideAnnouncements csrfToken="token" />);
130
+
131
+ await screen.findByText("There is nothing to see here.");
132
+ expect(screen.getByRole("button", { name: "Submit" })).toBeDisabled();
133
+ });
134
+ });
@@ -0,0 +1,69 @@
1
+ import * as React from "react";
2
+ import { screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+
5
+ import { renderWithProviders } from "../testUtils/withProviders";
6
+
7
+ // The tab containers are connected components that fetch on mount and require
8
+ // react-router context; TroubleshootingCategoryPage only chooses between them
9
+ // and hands them a `tab` and `goToTab`. Mock them to markers that surface the
10
+ // `tab` they receive and let us drive `goToTab`.
11
+ jest.mock("../../../src/components/DiagnosticsTabContainer", () => ({
12
+ __esModule: true,
13
+ default: (props: any) => (
14
+ <div data-testid="diagnostics-tab-container" data-tab={props.tab}>
15
+ <button type="button" onClick={() => props.goToTab("monitor")}>
16
+ go-to-monitor
17
+ </button>
18
+ </div>
19
+ ),
20
+ }));
21
+ jest.mock("../../../src/components/SelfTestsTabContainer", () => ({
22
+ __esModule: true,
23
+ default: (props: any) => (
24
+ <div data-testid="self-tests-tab-container" data-tab={props.tab} />
25
+ ),
26
+ }));
27
+
28
+ import TroubleshootingCategoryPage from "../../../src/components/TroubleshootingCategoryPage";
29
+
30
+ describe("TroubleshootingCategoryPage", () => {
31
+ it("renders a tab container", () => {
32
+ renderWithProviders(<TroubleshootingCategoryPage type="diagnostics" />);
33
+
34
+ expect(screen.getByTestId("diagnostics-tab-container")).toBeInTheDocument();
35
+ expect(
36
+ screen.queryByTestId("self-tests-tab-container")
37
+ ).not.toBeInTheDocument();
38
+ });
39
+
40
+ it("switches tabs", async () => {
41
+ const user = userEvent.setup();
42
+ renderWithProviders(<TroubleshootingCategoryPage type="diagnostics" />);
43
+
44
+ expect(screen.getByTestId("diagnostics-tab-container")).toHaveAttribute(
45
+ "data-tab",
46
+ "coverage_provider"
47
+ );
48
+
49
+ await user.click(screen.getByRole("button", { name: "go-to-monitor" }));
50
+
51
+ expect(screen.getByTestId("diagnostics-tab-container")).toHaveAttribute(
52
+ "data-tab",
53
+ "monitor"
54
+ );
55
+ });
56
+
57
+ it("renders a different tab container", () => {
58
+ const { rerender } = renderWithProviders(
59
+ <TroubleshootingCategoryPage type="diagnostics" />
60
+ );
61
+
62
+ rerender(<TroubleshootingCategoryPage type="self-tests" />);
63
+
64
+ expect(
65
+ screen.queryByTestId("diagnostics-tab-container")
66
+ ).not.toBeInTheDocument();
67
+ expect(screen.getByTestId("self-tests-tab-container")).toBeInTheDocument();
68
+ });
69
+ });
@@ -0,0 +1,94 @@
1
+ import * as React from "react";
2
+ import { screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+
5
+ import { renderWithProviders } from "../testUtils/withProviders";
6
+ import title from "../../../src/utils/title";
7
+
8
+ // Header needs react-router v3 context that renderWithProviders does not supply,
9
+ // and both Header and Footer are page chrome, so mock them to markers.
10
+ jest.mock("../../../src/components/Header", () => ({
11
+ __esModule: true,
12
+ default: () => <div data-testid="header" />,
13
+ }));
14
+ jest.mock("../../../src/components/Footer", () => ({
15
+ __esModule: true,
16
+ default: () => <div data-testid="footer" />,
17
+ }));
18
+
19
+ // The real TroubleshootingTabContainer requires router/pathFor context and
20
+ // mounts self-test/diagnostic pages that fetch on mount. TroubleshootingPage's
21
+ // own behavior is to own the active tab and pass it (and a goToTab callback)
22
+ // down, so mock the container to a marker that exposes its `tab`/`subtab` props
23
+ // and a control that invokes `goToTab` — exactly the contract under test.
24
+ jest.mock("../../../src/components/TroubleshootingTabContainer", () => ({
25
+ __esModule: true,
26
+ default: ({
27
+ tab,
28
+ subtab,
29
+ goToTab,
30
+ }: {
31
+ tab: string;
32
+ subtab: string;
33
+ goToTab: (tab: string) => void;
34
+ }) => (
35
+ <div data-testid="tab-container" data-tab={tab} data-subtab={subtab}>
36
+ <button type="button" onClick={() => goToTab("self-tests")}>
37
+ Go to self-tests
38
+ </button>
39
+ </div>
40
+ ),
41
+ }));
42
+
43
+ import TroubleshootingPage from "../../../src/components/TroubleshootingPage";
44
+
45
+ const renderPage = () =>
46
+ renderWithProviders(<TroubleshootingPage params={{ tab: "", subtab: "" }} />);
47
+
48
+ describe("TroubleshootingPage", () => {
49
+ it("renders a header", () => {
50
+ renderPage();
51
+ expect(screen.getByTestId("header")).toBeInTheDocument();
52
+ });
53
+
54
+ it("renders a heading", () => {
55
+ renderPage();
56
+ expect(
57
+ screen.getByRole("heading", { name: "Troubleshooting" })
58
+ ).toBeInTheDocument();
59
+ });
60
+
61
+ it("renders a tab container starting on the diagnostics tab", () => {
62
+ renderPage();
63
+ const tabContainer = screen.getByTestId("tab-container");
64
+ expect(tabContainer).toBeInTheDocument();
65
+ expect(tabContainer).toHaveAttribute("data-tab", "diagnostics");
66
+ });
67
+
68
+ it("switches tabs", async () => {
69
+ const user = userEvent.setup();
70
+ renderPage();
71
+
72
+ expect(screen.getByTestId("tab-container")).toHaveAttribute(
73
+ "data-tab",
74
+ "diagnostics"
75
+ );
76
+
77
+ await user.click(screen.getByRole("button", { name: "Go to self-tests" }));
78
+
79
+ expect(screen.getByTestId("tab-container")).toHaveAttribute(
80
+ "data-tab",
81
+ "self-tests"
82
+ );
83
+ });
84
+
85
+ it("sets the document title", () => {
86
+ renderPage();
87
+ expect(document.title).toBe(title("Troubleshooting"));
88
+ });
89
+
90
+ it("shows a footer", () => {
91
+ renderPage();
92
+ expect(screen.getByTestId("footer")).toBeInTheDocument();
93
+ });
94
+ });