@thepalaceproject/circulation-admin 1.43.0 → 1.44.0
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/CLAUDE.md +28 -7
- package/README.md +11 -5
- package/dist/circulation-admin.js +1 -1
- package/eslint.config.mjs +9 -1
- package/jest.config.js +22 -8
- package/package.json +6 -20
- package/tests/jest/actions.test.ts +962 -0
- package/tests/jest/components/AccountPage.test.tsx +41 -0
- package/tests/jest/components/AdvancedSearchBooleanFilter.test.tsx +231 -0
- package/tests/jest/components/AdvancedSearchBuilder.test.tsx +93 -20
- package/tests/jest/components/AdvancedSearchFilter.test.tsx +142 -0
- package/tests/jest/components/AdvancedSearchFilterInput.test.tsx +212 -0
- package/tests/jest/components/AdvancedSearchFilterViewer.test.tsx +52 -0
- package/tests/jest/components/AdvancedSearchValueFilter.test.tsx +123 -0
- package/tests/jest/components/Announcement.test.tsx +76 -0
- package/tests/jest/components/AnnouncementForm.test.tsx +229 -0
- package/tests/jest/components/AnnouncementsSection.test.tsx +146 -0
- package/tests/jest/components/Autocomplete.test.tsx +67 -0
- package/tests/jest/components/BookCoverEditor.test.tsx +393 -0
- package/tests/jest/components/BookDetails.test.tsx +133 -0
- package/tests/jest/components/BookDetailsContainer.test.tsx +116 -0
- package/tests/jest/components/BookDetailsEditor.test.tsx +275 -0
- package/tests/jest/components/BookDetailsTabContainer.test.tsx +237 -0
- package/tests/jest/components/BookEditForm.test.tsx +352 -0
- package/tests/jest/components/BookEditor.test.tsx +20 -21
- package/tests/jest/components/CatalogPage.test.tsx +158 -0
- package/tests/jest/components/CatalogServices.test.tsx +100 -0
- package/tests/jest/components/ChangePasswordForm.test.tsx +163 -0
- package/tests/jest/components/CirculationEventsDownloadForm.test.tsx +41 -0
- package/tests/jest/components/Classifications.test.tsx +166 -0
- package/tests/jest/components/ClassificationsForm.test.tsx +458 -0
- package/tests/jest/components/ClassificationsTable.test.tsx +57 -0
- package/tests/jest/components/Collections.test.tsx +335 -7
- package/tests/jest/components/ColorPicker.test.tsx +58 -0
- package/tests/jest/components/ComplaintForm.test.tsx +171 -0
- package/tests/jest/components/Complaints.test.tsx +259 -0
- package/tests/jest/components/ConfigPage.test.tsx +58 -0
- package/tests/jest/components/ConfigTabContainer.test.tsx +196 -0
- package/tests/jest/components/ContextProvider.test.tsx +138 -0
- package/tests/jest/components/Contributors.test.tsx +157 -0
- package/tests/jest/components/CustomListEditor.test.tsx +367 -0
- package/tests/jest/components/CustomListEntriesEditor.test.tsx +1240 -0
- package/tests/jest/components/CustomListPage.test.tsx +57 -0
- package/tests/jest/components/CustomListSearch.test.tsx +275 -0
- package/tests/jest/components/CustomLists.test.tsx +621 -4
- package/tests/jest/components/CustomListsForBook.test.tsx +353 -0
- package/tests/jest/components/CustomListsSidebar.test.tsx +251 -0
- package/tests/jest/components/DashboardPage.test.tsx +76 -0
- package/tests/jest/components/DebugAuthentication.test.tsx +1 -5
- package/tests/jest/components/DiagnosticsServiceTabs.test.tsx +141 -0
- package/tests/jest/components/DiagnosticsServiceType.test.tsx +75 -0
- package/tests/jest/components/DiagnosticsTabContainer.test.tsx +147 -0
- package/tests/jest/components/DiscoveryServices.test.tsx +154 -7
- package/tests/jest/components/EditableConfigList.test.tsx +606 -9
- package/tests/jest/components/EditableInput.test.tsx +250 -1
- package/tests/jest/components/EditorField.test.tsx +95 -0
- package/tests/jest/components/EntryPointsContainer.test.tsx +97 -0
- package/tests/jest/components/EntryPointsTabs.test.tsx +88 -0
- package/tests/jest/components/ErrorMessage.test.tsx +97 -0
- package/tests/jest/components/Footer.test.tsx +141 -0
- package/tests/jest/components/GenreForm.test.tsx +152 -0
- package/tests/jest/components/Header.test.tsx +421 -0
- package/tests/jest/components/IndividualAdminEditForm.test.tsx +506 -1
- package/tests/jest/components/IndividualAdmins.test.tsx +124 -8
- package/tests/jest/components/InputList.test.tsx +493 -0
- package/tests/jest/components/InventoryReportRequestModal.test.tsx +16 -42
- package/tests/jest/components/JsonField.test.tsx +20 -0
- package/tests/jest/components/Lane.test.tsx +132 -10
- package/tests/jest/components/LaneCustomListsEditor.test.tsx +450 -0
- package/tests/jest/components/LaneEditor.test.tsx +377 -13
- package/tests/jest/components/LanePage.test.tsx +68 -0
- package/tests/jest/components/Lanes.test.tsx +446 -0
- package/tests/jest/components/LanesSidebar.test.tsx +621 -0
- package/tests/jest/components/LanguageField.test.tsx +40 -0
- package/tests/jest/components/Libraries.test.tsx +48 -0
- package/tests/jest/components/LibraryEditForm.test.tsx +383 -0
- package/tests/jest/components/LibraryRegistration.test.tsx +354 -0
- package/tests/jest/components/LibraryRegistrationForm.test.tsx +203 -0
- package/tests/jest/components/LoadButton.test.tsx +49 -0
- package/tests/jest/components/ManagePatrons.test.tsx +73 -0
- package/tests/jest/components/ManagePatronsForm.test.tsx +180 -0
- package/tests/jest/components/ManagePatronsTabContainer.test.tsx +143 -0
- package/tests/jest/components/MetadataServices.test.tsx +95 -0
- package/tests/jest/components/NeighborhoodAnalyticsForm.test.tsx +167 -0
- package/tests/jest/components/PairedMenus.test.tsx +220 -0
- package/tests/jest/components/PatronAuthServices.test.tsx +114 -0
- package/tests/jest/components/PatronBlockingRulesEditor.test.tsx +3 -1
- package/tests/jest/components/PatronInfo.test.tsx +54 -0
- package/tests/jest/components/ProtocolFormField.test.tsx +479 -7
- package/tests/jest/components/ResetAdobeId.test.tsx +302 -0
- package/tests/jest/components/SaveButton.test.tsx +47 -0
- package/tests/jest/components/SelfTestResult.test.tsx +164 -0
- package/tests/jest/components/SelfTests.test.tsx +601 -0
- package/tests/jest/components/SelfTestsCategory.test.tsx +200 -0
- package/tests/jest/components/SelfTestsTabContainer.test.tsx +216 -0
- package/tests/jest/components/ServiceEditForm.test.tsx +1092 -0
- package/tests/jest/components/ServiceWithRegistrationsEditForm.test.tsx +110 -0
- package/tests/jest/components/SetupPage.test.tsx +41 -0
- package/tests/jest/components/SingleStatListItem.test.tsx +62 -0
- package/tests/jest/components/SitewideAnnouncements.test.tsx +134 -0
- package/tests/jest/components/Stats.test.tsx +4 -15
- package/tests/jest/components/TabContainer.test.tsx +68 -0
- package/tests/jest/components/TextWithEditMode.test.tsx +218 -0
- package/tests/jest/components/Timestamp.test.tsx +74 -0
- package/tests/jest/components/ToolTip.test.tsx +46 -0
- package/tests/jest/components/TroubleshootingCategoryPage.test.tsx +69 -0
- package/tests/jest/components/TroubleshootingPage.test.tsx +94 -0
- package/tests/jest/components/TroubleshootingTabContainer.test.tsx +68 -0
- package/tests/jest/components/UpdatingLoader.test.tsx +36 -0
- package/tests/jest/components/WelcomePage.test.tsx +43 -0
- package/tests/jest/components/WithEditButton.test.tsx +55 -0
- package/tests/jest/components/WithRemoveButton.test.tsx +95 -0
- package/tests/jest/editorAdapter.test.ts +245 -0
- package/tests/jest/features/book.test.ts +75 -80
- package/tests/jest/fixtures/classificationsData.ts +45 -0
- package/tests/jest/fixtures/genreData.ts +811 -0
- package/tests/jest/index.test.tsx +50 -0
- package/tests/jest/models/Admin.test.ts +206 -0
- package/tests/jest/reducers/bookCoverPreview.test.ts +81 -0
- package/tests/jest/reducers/classifications.test.ts +161 -0
- package/tests/jest/reducers/collections.test.ts +96 -0
- package/tests/jest/reducers/complaints.test.ts +166 -0
- package/tests/jest/reducers/createFetchEditReducer.test.ts +220 -0
- package/tests/jest/reducers/createRegisterLibraryReducer.test.ts +51 -0
- package/tests/jest/reducers/customListDetails.test.ts +120 -0
- package/tests/jest/reducers/customListEditor.test.ts +2823 -0
- package/tests/jest/reducers/managePatrons.test.ts +71 -0
- package/tests/jest/testUtils/formDataShim.test.ts +135 -0
- package/tests/jest/testUtils/formDataShim.ts +112 -0
- package/tests/jest/utils/sharedFunctions.test.ts +121 -0
- package/tsconfig.json +3 -4
- package/testReporter.js +0 -29
- package/tests/jest/README.md +0 -6
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import Timestamp from "../../../src/components/Timestamp";
|
|
5
|
+
|
|
6
|
+
describe("Timestamp", () => {
|
|
7
|
+
const timestamp = {
|
|
8
|
+
service: "test_service",
|
|
9
|
+
id: "1",
|
|
10
|
+
start: "start_time_string",
|
|
11
|
+
duration: "60",
|
|
12
|
+
collection_name: "collection1",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe("rendering", () => {
|
|
16
|
+
it("renders a success panel that is not collapsible", () => {
|
|
17
|
+
const { container } = render(<Timestamp timestamp={timestamp} />);
|
|
18
|
+
|
|
19
|
+
expect(container.querySelector(".panel-success")).toBeInTheDocument();
|
|
20
|
+
expect(container.querySelector(".panel-danger")).not.toBeInTheDocument();
|
|
21
|
+
// A non-collapsible panel is a static panel with no toggle button.
|
|
22
|
+
expect(container.querySelector(".static-panel")).toBeInTheDocument();
|
|
23
|
+
expect(screen.queryByRole("button")).not.toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("renders the start time", () => {
|
|
27
|
+
const { container } = render(<Timestamp timestamp={timestamp} />);
|
|
28
|
+
|
|
29
|
+
expect(container.querySelector(".panel-title")).toHaveTextContent(
|
|
30
|
+
"start_time_string"
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("renders the duration", () => {
|
|
35
|
+
const { container } = render(<Timestamp timestamp={timestamp} />);
|
|
36
|
+
|
|
37
|
+
expect(container.querySelectorAll("ul li")).toHaveLength(1);
|
|
38
|
+
expect(screen.getByText("Duration: 60 seconds")).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("rendering with achievements", () => {
|
|
43
|
+
it("renders achievements", () => {
|
|
44
|
+
const { container } = render(
|
|
45
|
+
<Timestamp timestamp={{ ...timestamp, achievements: "Ran a script" }} />
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(container.querySelectorAll("ul li")).toHaveLength(2);
|
|
49
|
+
const achievements = container.querySelector(".well pre");
|
|
50
|
+
expect(achievements).toBeInTheDocument();
|
|
51
|
+
expect(achievements).toHaveTextContent("Ran a script");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("rendering with exception", () => {
|
|
56
|
+
it("determines style based on whether there is an exception", () => {
|
|
57
|
+
const { container } = render(
|
|
58
|
+
<Timestamp timestamp={{ ...timestamp, exception: "Stack trace" }} />
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(container.querySelector(".panel-danger")).toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("renders an exception", () => {
|
|
65
|
+
const { container } = render(
|
|
66
|
+
<Timestamp timestamp={{ ...timestamp, exception: "Stack trace" }} />
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const exception = container.querySelector(".exception pre");
|
|
70
|
+
expect(exception).toBeInTheDocument();
|
|
71
|
+
expect(exception).toHaveTextContent("Stack trace");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import ToolTip from "../../../src/components/ToolTip";
|
|
5
|
+
|
|
6
|
+
describe("ToolTip", () => {
|
|
7
|
+
const renderToolTip = () =>
|
|
8
|
+
render(<ToolTip trigger={<h1>Hover</h1>} text="ToolTip Content" />);
|
|
9
|
+
|
|
10
|
+
it("renders the trigger element", () => {
|
|
11
|
+
renderToolTip();
|
|
12
|
+
expect(screen.getByRole("heading", { name: "Hover" })).toBeInTheDocument();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("renders the tooltip", () => {
|
|
16
|
+
const { container } = renderToolTip();
|
|
17
|
+
const tooltip = container.querySelector<HTMLElement>(".tool-tip")!;
|
|
18
|
+
expect(tooltip).toBeInTheDocument();
|
|
19
|
+
expect(tooltip).toHaveTextContent("ToolTip Content");
|
|
20
|
+
expect(tooltip.innerHTML).toContain("ToolTip Content");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("initially hides the tooltip", () => {
|
|
24
|
+
const { container } = renderToolTip();
|
|
25
|
+
expect(container.querySelector(".tool-tip")).toHaveClass("hide");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("shows the tooltip on mouseEnter", async () => {
|
|
29
|
+
const user = userEvent.setup();
|
|
30
|
+
const { container } = renderToolTip();
|
|
31
|
+
await user.hover(screen.getByRole("tooltip"));
|
|
32
|
+
expect(container.querySelector(".tool-tip")).not.toHaveClass("hide");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("hides the tooltip on mouseLeave", async () => {
|
|
36
|
+
const user = userEvent.setup();
|
|
37
|
+
const { container } = renderToolTip();
|
|
38
|
+
const toolTipContainer = screen.getByRole("tooltip");
|
|
39
|
+
|
|
40
|
+
await user.hover(toolTipContainer);
|
|
41
|
+
expect(container.querySelector(".tool-tip")).not.toHaveClass("hide");
|
|
42
|
+
|
|
43
|
+
await user.unhover(toolTipContainer);
|
|
44
|
+
expect(container.querySelector(".tool-tip")).toHaveClass("hide");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -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
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
|
|
5
|
+
// The tab content (TroubleshootingCategoryPage) renders the connected
|
|
6
|
+
// Diagnostics/Self-tests containers, which need Redux store + csrf context this
|
|
7
|
+
// test does not supply. That content is incidental here — the test is about the
|
|
8
|
+
// tab navigation — so mock it to a marker.
|
|
9
|
+
jest.mock("../../../src/components/TroubleshootingCategoryPage", () => ({
|
|
10
|
+
__esModule: true,
|
|
11
|
+
default: () => <div data-testid="category-page" />,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
import TroubleshootingTabContainer from "../../../src/components/TroubleshootingTabContainer";
|
|
15
|
+
|
|
16
|
+
describe("TroubleshootingTabContainer", () => {
|
|
17
|
+
let goToTab: jest.Mock;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
goToTab = jest.fn();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("renders tabs and defaults to showing the Diagnostics tab", () => {
|
|
24
|
+
const { container } = render(
|
|
25
|
+
<TroubleshootingTabContainer goToTab={goToTab} tab="diagnostics" />
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const nav = container.querySelector("ul.nav-tabs");
|
|
29
|
+
expect(nav).not.toBeNull();
|
|
30
|
+
|
|
31
|
+
const tabs = nav.querySelectorAll("li");
|
|
32
|
+
expect(tabs).toHaveLength(2);
|
|
33
|
+
|
|
34
|
+
expect(tabs[0]).toHaveTextContent("Diagnostics");
|
|
35
|
+
expect(tabs[0]).toHaveClass("active");
|
|
36
|
+
|
|
37
|
+
expect(tabs[1]).toHaveTextContent("Self-tests");
|
|
38
|
+
expect(tabs[1]).not.toHaveClass("active");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("calls goToTab when another tab is clicked", async () => {
|
|
42
|
+
const user = userEvent.setup();
|
|
43
|
+
render(<TroubleshootingTabContainer goToTab={goToTab} tab="diagnostics" />);
|
|
44
|
+
|
|
45
|
+
await user.click(screen.getByRole("link", { name: "Self-tests" }));
|
|
46
|
+
|
|
47
|
+
expect(goToTab).toHaveBeenCalledTimes(1);
|
|
48
|
+
expect(goToTab).toHaveBeenCalledWith("self-tests");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("switches the active tab when the tab prop changes", () => {
|
|
52
|
+
const { container, rerender } = render(
|
|
53
|
+
<TroubleshootingTabContainer goToTab={goToTab} tab="diagnostics" />
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
let tabs = container.querySelectorAll("ul.nav-tabs li");
|
|
57
|
+
expect(tabs[0]).toHaveClass("active");
|
|
58
|
+
expect(tabs[1]).not.toHaveClass("active");
|
|
59
|
+
|
|
60
|
+
rerender(
|
|
61
|
+
<TroubleshootingTabContainer goToTab={goToTab} tab="self-tests" />
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
tabs = container.querySelectorAll("ul.nav-tabs li");
|
|
65
|
+
expect(tabs[0]).not.toHaveClass("active");
|
|
66
|
+
expect(tabs[1]).toHaveClass("active");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import UpdatingLoader from "../../../src/components/UpdatingLoader";
|
|
5
|
+
|
|
6
|
+
describe("UpdatingLoader", () => {
|
|
7
|
+
it("renders only its container when not showing", () => {
|
|
8
|
+
const { container } = render(<UpdatingLoader show={false} />);
|
|
9
|
+
|
|
10
|
+
expect(
|
|
11
|
+
container.querySelector(".updating-loader-container")
|
|
12
|
+
).toBeInTheDocument();
|
|
13
|
+
expect(container.querySelector(".updating-loader")).not.toBeInTheDocument();
|
|
14
|
+
expect(screen.queryByText("Updating")).not.toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("renders the default message when showing", () => {
|
|
18
|
+
render(<UpdatingLoader show={true} />);
|
|
19
|
+
|
|
20
|
+
expect(screen.getByText("Updating")).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("renders the text it is given instead of the default", () => {
|
|
24
|
+
render(<UpdatingLoader show={true} text="Doing something" />);
|
|
25
|
+
|
|
26
|
+
expect(screen.getByText("Doing something")).toBeInTheDocument();
|
|
27
|
+
expect(screen.queryByText("Updating")).not.toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("renders a spinner", () => {
|
|
31
|
+
const { container } = render(<UpdatingLoader show={true} />);
|
|
32
|
+
|
|
33
|
+
// The spinner is a Font Awesome <i>, which carries no accessible role.
|
|
34
|
+
expect(container.querySelector("i.fa-spinner")).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
// Header pulls in the react-router v3 context a plain render does not supply, and
|
|
5
|
+
// both Header and Footer are page chrome with no behavior worth exercising here.
|
|
6
|
+
// Mock them to markers so the test stays about what WelcomePage composes.
|
|
7
|
+
jest.mock("../../../src/components/Header", () => ({
|
|
8
|
+
__esModule: true,
|
|
9
|
+
default: () => <div data-testid="header" />,
|
|
10
|
+
}));
|
|
11
|
+
jest.mock("../../../src/components/Footer", () => ({
|
|
12
|
+
__esModule: true,
|
|
13
|
+
default: () => <div data-testid="footer" />,
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
import WelcomePage from "../../../src/components/WelcomePage";
|
|
17
|
+
|
|
18
|
+
describe("WelcomePage", () => {
|
|
19
|
+
it("shows the header", () => {
|
|
20
|
+
render(<WelcomePage />);
|
|
21
|
+
expect(screen.getByTestId("header")).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("shows the welcome message", () => {
|
|
25
|
+
render(<WelcomePage />);
|
|
26
|
+
expect(
|
|
27
|
+
screen.getByRole("heading", {
|
|
28
|
+
name: "Welcome to the Circulation Admin Interface!",
|
|
29
|
+
})
|
|
30
|
+
).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("shows a link to the library create form", () => {
|
|
34
|
+
render(<WelcomePage />);
|
|
35
|
+
const link = screen.getByRole("link", { name: /create a new library/i });
|
|
36
|
+
expect(link).toHaveAttribute("href", "/admin/web/config/libraries/create");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("shows the footer", () => {
|
|
40
|
+
render(<WelcomePage />);
|
|
41
|
+
expect(screen.getByTestId("footer")).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
|
|
5
|
+
import WithEditButton from "../../../src/components/WithEditButton";
|
|
6
|
+
|
|
7
|
+
describe("WithEditButton", () => {
|
|
8
|
+
it("shows children", () => {
|
|
9
|
+
render(
|
|
10
|
+
<WithEditButton disabled={false} onEdit={jest.fn()}>
|
|
11
|
+
child
|
|
12
|
+
</WithEditButton>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
expect(screen.getByText("child")).toBeInTheDocument();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("shows an edit button", () => {
|
|
19
|
+
render(
|
|
20
|
+
<WithEditButton disabled={false} onEdit={jest.fn()}>
|
|
21
|
+
child
|
|
22
|
+
</WithEditButton>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
expect(screen.getByRole("button")).toHaveClass("edit-btn");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("calls onEdit when clicked", async () => {
|
|
29
|
+
const user = userEvent.setup();
|
|
30
|
+
const onEdit = jest.fn();
|
|
31
|
+
render(
|
|
32
|
+
<WithEditButton disabled={false} onEdit={onEdit}>
|
|
33
|
+
child
|
|
34
|
+
</WithEditButton>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
await user.click(screen.getByRole("button"));
|
|
38
|
+
|
|
39
|
+
expect(onEdit).toHaveBeenCalledTimes(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("does nothing when disabled", async () => {
|
|
43
|
+
const user = userEvent.setup();
|
|
44
|
+
const onEdit = jest.fn();
|
|
45
|
+
render(
|
|
46
|
+
<WithEditButton disabled={true} onEdit={onEdit}>
|
|
47
|
+
child
|
|
48
|
+
</WithEditButton>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
await user.click(screen.getByRole("button"));
|
|
52
|
+
|
|
53
|
+
expect(onEdit).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
|
|
5
|
+
import WithRemoveButton from "../../../src/components/WithRemoveButton";
|
|
6
|
+
|
|
7
|
+
describe("WithRemoveButton", () => {
|
|
8
|
+
it("shows children", () => {
|
|
9
|
+
render(
|
|
10
|
+
<WithRemoveButton disabled={false} onRemove={jest.fn()}>
|
|
11
|
+
child
|
|
12
|
+
</WithRemoveButton>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
expect(screen.getByText("child")).toBeInTheDocument();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("shows a remove button", () => {
|
|
19
|
+
render(
|
|
20
|
+
<WithRemoveButton disabled={false} onRemove={jest.fn()}>
|
|
21
|
+
child
|
|
22
|
+
</WithRemoveButton>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
expect(screen.getByRole("button")).toHaveClass("remove-btn");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("calls onRemove when clicked", async () => {
|
|
29
|
+
const user = userEvent.setup();
|
|
30
|
+
const onRemove = jest.fn();
|
|
31
|
+
render(
|
|
32
|
+
<WithRemoveButton disabled={false} onRemove={onRemove}>
|
|
33
|
+
child
|
|
34
|
+
</WithRemoveButton>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
await user.click(screen.getByRole("button"));
|
|
38
|
+
|
|
39
|
+
expect(onRemove).toHaveBeenCalledTimes(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("does nothing when disabled", async () => {
|
|
43
|
+
const user = userEvent.setup();
|
|
44
|
+
const onRemove = jest.fn();
|
|
45
|
+
render(
|
|
46
|
+
<WithRemoveButton disabled={true} onRemove={onRemove}>
|
|
47
|
+
child
|
|
48
|
+
</WithRemoveButton>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
await user.click(screen.getByRole("button"));
|
|
52
|
+
|
|
53
|
+
expect(onRemove).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("calls onRemove when confirmation returns true", async () => {
|
|
57
|
+
const user = userEvent.setup();
|
|
58
|
+
const onRemove = jest.fn();
|
|
59
|
+
const confirmRemoval = jest.fn().mockReturnValue(true);
|
|
60
|
+
render(
|
|
61
|
+
<WithRemoveButton
|
|
62
|
+
disabled={false}
|
|
63
|
+
onRemove={onRemove}
|
|
64
|
+
confirmRemoval={confirmRemoval}
|
|
65
|
+
>
|
|
66
|
+
child
|
|
67
|
+
</WithRemoveButton>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
await user.click(screen.getByRole("button"));
|
|
71
|
+
|
|
72
|
+
expect(confirmRemoval).toHaveBeenCalledTimes(1);
|
|
73
|
+
expect(onRemove).toHaveBeenCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("does not call onRemove when confirmation returns false", async () => {
|
|
77
|
+
const user = userEvent.setup();
|
|
78
|
+
const onRemove = jest.fn();
|
|
79
|
+
const confirmRemoval = jest.fn().mockReturnValue(false);
|
|
80
|
+
render(
|
|
81
|
+
<WithRemoveButton
|
|
82
|
+
disabled={false}
|
|
83
|
+
onRemove={onRemove}
|
|
84
|
+
confirmRemoval={confirmRemoval}
|
|
85
|
+
>
|
|
86
|
+
child
|
|
87
|
+
</WithRemoveButton>
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
await user.click(screen.getByRole("button"));
|
|
91
|
+
|
|
92
|
+
expect(confirmRemoval).toHaveBeenCalledTimes(1);
|
|
93
|
+
expect(onRemove).not.toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
});
|