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

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 (133) hide show
  1. package/CLAUDE.md +28 -7
  2. package/README.md +11 -5
  3. package/dist/circulation-admin.js +1 -1
  4. package/eslint.config.mjs +9 -1
  5. package/jest.config.js +22 -8
  6. package/package.json +6 -20
  7. package/tests/jest/actions.test.ts +962 -0
  8. package/tests/jest/components/AccountPage.test.tsx +41 -0
  9. package/tests/jest/components/AdvancedSearchBooleanFilter.test.tsx +231 -0
  10. package/tests/jest/components/AdvancedSearchBuilder.test.tsx +93 -20
  11. package/tests/jest/components/AdvancedSearchFilter.test.tsx +142 -0
  12. package/tests/jest/components/AdvancedSearchFilterInput.test.tsx +212 -0
  13. package/tests/jest/components/AdvancedSearchFilterViewer.test.tsx +52 -0
  14. package/tests/jest/components/AdvancedSearchValueFilter.test.tsx +123 -0
  15. package/tests/jest/components/Announcement.test.tsx +76 -0
  16. package/tests/jest/components/AnnouncementForm.test.tsx +229 -0
  17. package/tests/jest/components/AnnouncementsSection.test.tsx +146 -0
  18. package/tests/jest/components/Autocomplete.test.tsx +67 -0
  19. package/tests/jest/components/BookCoverEditor.test.tsx +393 -0
  20. package/tests/jest/components/BookDetails.test.tsx +133 -0
  21. package/tests/jest/components/BookDetailsContainer.test.tsx +116 -0
  22. package/tests/jest/components/BookDetailsEditor.test.tsx +275 -0
  23. package/tests/jest/components/BookDetailsTabContainer.test.tsx +237 -0
  24. package/tests/jest/components/BookEditForm.test.tsx +352 -0
  25. package/tests/jest/components/BookEditor.test.tsx +20 -21
  26. package/tests/jest/components/CatalogPage.test.tsx +158 -0
  27. package/tests/jest/components/CatalogServices.test.tsx +100 -0
  28. package/tests/jest/components/ChangePasswordForm.test.tsx +163 -0
  29. package/tests/jest/components/CirculationEventsDownloadForm.test.tsx +41 -0
  30. package/tests/jest/components/Classifications.test.tsx +166 -0
  31. package/tests/jest/components/ClassificationsForm.test.tsx +458 -0
  32. package/tests/jest/components/ClassificationsTable.test.tsx +57 -0
  33. package/tests/jest/components/Collections.test.tsx +335 -7
  34. package/tests/jest/components/ColorPicker.test.tsx +58 -0
  35. package/tests/jest/components/ComplaintForm.test.tsx +171 -0
  36. package/tests/jest/components/Complaints.test.tsx +259 -0
  37. package/tests/jest/components/ConfigPage.test.tsx +58 -0
  38. package/tests/jest/components/ConfigTabContainer.test.tsx +196 -0
  39. package/tests/jest/components/ContextProvider.test.tsx +138 -0
  40. package/tests/jest/components/Contributors.test.tsx +157 -0
  41. package/tests/jest/components/CustomListEditor.test.tsx +367 -0
  42. package/tests/jest/components/CustomListEntriesEditor.test.tsx +1240 -0
  43. package/tests/jest/components/CustomListPage.test.tsx +57 -0
  44. package/tests/jest/components/CustomListSearch.test.tsx +275 -0
  45. package/tests/jest/components/CustomLists.test.tsx +621 -4
  46. package/tests/jest/components/CustomListsForBook.test.tsx +353 -0
  47. package/tests/jest/components/CustomListsSidebar.test.tsx +251 -0
  48. package/tests/jest/components/DashboardPage.test.tsx +76 -0
  49. package/tests/jest/components/DebugAuthentication.test.tsx +1 -5
  50. package/tests/jest/components/DiagnosticsServiceTabs.test.tsx +141 -0
  51. package/tests/jest/components/DiagnosticsServiceType.test.tsx +75 -0
  52. package/tests/jest/components/DiagnosticsTabContainer.test.tsx +147 -0
  53. package/tests/jest/components/DiscoveryServices.test.tsx +154 -7
  54. package/tests/jest/components/EditableConfigList.test.tsx +606 -9
  55. package/tests/jest/components/EditableInput.test.tsx +250 -1
  56. package/tests/jest/components/EditorField.test.tsx +95 -0
  57. package/tests/jest/components/EntryPointsContainer.test.tsx +97 -0
  58. package/tests/jest/components/EntryPointsTabs.test.tsx +88 -0
  59. package/tests/jest/components/ErrorMessage.test.tsx +97 -0
  60. package/tests/jest/components/Footer.test.tsx +141 -0
  61. package/tests/jest/components/GenreForm.test.tsx +152 -0
  62. package/tests/jest/components/Header.test.tsx +421 -0
  63. package/tests/jest/components/IndividualAdminEditForm.test.tsx +506 -1
  64. package/tests/jest/components/IndividualAdmins.test.tsx +124 -8
  65. package/tests/jest/components/InputList.test.tsx +493 -0
  66. package/tests/jest/components/InventoryReportRequestModal.test.tsx +16 -42
  67. package/tests/jest/components/JsonField.test.tsx +20 -0
  68. package/tests/jest/components/Lane.test.tsx +132 -10
  69. package/tests/jest/components/LaneCustomListsEditor.test.tsx +450 -0
  70. package/tests/jest/components/LaneEditor.test.tsx +377 -13
  71. package/tests/jest/components/LanePage.test.tsx +68 -0
  72. package/tests/jest/components/Lanes.test.tsx +446 -0
  73. package/tests/jest/components/LanesSidebar.test.tsx +621 -0
  74. package/tests/jest/components/LanguageField.test.tsx +40 -0
  75. package/tests/jest/components/Libraries.test.tsx +48 -0
  76. package/tests/jest/components/LibraryEditForm.test.tsx +383 -0
  77. package/tests/jest/components/LibraryRegistration.test.tsx +354 -0
  78. package/tests/jest/components/LibraryRegistrationForm.test.tsx +203 -0
  79. package/tests/jest/components/LoadButton.test.tsx +49 -0
  80. package/tests/jest/components/ManagePatrons.test.tsx +73 -0
  81. package/tests/jest/components/ManagePatronsForm.test.tsx +180 -0
  82. package/tests/jest/components/ManagePatronsTabContainer.test.tsx +143 -0
  83. package/tests/jest/components/MetadataServices.test.tsx +95 -0
  84. package/tests/jest/components/NeighborhoodAnalyticsForm.test.tsx +167 -0
  85. package/tests/jest/components/PairedMenus.test.tsx +220 -0
  86. package/tests/jest/components/PatronAuthServices.test.tsx +114 -0
  87. package/tests/jest/components/PatronBlockingRulesEditor.test.tsx +3 -1
  88. package/tests/jest/components/PatronInfo.test.tsx +54 -0
  89. package/tests/jest/components/ProtocolFormField.test.tsx +479 -7
  90. package/tests/jest/components/ResetAdobeId.test.tsx +302 -0
  91. package/tests/jest/components/SaveButton.test.tsx +47 -0
  92. package/tests/jest/components/SelfTestResult.test.tsx +164 -0
  93. package/tests/jest/components/SelfTests.test.tsx +601 -0
  94. package/tests/jest/components/SelfTestsCategory.test.tsx +200 -0
  95. package/tests/jest/components/SelfTestsTabContainer.test.tsx +216 -0
  96. package/tests/jest/components/ServiceEditForm.test.tsx +1092 -0
  97. package/tests/jest/components/ServiceWithRegistrationsEditForm.test.tsx +110 -0
  98. package/tests/jest/components/SetupPage.test.tsx +41 -0
  99. package/tests/jest/components/SingleStatListItem.test.tsx +62 -0
  100. package/tests/jest/components/SitewideAnnouncements.test.tsx +134 -0
  101. package/tests/jest/components/Stats.test.tsx +4 -15
  102. package/tests/jest/components/TabContainer.test.tsx +68 -0
  103. package/tests/jest/components/TextWithEditMode.test.tsx +218 -0
  104. package/tests/jest/components/Timestamp.test.tsx +74 -0
  105. package/tests/jest/components/ToolTip.test.tsx +46 -0
  106. package/tests/jest/components/TroubleshootingCategoryPage.test.tsx +69 -0
  107. package/tests/jest/components/TroubleshootingPage.test.tsx +94 -0
  108. package/tests/jest/components/TroubleshootingTabContainer.test.tsx +68 -0
  109. package/tests/jest/components/UpdatingLoader.test.tsx +36 -0
  110. package/tests/jest/components/WelcomePage.test.tsx +43 -0
  111. package/tests/jest/components/WithEditButton.test.tsx +55 -0
  112. package/tests/jest/components/WithRemoveButton.test.tsx +95 -0
  113. package/tests/jest/editorAdapter.test.ts +245 -0
  114. package/tests/jest/features/book.test.ts +75 -80
  115. package/tests/jest/fixtures/classificationsData.ts +45 -0
  116. package/tests/jest/fixtures/genreData.ts +811 -0
  117. package/tests/jest/index.test.tsx +50 -0
  118. package/tests/jest/models/Admin.test.ts +206 -0
  119. package/tests/jest/reducers/bookCoverPreview.test.ts +81 -0
  120. package/tests/jest/reducers/classifications.test.ts +161 -0
  121. package/tests/jest/reducers/collections.test.ts +96 -0
  122. package/tests/jest/reducers/complaints.test.ts +166 -0
  123. package/tests/jest/reducers/createFetchEditReducer.test.ts +220 -0
  124. package/tests/jest/reducers/createRegisterLibraryReducer.test.ts +51 -0
  125. package/tests/jest/reducers/customListDetails.test.ts +120 -0
  126. package/tests/jest/reducers/customListEditor.test.ts +2823 -0
  127. package/tests/jest/reducers/managePatrons.test.ts +71 -0
  128. package/tests/jest/testUtils/formDataShim.test.ts +135 -0
  129. package/tests/jest/testUtils/formDataShim.ts +112 -0
  130. package/tests/jest/utils/sharedFunctions.test.ts +121 -0
  131. package/tsconfig.json +3 -4
  132. package/testReporter.js +0 -29
  133. package/tests/jest/README.md +0 -6
