@thepalaceproject/circulation-admin 1.43.0-post.1 → 1.43.0-post.11
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 +16 -7
- package/dist/circulation-admin.js +1 -1
- package/eslint.config.mjs +9 -1
- package/jest.config.js +56 -9
- package/package.json +6 -16
- 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/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/Autocomplete.test.tsx +67 -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/BookEditForm.test.tsx +352 -0
- package/tests/jest/components/CatalogServices.test.tsx +63 -0
- package/tests/jest/components/CirculationEventsDownloadForm.test.tsx +41 -0
- package/tests/jest/components/Classifications.test.tsx +166 -0
- package/tests/jest/components/ClassificationsTable.test.tsx +57 -0
- 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/ContextProvider.test.tsx +138 -0
- package/tests/jest/components/CustomListEditor.test.tsx +367 -0
- package/tests/jest/components/CustomListPage.test.tsx +57 -0
- package/tests/jest/components/CustomListSearch.test.tsx +275 -0
- package/tests/jest/components/CustomListsForBook.test.tsx +315 -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/EditableConfigList.test.tsx +8 -2
- 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/InventoryReportRequestModal.test.tsx +16 -42
- package/tests/jest/components/LaneEditor.test.tsx +2 -6
- package/tests/jest/components/LanePage.test.tsx +68 -0
- package/tests/jest/components/LanguageField.test.tsx +40 -0
- package/tests/jest/components/LibraryEditForm.test.tsx +383 -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 +59 -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/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/SelfTestsCategory.test.tsx +200 -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 -8
- package/tests/jest/components/TabContainer.test.tsx +68 -0
- package/tests/jest/components/Timestamp.test.tsx +74 -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/index.test.tsx +50 -0
- package/tests/jest/legacy-setup.ts +13 -0
- package/tests/jest/legacyJsdomEnvironment.js +49 -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/components/AdvancedSearchBuilder.test.tsx +0 -38
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { renderWithProviders } from "../testUtils/withProviders";
|
|
3
|
+
import Footer, {
|
|
4
|
+
makeFooterSupportContactText,
|
|
5
|
+
} from "../../../src/components/Footer";
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_SUPPORT_CONTACT_TEXT,
|
|
8
|
+
SupportContactLink,
|
|
9
|
+
} from "../../../src/context/appContext";
|
|
10
|
+
|
|
11
|
+
const expectedTosText = "Terms of Service Text";
|
|
12
|
+
const expectedTosHref = "terms_of_service";
|
|
13
|
+
const testSupportContactEmail = "helpdesk@example.com";
|
|
14
|
+
const expectedSupportContact: SupportContactLink = {
|
|
15
|
+
href: `mailto:${testSupportContactEmail}?subject=Support+request`,
|
|
16
|
+
text: `Email ${testSupportContactEmail}.`,
|
|
17
|
+
};
|
|
18
|
+
const expectedSupportContactText = makeFooterSupportContactText(
|
|
19
|
+
expectedSupportContact.text
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// Builds the app config the ContextProvider transforms into terms-of-service and
|
|
23
|
+
// support-contact context, mirroring the legacy test's `getFooterProviders`.
|
|
24
|
+
const footerConfig = ({ hasSupportContactUrl = false } = {}) => ({
|
|
25
|
+
tos_link_text: expectedTosText,
|
|
26
|
+
tos_link_href: expectedTosHref,
|
|
27
|
+
// Include support contact URL only if we ask for it.
|
|
28
|
+
support_contact_url: hasSupportContactUrl
|
|
29
|
+
? "https://example.com/link-from-deprecated-setting"
|
|
30
|
+
: undefined,
|
|
31
|
+
supportContactUrl: hasSupportContactUrl
|
|
32
|
+
? expectedSupportContact.href
|
|
33
|
+
: undefined,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("Footer", () => {
|
|
37
|
+
it("accepts an optional className prop", () => {
|
|
38
|
+
const { container } = renderWithProviders(
|
|
39
|
+
<Footer className="customClass" />,
|
|
40
|
+
{ appConfigSettings: footerConfig() }
|
|
41
|
+
);
|
|
42
|
+
expect(container.querySelector("footer")).toHaveClass("customClass");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("displays a terms of service link", () => {
|
|
46
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
47
|
+
appConfigSettings: footerConfig(),
|
|
48
|
+
});
|
|
49
|
+
const links = container.querySelectorAll("a");
|
|
50
|
+
expect(links).toHaveLength(1);
|
|
51
|
+
|
|
52
|
+
expect(links[0]).toHaveTextContent(expectedTosText);
|
|
53
|
+
expect(links[0]).toHaveAttribute("href", expectedTosHref);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("support contact link", () => {
|
|
57
|
+
it("displays a support contact link, when URL present", () => {
|
|
58
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
59
|
+
appConfigSettings: footerConfig({ hasSupportContactUrl: true }),
|
|
60
|
+
});
|
|
61
|
+
const links = container.querySelectorAll("a");
|
|
62
|
+
expect(links).toHaveLength(2);
|
|
63
|
+
|
|
64
|
+
// The second link should be the support contact link.
|
|
65
|
+
expect(links[1]).toHaveAttribute("href", expectedSupportContact.href);
|
|
66
|
+
expect(links[1]).toHaveTextContent(expectedSupportContactText);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("omits contact link, when no support URL provided", () => {
|
|
70
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
71
|
+
appConfigSettings: footerConfig({ hasSupportContactUrl: false }),
|
|
72
|
+
});
|
|
73
|
+
// There should only be one link....
|
|
74
|
+
const links = container.querySelectorAll("a");
|
|
75
|
+
expect(links).toHaveLength(1);
|
|
76
|
+
|
|
77
|
+
// ... and it should be the TOS link, not a support contact link.
|
|
78
|
+
expect(links[0]).not.toHaveAttribute("href", expectedSupportContact.href);
|
|
79
|
+
expect(links[0]).toHaveAttribute("href", expectedTosHref);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("displays a default label for an https url", () => {
|
|
83
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
84
|
+
appConfigSettings: { supportContactUrl: "https://example.com/support" },
|
|
85
|
+
});
|
|
86
|
+
const links = container.querySelectorAll("a");
|
|
87
|
+
expect(links).toHaveLength(2);
|
|
88
|
+
expect(links[1]).toHaveAttribute("href", "https://example.com/support");
|
|
89
|
+
expect(links[1]).toHaveTextContent(
|
|
90
|
+
makeFooterSupportContactText(DEFAULT_SUPPORT_CONTACT_TEXT)
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("displays a custom label for an https url", () => {
|
|
95
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
96
|
+
appConfigSettings: {
|
|
97
|
+
supportContactUrl: "https://example.com/support",
|
|
98
|
+
supportContactText: "Custom Support Text",
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
const links = container.querySelectorAll("a");
|
|
102
|
+
expect(links).toHaveLength(2);
|
|
103
|
+
expect(links[1]).toHaveAttribute("href", "https://example.com/support");
|
|
104
|
+
expect(links[1]).toHaveTextContent(
|
|
105
|
+
makeFooterSupportContactText("Custom Support Text")
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("uses the deprecated support_contact_url if supportContactUrl is missing", () => {
|
|
110
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
111
|
+
appConfigSettings: {
|
|
112
|
+
support_contact_url: "https://example.com/deprecated-support",
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
const links = container.querySelectorAll("a");
|
|
116
|
+
expect(links).toHaveLength(2);
|
|
117
|
+
expect(links[1]).toHaveAttribute(
|
|
118
|
+
"href",
|
|
119
|
+
"https://example.com/deprecated-support"
|
|
120
|
+
);
|
|
121
|
+
expect(links[1]).toHaveTextContent(
|
|
122
|
+
makeFooterSupportContactText(DEFAULT_SUPPORT_CONTACT_TEXT)
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("displays a custom label for a mailto url", () => {
|
|
127
|
+
const { container } = renderWithProviders(<Footer />, {
|
|
128
|
+
appConfigSettings: {
|
|
129
|
+
supportContactUrl: "mailto:custom@example.com",
|
|
130
|
+
supportContactText: "Email Us Now",
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
const links = container.querySelectorAll("a");
|
|
134
|
+
expect(links).toHaveLength(2);
|
|
135
|
+
expect(links[1]).toHaveAttribute("href", "mailto:custom@example.com");
|
|
136
|
+
expect(links[1]).toHaveTextContent(
|
|
137
|
+
makeFooterSupportContactText("Email Us Now")
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -304,11 +304,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
304
304
|
const NO_EMAIL_CONTEXT_PROVIDER_PROPS = { email: undefined };
|
|
305
305
|
|
|
306
306
|
it("shows the modal when `show` is true", async () => {
|
|
307
|
-
const {
|
|
308
|
-
getAllByRole,
|
|
309
|
-
queryAllByRole,
|
|
310
|
-
rerender,
|
|
311
|
-
} = renderWithProviders(
|
|
307
|
+
const { getAllByRole, queryAllByRole, rerender } = renderWithProviders(
|
|
312
308
|
<InventoryReportRequestModal
|
|
313
309
|
show={false}
|
|
314
310
|
onHide={onHide}
|
|
@@ -385,19 +381,15 @@ describe("InventoryReportRequestModal", () => {
|
|
|
385
381
|
let show = true;
|
|
386
382
|
onHide.mockImplementation(() => (show = false));
|
|
387
383
|
|
|
388
|
-
const {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
library={LIBRARY}
|
|
398
|
-
/>,
|
|
399
|
-
{ queryClient }
|
|
400
|
-
);
|
|
384
|
+
const { getAllByRole, getByRole, queryAllByRole, rerender } =
|
|
385
|
+
renderWithProviders(
|
|
386
|
+
<InventoryReportRequestModal
|
|
387
|
+
show={show}
|
|
388
|
+
onHide={onHide}
|
|
389
|
+
library={LIBRARY}
|
|
390
|
+
/>,
|
|
391
|
+
{ queryClient }
|
|
392
|
+
);
|
|
401
393
|
getAllByRole("dialog");
|
|
402
394
|
expect(show).toBe(true);
|
|
403
395
|
expect(onHide).not.toHaveBeenCalled();
|
|
@@ -420,10 +412,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
420
412
|
});
|
|
421
413
|
|
|
422
414
|
it("updates confirmation message, if report info request arrives in time", async () => {
|
|
423
|
-
const {
|
|
424
|
-
getByRole,
|
|
425
|
-
rerender,
|
|
426
|
-
} = renderWithProviders(
|
|
415
|
+
const { getByRole, rerender } = renderWithProviders(
|
|
427
416
|
<InventoryReportRequestModal
|
|
428
417
|
show={true}
|
|
429
418
|
onHide={onHide}
|
|
@@ -457,10 +446,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
457
446
|
)
|
|
458
447
|
);
|
|
459
448
|
|
|
460
|
-
const {
|
|
461
|
-
getByRole,
|
|
462
|
-
rerender,
|
|
463
|
-
} = renderWithProviders(
|
|
449
|
+
const { getByRole, rerender } = renderWithProviders(
|
|
464
450
|
<InventoryReportRequestModal
|
|
465
451
|
show={true}
|
|
466
452
|
onHide={onHide}
|
|
@@ -505,10 +491,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
505
491
|
)
|
|
506
492
|
);
|
|
507
493
|
|
|
508
|
-
const {
|
|
509
|
-
getByRole,
|
|
510
|
-
rerender,
|
|
511
|
-
} = renderWithProviders(
|
|
494
|
+
const { getByRole, rerender } = renderWithProviders(
|
|
512
495
|
<InventoryReportRequestModal
|
|
513
496
|
show={true}
|
|
514
497
|
onHide={onHide}
|
|
@@ -538,10 +521,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
538
521
|
it("requests report generation, if request confirmed", async () => {
|
|
539
522
|
const user = userEvent.setup();
|
|
540
523
|
|
|
541
|
-
const {
|
|
542
|
-
getByRole,
|
|
543
|
-
rerender,
|
|
544
|
-
} = renderWithProviders(
|
|
524
|
+
const { getByRole, rerender } = renderWithProviders(
|
|
545
525
|
<InventoryReportRequestModal
|
|
546
526
|
show={true}
|
|
547
527
|
onHide={onHide}
|
|
@@ -574,10 +554,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
574
554
|
it("displays success message, when request is successful", async () => {
|
|
575
555
|
const user = userEvent.setup();
|
|
576
556
|
|
|
577
|
-
const {
|
|
578
|
-
getByRole,
|
|
579
|
-
rerender,
|
|
580
|
-
} = renderWithProviders(
|
|
557
|
+
const { getByRole, rerender } = renderWithProviders(
|
|
581
558
|
<InventoryReportRequestModal
|
|
582
559
|
show={true}
|
|
583
560
|
onHide={onHide}
|
|
@@ -615,10 +592,7 @@ describe("InventoryReportRequestModal", () => {
|
|
|
615
592
|
);
|
|
616
593
|
const user = userEvent.setup();
|
|
617
594
|
|
|
618
|
-
const {
|
|
619
|
-
getByRole,
|
|
620
|
-
rerender,
|
|
621
|
-
} = renderWithProviders(
|
|
595
|
+
const { getByRole, rerender } = renderWithProviders(
|
|
622
596
|
<InventoryReportRequestModal
|
|
623
597
|
show={true}
|
|
624
598
|
onHide={onHide}
|
|
@@ -19,13 +19,9 @@ const customListsData = [
|
|
|
19
19
|
{ id: 1, name: "list 1", entries: [], is_owner: true, is_shared: false },
|
|
20
20
|
];
|
|
21
21
|
|
|
22
|
-
const editLane = stub().returns(
|
|
23
|
-
new Promise<void>((resolve) => resolve())
|
|
24
|
-
);
|
|
22
|
+
const editLane = stub().returns(new Promise<void>((resolve) => resolve()));
|
|
25
23
|
|
|
26
|
-
const deleteLane = stub().returns(
|
|
27
|
-
new Promise<void>((resolve) => resolve())
|
|
28
|
-
);
|
|
24
|
+
const deleteLane = stub().returns(new Promise<void>((resolve) => resolve()));
|
|
29
25
|
|
|
30
26
|
const toggleLaneVisibility = stub();
|
|
31
27
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { screen, waitForElementToBeRemoved } from "@testing-library/react";
|
|
3
|
+
import * as fetchMock from "fetch-mock-jest";
|
|
4
|
+
|
|
5
|
+
import { renderWithProviders } from "../testUtils/withProviders";
|
|
6
|
+
|
|
7
|
+
// Header and Footer are page chrome; Header pulls in the react-router v3 context
|
|
8
|
+
// that renderWithProviders does not supply. Mock them to markers.
|
|
9
|
+
jest.mock("../../../src/components/Header", () => ({
|
|
10
|
+
__esModule: true,
|
|
11
|
+
default: () => <div data-testid="header" />,
|
|
12
|
+
}));
|
|
13
|
+
jest.mock("../../../src/components/Footer", () => ({
|
|
14
|
+
__esModule: true,
|
|
15
|
+
default: () => <div data-testid="footer" />,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
// The real Lanes child (and its sidebar/editor) renders React Router `Link`s,
|
|
19
|
+
// which need router context renderWithProviders does not supply. Mock `Link` to
|
|
20
|
+
// a marker, matching Lane.test.tsx.
|
|
21
|
+
jest.mock("react-router", () => ({
|
|
22
|
+
...jest.requireActual("react-router"),
|
|
23
|
+
Link: (props) => <div data-testid="Link">{props.children}</div>,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
import LanePage from "../../../src/components/LanePage";
|
|
27
|
+
|
|
28
|
+
describe("LanePage", () => {
|
|
29
|
+
beforeAll(() => {
|
|
30
|
+
Object.assign(fetchMock.config, { fetch, Headers, Request, Response });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
// Lanes fetches lanes and custom lists on mount; stub the network so no real
|
|
35
|
+
// request is made.
|
|
36
|
+
fetchMock.mock("*", { lanes: [], custom_lists: [] });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
fetchMock.restore();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("shows lanes with info from params", async () => {
|
|
44
|
+
const params = {
|
|
45
|
+
library: "library",
|
|
46
|
+
editOrCreate: "edit",
|
|
47
|
+
identifier: "5",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const { container } = renderWithProviders(<LanePage params={params} />);
|
|
51
|
+
|
|
52
|
+
// Header and Footer chrome are composed around the body.
|
|
53
|
+
expect(screen.getByTestId("header")).toBeInTheDocument();
|
|
54
|
+
expect(screen.getByTestId("footer")).toBeInTheDocument();
|
|
55
|
+
|
|
56
|
+
// The real Lanes child renders its container...
|
|
57
|
+
expect(container.querySelector("main.lanes-container")).toBeInTheDocument();
|
|
58
|
+
// ...and, because editOrCreate is "edit", its lane editor panel.
|
|
59
|
+
expect(container.querySelector(".lane-editor")).toBeInTheDocument();
|
|
60
|
+
|
|
61
|
+
// While its on-mount fetches (lanes and custom lists) are in flight, Lanes
|
|
62
|
+
// shows a loading indicator. Wait for it to clear so those fetches settle
|
|
63
|
+
// and their state updates flush, instead of racing a fixed-length timer.
|
|
64
|
+
await waitForElementToBeRemoved(() =>
|
|
65
|
+
screen.queryByRole("dialog", { name: "Loading" })
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import LanguageField from "../../../src/components/LanguageField";
|
|
5
|
+
|
|
6
|
+
describe("LanguageField", () => {
|
|
7
|
+
const languages = {
|
|
8
|
+
eng: ["English"],
|
|
9
|
+
es: ["Spanish", "Castilian"],
|
|
10
|
+
spa: ["Spanish", "Castilian"],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
it("renders an autocomplete field", () => {
|
|
14
|
+
const { container } = render(
|
|
15
|
+
<LanguageField name="language" languages={languages} />
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// An <input> with a `list` attribute has the implicit ARIA role "combobox".
|
|
19
|
+
const input = screen.getByRole("combobox");
|
|
20
|
+
expect(input).toHaveAttribute("name", "language");
|
|
21
|
+
expect(input).toHaveAttribute("list", "language-autocomplete-list");
|
|
22
|
+
expect(
|
|
23
|
+
container.querySelector("datalist#language-autocomplete-list")
|
|
24
|
+
).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("renders a unique, ordered list of language names as options", () => {
|
|
28
|
+
const { container } = render(
|
|
29
|
+
<LanguageField name="language" languages={languages} />
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const options = Array.from(
|
|
33
|
+
container.querySelectorAll<HTMLOptionElement>(
|
|
34
|
+
"#language-autocomplete-list option"
|
|
35
|
+
)
|
|
36
|
+
).map((option) => option.value);
|
|
37
|
+
|
|
38
|
+
expect(options).toStrictEqual(["English", "Spanish", "Castilian"]);
|
|
39
|
+
});
|
|
40
|
+
});
|