@@ -0,0 +1,71 @@
1
+ import ManagePatrons from "../../../src/reducers/managePatrons";
2
+ import ActionCreator from "../../../src/actions";
3
+
4
+ describe("ManagePatrons reducer", () => {
5
+ const initState = {
6
+ data: null,
7
+ isFetching: false,
8
+ isEditing: false,
9
+ fetchError: null,
10
+ formError: null,
11
+ responseBody: null,
12
+ successMessage: null,
13
+ isLoaded: false,
14
+ };
15
+
16
+ it("returns initial state for unrecognized action", () => {
17
+ expect(ManagePatrons(undefined, {})).toStrictEqual(initState);
18
+ });
19
+
20
+ it("handles CLEAR_PATRON_DATA_LOAD", () => {
21
+ const action = {
22
+ type: `${ActionCreator.CLEAR_PATRON_DATA}_LOAD`,
23
+ data: null,
24
+ };
25
+ const oldPatronState = {
26
+ url: "test url",
27
+ data: {
28
+ authorization_expires: "",
29
+ authorization_identifier: "1234",
30
+ authorization_identifiers: [],
31
+ block_reason: "",
32
+ external_type: "",
33
+ fines: "",
34
+ permanent_id: "1234",
35
+ },
36
+ isFetching: true,
37
+ fetchError: null,
38
+ editError: null,
39
+ isLoaded: true,
40
+ isEditing: false,
41
+ };
42
+ const oldErrorState = {
43
+ url: "test url",
44
+ data: null,
45
+ isFetching: true,
46
+ fetchError: {
47
+ status: 400,
48
+ response: "No patron found",
49
+ url: "",
50
+ },
51
+ editError: null,
52
+ isLoaded: true,
53
+ isEditing: false,
54
+ };
55
+
56
+ const newPatronState = Object.assign({}, oldPatronState, {
57
+ data: null,
58
+ isFetching: false,
59
+ isLoaded: true,
60
+ });
61
+ const newErrorState = Object.assign({}, oldErrorState, {
62
+ data: null,
63
+ isFetching: false,
64
+ isLoaded: true,
65
+ fetchError: null,
66
+ });
67
+
68
+ expect(ManagePatrons(oldPatronState, action)).toStrictEqual(newPatronState);
69
+ expect(ManagePatrons(oldErrorState, action)).toStrictEqual(newErrorState);
70
+ });
71
+ });
@@ -0,0 +1,135 @@
1
+ import { FormDataShim } from "./formDataShim";
2
+
3
+ // Verifies the shim mirrors the browser's `new FormData(form)` "successful
4
+ // controls" rules — the fidelity that makes the payload assertions in the form
5
+ // suites (BookEditForm, SitewideAnnouncements, ...) trustworthy.
6
+ describe("FormDataShim", () => {
7
+ const formWith = (html: string): HTMLFormElement => {
8
+ const form = document.createElement("form");
9
+ form.innerHTML = html;
10
+ return form;
11
+ };
12
+
13
+ it("includes named, enabled text controls", () => {
14
+ const data = new FormDataShim(
15
+ formWith(`<input name="title" value="Dune" />`)
16
+ );
17
+ expect(data.get("title")).toBe("Dune");
18
+ });
19
+
20
+ it("skips disabled controls, as the browser does", () => {
21
+ const data = new FormDataShim(
22
+ formWith(`<input name="title" value="Dune" disabled />`)
23
+ );
24
+ expect(data.get("title")).toBeNull();
25
+ });
26
+
27
+ it("skips unnamed controls", () => {
28
+ const data = new FormDataShim(formWith(`<input value="anon" />`));
29
+ expect(data.get("")).toBeNull();
30
+ });
31
+
32
+ it("skips controls disabled by an ancestor fieldset", () => {
33
+ // A control inside <fieldset disabled> is a non-successful control even
34
+ // though its own `disabled` property is false. (Attached to the document so
35
+ // the :disabled match resolves ancestry.)
36
+ const form = formWith(
37
+ `<fieldset disabled><input name="inside" value="x" /></fieldset>
38
+ <input name="outside" value="y" />`
39
+ );
40
+ document.body.appendChild(form);
41
+ try {
42
+ const data = new FormDataShim(form);
43
+ expect(data.get("inside")).toBeNull();
44
+ expect(data.get("outside")).toBe("y");
45
+ } finally {
46
+ form.remove();
47
+ }
48
+ });
49
+
50
+ it("includes a checkbox only when it is checked", () => {
51
+ expect(
52
+ new FormDataShim(
53
+ formWith(`<input type="checkbox" name="agree" value="yes" />`)
54
+ ).get("agree")
55
+ ).toBeNull();
56
+ expect(
57
+ new FormDataShim(
58
+ formWith(`<input type="checkbox" name="agree" value="yes" checked />`)
59
+ ).get("agree")
60
+ ).toBe("yes");
61
+ });
62
+
63
+ it("includes only the checked radio in a group", () => {
64
+ const data = new FormDataShim(
65
+ formWith(
66
+ `<input type="radio" name="size" value="s" />
67
+ <input type="radio" name="size" value="m" checked />`
68
+ )
69
+ );
70
+ expect(data.get("size")).toBe("m");
71
+ });
72
+
73
+ it("excludes submit/reset/button inputs", () => {
74
+ const data = new FormDataShim(
75
+ formWith(`<input type="submit" name="go" value="Save" />`)
76
+ );
77
+ expect(data.get("go")).toBeNull();
78
+ });
79
+
80
+ it("omits file inputs (the browser submits them as File objects)", () => {
81
+ // Deliberate divergence from real FormData: a value-reading shim can't
82
+ // reproduce a File, so file fields are treated as absent rather than sent
83
+ // as their string value. Pinned so a regression can't silently re-add them.
84
+ const data = new FormDataShim(formWith(`<input type="file" name="doc" />`));
85
+ expect(data.get("doc")).toBeNull();
86
+ });
87
+
88
+ it("includes every selected option of a multi-select", () => {
89
+ const form = document.createElement("form");
90
+ const select = document.createElement("select");
91
+ select.name = "langs";
92
+ select.multiple = true;
93
+ (
94
+ [
95
+ ["en", true],
96
+ ["fr", false],
97
+ ["de", true],
98
+ ] as const
99
+ ).forEach(([value, selected]) => {
100
+ const option = document.createElement("option");
101
+ option.value = value;
102
+ option.selected = selected;
103
+ select.appendChild(option);
104
+ });
105
+ form.appendChild(select);
106
+
107
+ expect(new FormDataShim(form).getAll("langs")).toStrictEqual(["en", "de"]);
108
+ });
109
+
110
+ it("supports the standard read/write surface", () => {
111
+ const data = new FormDataShim();
112
+ data.append("k", "1");
113
+ data.append("k", "2");
114
+ expect(data.getAll("k")).toStrictEqual(["1", "2"]);
115
+ expect(data.has("k")).toBe(true);
116
+ data.set("k", "3");
117
+ expect(data.getAll("k")).toStrictEqual(["3"]);
118
+ data.delete("k");
119
+ expect(data.has("k")).toBe(false);
120
+ });
121
+
122
+ it("set() replaces the first entry in place and drops later duplicates", () => {
123
+ const data = new FormDataShim();
124
+ data.append("a", "1");
125
+ data.append("b", "2");
126
+ data.append("a", "3");
127
+
128
+ data.set("a", "9");
129
+
130
+ expect(Array.from(data.entries())).toStrictEqual([
131
+ ["a", "9"],
132
+ ["b", "2"],
133
+ ]);
134
+ });
135
+ });
@@ -0,0 +1,112 @@
1
+ // The unit jsdom environment installs undici's `FormData`, which throws on
2
+ // `new FormData(formElement)`. The reusable-components `Form` builds FormData
3
+ // that way on submit, so tests that assert a submitted payload need a stand-in.
4
+ //
5
+ // This shim mirrors the browser's `new FormData(form)`: it serializes only
6
+ // "successful controls" — named, non-disabled controls, with checkboxes and
7
+ // radios contributing only when checked, submit/reset/button/image/file inputs
8
+ // excluded, and every selected option of a multi-select included. A naive shim
9
+ // that records *every* named control can make a payload assertion pass while the
10
+ // real browser omits a disabled or unchecked field.
11
+ export class FormDataShim {
12
+ private items: Array<[string, string]> = [];
13
+
14
+ constructor(form?: HTMLFormElement) {
15
+ if (!form) {
16
+ return;
17
+ }
18
+ // Serializes the form's own descendant controls; the forms under test don't
19
+ // associate external controls via `form="id"`, so those are not collected.
20
+ form
21
+ .querySelectorAll<
22
+ HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
23
+ >("input, select, textarea")
24
+ .forEach((el) => {
25
+ // `:disabled` (not the `.disabled` property) so controls disabled via an
26
+ // ancestor `<fieldset disabled>` are omitted too, as the browser does.
27
+ if (!el.name || el.matches(":disabled")) {
28
+ return;
29
+ }
30
+ if (el instanceof HTMLInputElement) {
31
+ // Buttons never contribute a value. File inputs are omitted
32
+ // deliberately: the browser submits them as File objects, which a
33
+ // value-reading shim can't reproduce, so tests treat them as absent.
34
+ if (
35
+ ["submit", "reset", "button", "image", "file"].includes(el.type)
36
+ ) {
37
+ return;
38
+ }
39
+ if ((el.type === "checkbox" || el.type === "radio") && !el.checked) {
40
+ return;
41
+ }
42
+ }
43
+ if (el instanceof HTMLSelectElement && el.multiple) {
44
+ Array.from(el.selectedOptions).forEach((option) =>
45
+ this.items.push([el.name, option.value])
46
+ );
47
+ return;
48
+ }
49
+ this.items.push([el.name, el.value]);
50
+ });
51
+ }
52
+
53
+ get(key: string) {
54
+ const found = this.items.find(([k]) => k === key);
55
+ return found ? found[1] : null;
56
+ }
57
+ getAll(key: string) {
58
+ return this.items.filter(([k]) => k === key).map(([, v]) => v);
59
+ }
60
+ has(key: string) {
61
+ return this.items.some(([k]) => k === key);
62
+ }
63
+ append(key: string, value: string) {
64
+ this.items.push([key, value]);
65
+ }
66
+ set(key: string, value: string) {
67
+ // Replace the first matching entry in place and drop any later duplicates,
68
+ // preserving position as FormData.set does.
69
+ const firstIndex = this.items.findIndex(([k]) => k === key);
70
+ this.items = this.items.filter(([k]) => k !== key);
71
+ if (firstIndex === -1) {
72
+ this.items.push([key, value]);
73
+ } else {
74
+ this.items.splice(firstIndex, 0, [key, value]);
75
+ }
76
+ }
77
+ delete(key: string) {
78
+ this.items = this.items.filter(([k]) => k !== key);
79
+ }
80
+ forEach(
81
+ callback: (value: string, key: string, parent: FormDataShim) => void
82
+ ) {
83
+ this.items.forEach(([k, v]) => callback(v, k, this));
84
+ }
85
+ keys() {
86
+ return this.items.map(([k]) => k)[Symbol.iterator]();
87
+ }
88
+ values() {
89
+ return this.items.map(([, v]) => v)[Symbol.iterator]();
90
+ }
91
+ entries() {
92
+ return this.items
93
+ .map(([k, v]) => [k, v] as [string, string])
94
+ [Symbol.iterator]();
95
+ }
96
+ [Symbol.iterator]() {
97
+ return this.entries();
98
+ }
99
+ }
100
+
101
+ // Swaps `window.FormData` for the shim around a suite, restoring it afterward.
102
+ // Call once at the top level of a test file.
103
+ export function installFormDataShim(): void {
104
+ let originalFormData: typeof FormData;
105
+ beforeAll(() => {
106
+ originalFormData = window.FormData;
107
+ (window as any).FormData = FormDataShim;
108
+ });
109
+ afterAll(() => {
110
+ (window as any).FormData = originalFormData;
111
+ });
112
+ }
@@ -0,0 +1,121 @@
1
+ import {
2
+ findDefault,
3
+ formatString,
4
+ isEqual,
5
+ } from "../../../src/utils/sharedFunctions";
6
+
7
+ describe("findDefault", () => {
8
+ const settingWithoutDefaults = {
9
+ key: "test_setting_no_default",
10
+ options: [
11
+ { key: "true", label: "Yes" },
12
+ { key: "false", label: "No" },
13
+ ],
14
+ };
15
+
16
+ const settingWithOneDefault = {
17
+ default: "true",
18
+ key: "test_setting_1_default",
19
+ options: [
20
+ { key: "true", label: "Yes" },
21
+ { key: "false", label: "No" },
22
+ ],
23
+ };
24
+
25
+ const settingWithMultipleDefaults = {
26
+ default: ["first default", "second default"],
27
+ key: "test_setting_mult_defaults",
28
+ options: [
29
+ { key: "first default", label: "Yes" },
30
+ { key: "no", label: "No" },
31
+ { key: "second default", label: "This one too" },
32
+ { key: "also no", label: "Not this one" },
33
+ ],
34
+ };
35
+
36
+ it("doesn't return anything if the setting has no default value", () => {
37
+ const result = findDefault(settingWithoutDefaults);
38
+ expect(result).toBeUndefined();
39
+ });
40
+
41
+ it("identifies the default setting from a list of options", () => {
42
+ const result = findDefault(settingWithOneDefault);
43
+ expect(result.length).toBe(1);
44
+ expect(result[0].key).toBe("true");
45
+ expect(result[0].label).toBe("Yes");
46
+ });
47
+
48
+ it("identifies multiple default settings from a list of options", () => {
49
+ const result = findDefault(settingWithMultipleDefaults);
50
+ expect(result.length).toBe(2);
51
+ expect(result[0].key).toBe("first default");
52
+ expect(result[0].label).toBe("Yes");
53
+ expect(result[1].key).toBe("second default");
54
+ expect(result[1].label).toBe("This one too");
55
+ });
56
+ });
57
+
58
+ describe("formatString", () => {
59
+ const stringToFormat = "this-is-a-sentence.";
60
+ it("capitalizes the first letter of a string by default", () => {
61
+ const result = formatString(stringToFormat);
62
+ expect(result).toBe("This-is-a-sentence.");
63
+ });
64
+
65
+ it("can be prevented from capitalizing", () => {
66
+ const result = formatString(stringToFormat, null, false);
67
+ expect(result).toBe("this-is-a-sentence.");
68
+ });
69
+
70
+ it("replaces characters", () => {
71
+ const result = formatString(stringToFormat, ["-", " "], false);
72
+ expect(result).toBe("this is a sentence.");
73
+ });
74
+
75
+ it("replaces characters and capitalizes", () => {
76
+ const result = formatString(stringToFormat, ["-", "!"]);
77
+ expect(result).toBe("This!is!a!sentence.");
78
+ });
79
+
80
+ it("replaces multiple characters", () => {
81
+ const result = formatString("need-to-replace!multiple-characters", [
82
+ "-",
83
+ "!",
84
+ " ",
85
+ ]);
86
+ expect(result).toBe("Need to replace multiple characters");
87
+ });
88
+
89
+ it("defaults to replacing characters with a space", () => {
90
+ const result = formatString(stringToFormat, ["-"]);
91
+ expect(result).toBe("This is a sentence.");
92
+ });
93
+ });
94
+
95
+ describe("isEqual", () => {
96
+ const arr1 = ["a", "b", "c"];
97
+
98
+ it("returns false if the arrays are not the same length", () => {
99
+ const arr2 = ["a", "b", "c", "d"];
100
+ expect(isEqual(arr1, arr2)).toBe(false);
101
+ });
102
+ it("returns false if the lengths are the same but not all of the elements match", () => {
103
+ const arr2 = ["a", "b", "d"];
104
+ expect(isEqual(arr1, arr2)).toBe(false);
105
+ });
106
+ it("returns false if there are duplicates", () => {
107
+ const arr2 = ["a", "a", "b"];
108
+ expect(isEqual(arr1, arr2)).toBe(false);
109
+ });
110
+ it("returns true if the arrays are the same", () => {
111
+ const arr2 = ["a", "b", "c"];
112
+ expect(isEqual(arr1, arr2)).toBe(true);
113
+ });
114
+ it("returns true even if the arrays do not list the elements in the same order", () => {
115
+ const arr2 = ["b", "c", "a"];
116
+ expect(isEqual(arr1, arr2)).toBe(true);
117
+ });
118
+ it("returns true if the arrays have the same duplicates", () => {
119
+ expect(isEqual(["a", "a", "b"], ["b", "a", "a"])).toBe(true);
120
+ });
121
+ });
package/tsconfig.json CHANGED
@@ -6,11 +6,10 @@
6
6
  "outDir": "lib",
7
7
  "lib": ["es2023.array","es2019", "dom"],
8
8
  "rootDir": ".",
9
- // Mocha and jest are both used in this project. Certain globals are declared by both,
10
- // such as describe, it, and test. Setting skipLibCheck to true prevents typescript from
11
- // erroring when it sees duplicate variable declarations with different types.
9
+ // Some dependencies' type declarations (recharts, @open-draft/deferred-promise)
10
+ // do not compile under this project's `target` and `esModuleInterop` settings.
12
11
  "skipLibCheck": true,
13
- "types": ["mocha", "node", "jest", "@testing-library/jest-dom"],
12
+ "types": ["node", "jest", "@testing-library/jest-dom"],
14
13
  "jsx": "react"
15
14
  },
16
15
  "exclude": [
package/testReporter.js DELETED
@@ -1,29 +0,0 @@
1
- const mocha = require("mocha");
2
- const sinon = require("sinon");
3
- const color = require("colors-cli/safe");
4
-
5
- function TestReporter(runner) {
6
- // This isn't the place for warnings about soon-to-be-deprecated React methods, etc; we just want a clean list.
7
- console.warn = sinon.stub();
8
- console.error = sinon.stub();
9
-
10
- const {
11
- EVENT_SUITE_BEGIN,
12
- EVENT_TEST_BEGIN,
13
- EVENT_SUITE_END,
14
- } = mocha.Runner.constants;
15
-
16
- mocha.reporters.Base.call(this, runner);
17
-
18
- runner.on(EVENT_SUITE_BEGIN, function (suite) {
19
- console.group(color.x25.bold(suite.title));
20
- });
21
- runner.on(EVENT_TEST_BEGIN, function (test) {
22
- console.log(test.title);
23
- });
24
- runner.on(EVENT_SUITE_END, function () {
25
- console.groupEnd();
26
- });
27
- }
28
-
29
- module.exports = TestReporter;
@@ -1,6 +0,0 @@
1
- # Jest Unit Tests
2
-
3
- This directory contains unit tests that run using jest. The directory structure should mirror that of the `src` tree.
4
-
5
- To run these tests, use the command `npm run test-jest`. These tests are executed along with the older mocha-based tests when `npm test` is run.
6
- To run a single test file, use the command `npm run test-jest-file [filename]`.