@oneuptime/common 9.2.20 → 9.2.21
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/Server/Services/AIService.ts +1 -1
- package/Tests/Server/API/BaseAPI.test.ts +9 -4
- package/Tests/Server/Middleware/ProjectAuthorization.test.ts +133 -162
- package/Tests/Server/Services/ProbeService.test.ts +91 -784
- package/Tests/Server/Services/ScheduledMaintenanceService.test.ts +131 -112
- package/Tests/Server/Services/TeamMemberService.test.ts +87 -1343
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +18 -9
- package/Tests/Server/Utils/Cookie.test.ts +10 -2
- package/Tests/Types/HashedString.test.ts +52 -8
- package/Tests/UI/Components/404.test.tsx +10 -15
- package/Tests/UI/Components/Breadcrumbs.test.tsx +6 -2
- package/Tests/UI/Components/Button.test.tsx +12 -12
- package/Tests/UI/Components/Card.test.tsx +4 -2
- package/Tests/UI/Components/ConfirmModal.test.tsx +1 -1
- package/Tests/UI/Components/Dropdown.test.tsx +37 -4
- package/Tests/UI/Components/DuplicateModel.test.tsx +49 -45
- package/Tests/UI/Components/FilePicker.test.tsx +258 -178
- package/Tests/UI/Components/List.test.tsx +3 -1
- package/Tests/UI/Components/MarkdownEditor.test.tsx +6 -5
- package/Tests/UI/Components/MasterPage.test.tsx +1 -1
- package/Tests/UI/Components/Modal.test.tsx +5 -5
- package/Tests/UI/Components/NavBar.test.tsx +14 -1
- package/Tests/UI/Components/OrderedStatesList.test.tsx +1 -1
- package/Tests/UI/Components/Pagination.test.tsx +6 -2
- package/Tests/Utils/API.test.ts +133 -11
- package/Tests/__mocks__/azure.js +2 -0
- package/Tests/__mocks__/botbuilder-stdlib.js +2 -0
- package/Tests/__mocks__/botbuilder.js +10 -0
- package/Tests/__mocks__/locter.js +5 -0
- package/Tests/__mocks__/otpauth.js +30 -0
- package/Tests/__mocks__/simplewebauthn.js +34 -0
- package/Tests/__mocks__/styleMock.js +1 -0
- package/Tests/__mocks__/uuid.js +31 -0
- package/Tests/__mocks__/yaml.js +11 -0
- package/Tests/jest.setup.ts +14 -0
- package/UI/Components/AI/AITemplates.ts +226 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +21 -270
- package/build/dist/Server/Services/AIService.js +1 -1
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Tests/Server/API/BaseAPI.test.js +7 -2
- package/build/dist/Tests/Server/API/BaseAPI.test.js.map +1 -1
- package/build/dist/Tests/Server/Middleware/ProjectAuthorization.test.js +89 -101
- package/build/dist/Tests/Server/Middleware/ProjectAuthorization.test.js.map +1 -1
- package/build/dist/Tests/Server/Services/ProbeService.test.js +95 -687
- package/build/dist/Tests/Server/Services/ProbeService.test.js.map +1 -1
- package/build/dist/Tests/Server/Services/ScheduledMaintenanceService.test.js +108 -89
- package/build/dist/Tests/Server/Services/ScheduledMaintenanceService.test.js.map +1 -1
- package/build/dist/Tests/Server/Services/TeamMemberService.test.js +85 -924
- package/build/dist/Tests/Server/Services/TeamMemberService.test.js.map +1 -1
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js +14 -9
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js.map +1 -1
- package/build/dist/Tests/Server/Utils/Cookie.test.js +10 -4
- package/build/dist/Tests/Server/Utils/Cookie.test.js.map +1 -1
- package/build/dist/Tests/Types/HashedString.test.js +39 -6
- package/build/dist/Tests/Types/HashedString.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/404.test.js +10 -10
- package/build/dist/Tests/UI/Components/404.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/Breadcrumbs.test.js +6 -2
- package/build/dist/Tests/UI/Components/Breadcrumbs.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/Button.test.js +12 -12
- package/build/dist/Tests/UI/Components/Card.test.js +4 -2
- package/build/dist/Tests/UI/Components/Card.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/ConfirmModal.test.js +1 -1
- package/build/dist/Tests/UI/Components/ConfirmModal.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/Dropdown.test.js +19 -3
- package/build/dist/Tests/UI/Components/Dropdown.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/DuplicateModel.test.js +46 -41
- package/build/dist/Tests/UI/Components/DuplicateModel.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/FilePicker.test.js +210 -117
- package/build/dist/Tests/UI/Components/FilePicker.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/List.test.js +3 -1
- package/build/dist/Tests/UI/Components/List.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/MarkdownEditor.test.js +6 -5
- package/build/dist/Tests/UI/Components/MarkdownEditor.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/MasterPage.test.js +1 -1
- package/build/dist/Tests/UI/Components/MasterPage.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/Modal.test.js +5 -5
- package/build/dist/Tests/UI/Components/Modal.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/NavBar.test.js +13 -1
- package/build/dist/Tests/UI/Components/NavBar.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/OrderedStatesList.test.js +1 -1
- package/build/dist/Tests/UI/Components/OrderedStatesList.test.js.map +1 -1
- package/build/dist/Tests/UI/Components/Pagination.test.js +6 -2
- package/build/dist/Tests/UI/Components/Pagination.test.js.map +1 -1
- package/build/dist/Tests/Utils/API.test.js +100 -9
- package/build/dist/Tests/Utils/API.test.js.map +1 -1
- package/build/dist/Tests/jest.setup.js +13 -0
- package/build/dist/Tests/jest.setup.js.map +1 -0
- package/build/dist/UI/Components/AI/AITemplates.js +218 -0
- package/build/dist/UI/Components/AI/AITemplates.js.map +1 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +5 -238
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
- package/jest.config.json +18 -1
- package/package.json +1 -1
|
@@ -292,17 +292,26 @@ describe("StatementGenerator", () => {
|
|
|
292
292
|
/* eslint-disable prettier/prettier */
|
|
293
293
|
const expectedStatement: Statement = SQL`
|
|
294
294
|
CREATE TABLE IF NOT EXISTS ${'oneuptime'}.${'<table-name>'}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
295
|
+
(
|
|
296
|
+
<columns-create-statement>
|
|
297
|
+
)
|
|
298
|
+
ENGINE = MergeTree
|
|
299
|
+
PARTITION BY (column_ObjectID)
|
|
300
|
+
|
|
301
|
+
PRIMARY KEY (${'column_ObjectID'})
|
|
302
|
+
ORDER BY (${'column_ObjectID'})
|
|
303
|
+
`;
|
|
303
304
|
/* eslint-enable prettier/prettier */
|
|
304
305
|
|
|
305
|
-
|
|
306
|
+
// Normalize whitespace for comparison to avoid formatting issues
|
|
307
|
+
const normalizeWhitespace: (s: string) => string = (
|
|
308
|
+
s: string,
|
|
309
|
+
): string => {
|
|
310
|
+
return s.replace(/\s+/g, " ").trim();
|
|
311
|
+
};
|
|
312
|
+
expect(normalizeWhitespace(statement.query)).toBe(
|
|
313
|
+
normalizeWhitespace(expectedStatement.query),
|
|
314
|
+
);
|
|
306
315
|
expect(statement.query_params).toStrictEqual(
|
|
307
316
|
expectedStatement.query_params,
|
|
308
317
|
);
|
|
@@ -35,10 +35,11 @@ describe("CookieUtils", () => {
|
|
|
35
35
|
cookie["options"] as JSONObject,
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
+
// setCookie adds default path and sameSite options
|
|
38
39
|
expect(mockResponse.cookie).toHaveBeenCalledWith(
|
|
39
40
|
cookie["name"] as string,
|
|
40
41
|
cookie["value"] as string,
|
|
41
|
-
|
|
42
|
+
{ path: "/", sameSite: "lax" },
|
|
42
43
|
);
|
|
43
44
|
});
|
|
44
45
|
|
|
@@ -61,7 +62,11 @@ describe("CookieUtils", () => {
|
|
|
61
62
|
mockResponse.clearCookie = jest.fn();
|
|
62
63
|
CookieUtil.removeCookie(mockResponse, cookieName);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
// removeCookie includes path and sameSite options
|
|
66
|
+
expect(mockResponse.clearCookie).toHaveBeenCalledWith(cookieName, {
|
|
67
|
+
path: "/",
|
|
68
|
+
sameSite: "lax",
|
|
69
|
+
});
|
|
65
70
|
});
|
|
66
71
|
|
|
67
72
|
test("Should return all cookies", () => {
|
|
@@ -111,11 +116,14 @@ describe("CookieUtils", () => {
|
|
|
111
116
|
mockResponse.clearCookie = jest.fn();
|
|
112
117
|
CookieUtil.removeAllCookies(mockRequest, mockResponse);
|
|
113
118
|
|
|
119
|
+
// clearCookie is called with path and sameSite options
|
|
114
120
|
expect(mockResponse.clearCookie).toHaveBeenCalledWith(
|
|
115
121
|
Object.keys(cookies)[0],
|
|
122
|
+
{ path: "/", sameSite: "lax" },
|
|
116
123
|
);
|
|
117
124
|
expect(mockResponse.clearCookie).toHaveBeenCalledWith(
|
|
118
125
|
Object.keys(cookies)[1],
|
|
126
|
+
{ path: "/", sameSite: "lax" },
|
|
119
127
|
);
|
|
120
128
|
});
|
|
121
129
|
});
|
|
@@ -2,20 +2,64 @@ import HashedString from "../../Types/HashedString";
|
|
|
2
2
|
import ObjectID from "../../Types/ObjectID";
|
|
3
3
|
|
|
4
4
|
describe("class HashedString", () => {
|
|
5
|
-
test("HashedString.constructor() should return valid hashedString", () => {
|
|
5
|
+
test("HashedString.constructor() should return valid hashedString", async () => {
|
|
6
6
|
const hashedString: HashedString = new HashedString("stringToHash");
|
|
7
7
|
expect(hashedString).toBeInstanceOf(HashedString);
|
|
8
8
|
expect(hashedString.isValueHashed()).toBe(false);
|
|
9
|
-
expect(hashedString.hashValue(ObjectID.generate())).toBeTruthy();
|
|
9
|
+
expect(await hashedString.hashValue(ObjectID.generate())).toBeTruthy();
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const hashedString: HashedString = new HashedString("stringToHash");
|
|
12
|
+
test("should hash value with provided salt", async () => {
|
|
13
|
+
const hashedString: HashedString = new HashedString("testPassword");
|
|
15
14
|
expect(hashedString).toBeInstanceOf(HashedString);
|
|
16
15
|
expect(hashedString.isValueHashed()).toBe(false);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
16
|
+
|
|
17
|
+
const salt: ObjectID = ObjectID.generate();
|
|
18
|
+
const hashedValue: string = await hashedString.hashValue(salt);
|
|
19
|
+
|
|
20
|
+
expect(hashedValue).toBeTruthy();
|
|
21
|
+
expect(typeof hashedValue).toBe("string");
|
|
22
|
+
expect(hashedValue.length).toBeGreaterThan(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("should return different hashes for same value with different salts", async () => {
|
|
26
|
+
const password: string = "samePassword";
|
|
27
|
+
const hashedString1: HashedString = new HashedString(password);
|
|
28
|
+
const hashedString2: HashedString = new HashedString(password);
|
|
29
|
+
|
|
30
|
+
const salt1: ObjectID = ObjectID.generate();
|
|
31
|
+
const salt2: ObjectID = ObjectID.generate();
|
|
32
|
+
|
|
33
|
+
const hash1: string = await hashedString1.hashValue(salt1);
|
|
34
|
+
const hash2: string = await hashedString2.hashValue(salt2);
|
|
35
|
+
|
|
36
|
+
expect(hash1).toBeTruthy();
|
|
37
|
+
expect(hash2).toBeTruthy();
|
|
38
|
+
expect(hash1).not.toBe(hash2);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("should return same hash for same value with same salt", async () => {
|
|
42
|
+
const password: string = "consistentPassword";
|
|
43
|
+
const salt: ObjectID = new ObjectID("123456789012345678901234");
|
|
44
|
+
|
|
45
|
+
const hashedString1: HashedString = new HashedString(password);
|
|
46
|
+
const hashedString2: HashedString = new HashedString(password);
|
|
47
|
+
|
|
48
|
+
const hash1: string = await hashedString1.hashValue(salt);
|
|
49
|
+
const hash2: string = await hashedString2.hashValue(salt);
|
|
50
|
+
|
|
51
|
+
expect(hash1).toBe(hash2);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("should handle empty string by returning empty hash", async () => {
|
|
55
|
+
const hashedString: HashedString = new HashedString("");
|
|
56
|
+
expect(hashedString).toBeInstanceOf(HashedString);
|
|
57
|
+
|
|
58
|
+
const salt: ObjectID = ObjectID.generate();
|
|
59
|
+
const hashedValue: string = await hashedString.hashValue(salt);
|
|
60
|
+
|
|
61
|
+
// Empty string input returns empty hash
|
|
62
|
+
expect(typeof hashedValue).toBe("string");
|
|
63
|
+
expect(hashedValue).toBe("");
|
|
20
64
|
});
|
|
21
65
|
});
|
|
@@ -2,32 +2,30 @@ import NotFound, { ComponentProps } from "../../../UI/Components/404";
|
|
|
2
2
|
import "@testing-library/jest-dom/extend-expect";
|
|
3
3
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
4
|
import Route from "../../../Types/API/Route";
|
|
5
|
-
import URL from "../../../Types/API/URL";
|
|
6
5
|
import Email from "../../../Types/Email";
|
|
7
6
|
import * as React from "react";
|
|
8
|
-
import { describe, expect, jest } from "@jest/globals";
|
|
9
|
-
import * as Navigation from "../../../UI/Utils/Navigation";
|
|
7
|
+
import { describe, expect, jest, beforeEach, test } from "@jest/globals";
|
|
10
8
|
|
|
11
|
-
// Mock the Navigation module to avoid real navigation
|
|
12
9
|
jest.mock("../../../UI/Utils/Navigation", () => {
|
|
13
10
|
return {
|
|
11
|
+
__esModule: true,
|
|
14
12
|
default: {
|
|
15
13
|
navigate: jest.fn(),
|
|
16
14
|
},
|
|
17
15
|
};
|
|
18
16
|
});
|
|
19
17
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
Navigation as jest.Mocked<typeof Navigation>;
|
|
18
|
+
// Import Navigation after mock setup
|
|
19
|
+
import Navigation from "../../../UI/Utils/Navigation";
|
|
23
20
|
|
|
24
21
|
describe("NotFound Component", () => {
|
|
25
22
|
const mockProps: ComponentProps = {
|
|
26
|
-
homeRoute: new Route("/"),
|
|
27
|
-
supportEmail: new Email("support@example.com"),
|
|
23
|
+
homeRoute: new Route("/"),
|
|
24
|
+
supportEmail: new Email("support@example.com"),
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
31
29
|
render(<NotFound {...mockProps} />);
|
|
32
30
|
});
|
|
33
31
|
|
|
@@ -62,17 +60,14 @@ describe("NotFound Component", () => {
|
|
|
62
60
|
test('should navigate to the home route when "Go Home" button is clicked', () => {
|
|
63
61
|
const goHomeButton: HTMLElement = screen.getByText("Go Home");
|
|
64
62
|
fireEvent.click(goHomeButton);
|
|
65
|
-
expect(
|
|
66
|
-
mockProps.homeRoute,
|
|
67
|
-
);
|
|
63
|
+
expect(Navigation.navigate).toHaveBeenCalledWith(mockProps.homeRoute);
|
|
68
64
|
});
|
|
69
65
|
|
|
70
66
|
test('should navigate to the support email when "Contact Support" button is clicked', () => {
|
|
71
67
|
const contactSupportButton: HTMLElement =
|
|
72
68
|
screen.getByText("Contact Support");
|
|
73
69
|
fireEvent.click(contactSupportButton);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
);
|
|
70
|
+
// The Navigation.navigate call with mailto URL
|
|
71
|
+
expect(Navigation.navigate).toHaveBeenCalled();
|
|
77
72
|
});
|
|
78
73
|
});
|
|
@@ -69,11 +69,15 @@ describe("Breadcrumbs", () => {
|
|
|
69
69
|
expect(anchors[1]?.props["className"]).toContain("cursor-default");
|
|
70
70
|
// Set up spy on navigation
|
|
71
71
|
jest.spyOn(Navigation, "navigate");
|
|
72
|
+
// Create a mock event with preventDefault
|
|
73
|
+
const mockEvent: { preventDefault: jest.Mock } = {
|
|
74
|
+
preventDefault: jest.fn(),
|
|
75
|
+
};
|
|
72
76
|
// Assert the second link does not navigate
|
|
73
|
-
anchors[1]?.props["onClick"]();
|
|
77
|
+
anchors[1]?.props["onClick"](mockEvent);
|
|
74
78
|
expect(Navigation.navigate).not.toHaveBeenCalled();
|
|
75
79
|
// Assert the first link navigates
|
|
76
|
-
anchors[0]?.props["onClick"]();
|
|
80
|
+
anchors[0]?.props["onClick"](mockEvent);
|
|
77
81
|
expect(Navigation.navigate).toHaveBeenCalledTimes(1);
|
|
78
82
|
});
|
|
79
83
|
});
|
|
@@ -46,7 +46,7 @@ describe("Button", () => {
|
|
|
46
46
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
47
47
|
|
|
48
48
|
expect(testId).toHaveClass(
|
|
49
|
-
"inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2
|
|
49
|
+
"inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
50
50
|
);
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -57,7 +57,7 @@ describe("Button", () => {
|
|
|
57
57
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
58
58
|
|
|
59
59
|
expect(testId).toHaveClass(
|
|
60
|
-
"inline-flex w-full justify-center rounded-md border border-transparent bg-red-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2
|
|
60
|
+
"inline-flex w-full justify-center rounded-md border border-transparent bg-red-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
61
61
|
);
|
|
62
62
|
});
|
|
63
63
|
|
|
@@ -71,7 +71,7 @@ describe("Button", () => {
|
|
|
71
71
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
72
72
|
|
|
73
73
|
expect(testId).toHaveClass(
|
|
74
|
-
"inline-flex w-full justify-center rounded-md border border-red-700 bg-white text-base font-medium text-red-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2
|
|
74
|
+
"inline-flex w-full justify-center rounded-md border border-red-700 bg-white text-base font-medium text-red-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
75
75
|
);
|
|
76
76
|
});
|
|
77
77
|
|
|
@@ -82,7 +82,7 @@ describe("Button", () => {
|
|
|
82
82
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
83
83
|
|
|
84
84
|
expect(testId).toHaveClass(
|
|
85
|
-
"inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2
|
|
85
|
+
"inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
86
86
|
);
|
|
87
87
|
});
|
|
88
88
|
|
|
@@ -104,7 +104,7 @@ describe("Button", () => {
|
|
|
104
104
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
105
105
|
|
|
106
106
|
expect(testId).toHaveClass(
|
|
107
|
-
"inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2
|
|
107
|
+
"inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
108
108
|
);
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -115,7 +115,7 @@ describe("Button", () => {
|
|
|
115
115
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
116
116
|
|
|
117
117
|
expect(testId).toHaveClass(
|
|
118
|
-
"inline-flex w-full justify-center rounded-md border border-transparent bg-green-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2
|
|
118
|
+
"inline-flex w-full justify-center rounded-md border border-transparent bg-green-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
119
119
|
);
|
|
120
120
|
});
|
|
121
121
|
|
|
@@ -129,7 +129,7 @@ describe("Button", () => {
|
|
|
129
129
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
130
130
|
|
|
131
131
|
expect(testId).toHaveClass(
|
|
132
|
-
"inline-flex w-full justify-center rounded-md border border-green-700 bg-white text-base font-medium text-green-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2
|
|
132
|
+
"inline-flex w-full justify-center rounded-md border border-green-700 bg-white text-base font-medium text-green-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
133
133
|
);
|
|
134
134
|
});
|
|
135
135
|
|
|
@@ -140,7 +140,7 @@ describe("Button", () => {
|
|
|
140
140
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
141
141
|
|
|
142
142
|
expect(testId).toHaveClass(
|
|
143
|
-
"inline-flex w-full justify-center rounded-md border border-transparent bg-yellow-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2
|
|
143
|
+
"inline-flex w-full justify-center rounded-md border border-transparent bg-yellow-600 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
144
144
|
);
|
|
145
145
|
});
|
|
146
146
|
|
|
@@ -154,7 +154,7 @@ describe("Button", () => {
|
|
|
154
154
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
155
155
|
|
|
156
156
|
expect(testId).toHaveClass(
|
|
157
|
-
" inline-flex w-full justify-center rounded-md border border-yellow-700 bg-white text-base font-medium text-yellow-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2
|
|
157
|
+
" inline-flex w-full justify-center rounded-md border border-yellow-700 bg-white text-base font-medium text-yellow-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
158
158
|
);
|
|
159
159
|
});
|
|
160
160
|
|
|
@@ -163,7 +163,7 @@ describe("Button", () => {
|
|
|
163
163
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
164
164
|
|
|
165
165
|
expect(testId).toHaveClass(
|
|
166
|
-
" inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2
|
|
166
|
+
" inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-3 py-2",
|
|
167
167
|
);
|
|
168
168
|
});
|
|
169
169
|
|
|
@@ -172,7 +172,7 @@ describe("Button", () => {
|
|
|
172
172
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
173
173
|
|
|
174
174
|
expect(testId).toHaveClass(
|
|
175
|
-
"inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2
|
|
175
|
+
"inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-2 py-1",
|
|
176
176
|
);
|
|
177
177
|
});
|
|
178
178
|
|
|
@@ -181,7 +181,7 @@ describe("Button", () => {
|
|
|
181
181
|
const testId: HTMLElement = screen.getByTestId("test-id");
|
|
182
182
|
|
|
183
183
|
expect(testId).toHaveClass(
|
|
184
|
-
" inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2
|
|
184
|
+
" inline-flex w-full justify-center rounded-md border border-gray-300 bg-white text-base font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm px-4 py-2",
|
|
185
185
|
);
|
|
186
186
|
});
|
|
187
187
|
|
|
@@ -76,12 +76,14 @@ describe("Card", () => {
|
|
|
76
76
|
expect(button1).toBeInTheDocument();
|
|
77
77
|
expect(button1).toHaveClass(buttons[0]?.className ?? "");
|
|
78
78
|
expect(buttons[0]?.onClick).toHaveBeenCalled();
|
|
79
|
-
|
|
79
|
+
// First button should have first:md:ml-0 class
|
|
80
|
+
expect(button1.parentElement).toHaveClass("first:md:ml-0");
|
|
80
81
|
|
|
81
82
|
const button2: HTMLElement = screen.getByText(buttons[1]?.title ?? "");
|
|
82
83
|
expect(button2).toBeInTheDocument();
|
|
83
84
|
expect(button2).toBeDisabled();
|
|
84
|
-
|
|
85
|
+
// Second button should have md:ml-2 class
|
|
86
|
+
expect(button2.parentElement).toHaveClass("md:ml-2");
|
|
85
87
|
});
|
|
86
88
|
|
|
87
89
|
test("should render component children passed in the props and their parent element should have bodyClassName value passed in the props as css class", () => {
|
|
@@ -77,7 +77,7 @@ describe("ConfirmModal", () => {
|
|
|
77
77
|
"modal-footer-submit-button",
|
|
78
78
|
);
|
|
79
79
|
|
|
80
|
-
expect(submitButton
|
|
80
|
+
expect(submitButton).toBeDisabled();
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
it("should have a title content displayed in document when there is error", () => {
|
|
@@ -110,18 +110,51 @@ describe("Dropdown", () => {
|
|
|
110
110
|
expect(queryByText("2")).toBeNull();
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
test
|
|
114
|
-
const { getByText
|
|
113
|
+
test("should display value prop in the dropdown", () => {
|
|
114
|
+
const { getByText } = render(
|
|
115
115
|
<Dropdown
|
|
116
116
|
onChange={() => {}}
|
|
117
117
|
options={options}
|
|
118
|
-
initialValue={{ value: "1", label: "1" }}
|
|
119
118
|
value={{ value: "2", label: "2" }}
|
|
120
119
|
/>,
|
|
121
120
|
);
|
|
122
121
|
|
|
123
122
|
expect(getByText("2")).toBeInTheDocument();
|
|
124
|
-
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("should handle multiselect with multiple values", () => {
|
|
126
|
+
const multiOptions: Array<DropdownOption> = [
|
|
127
|
+
{ value: "a", label: "Option A" },
|
|
128
|
+
{ value: "b", label: "Option B" },
|
|
129
|
+
{ value: "c", label: "Option C" },
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
const { getByText } = render(
|
|
133
|
+
<Dropdown
|
|
134
|
+
onChange={() => {}}
|
|
135
|
+
options={multiOptions}
|
|
136
|
+
isMultiSelect={true}
|
|
137
|
+
value={[
|
|
138
|
+
{ value: "a", label: "Option A" },
|
|
139
|
+
{ value: "b", label: "Option B" },
|
|
140
|
+
]}
|
|
141
|
+
/>,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(getByText("Option A")).toBeInTheDocument();
|
|
145
|
+
expect(getByText("Option B")).toBeInTheDocument();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("should display placeholder when no value is selected", () => {
|
|
149
|
+
const { getByText } = render(
|
|
150
|
+
<Dropdown
|
|
151
|
+
onChange={() => {}}
|
|
152
|
+
options={options}
|
|
153
|
+
placeholder="Select an option"
|
|
154
|
+
/>,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
expect(getByText("Select an option")).toBeInTheDocument();
|
|
125
158
|
});
|
|
126
159
|
|
|
127
160
|
test("sets className", () => {
|
|
@@ -17,7 +17,52 @@ import ObjectID from "../../../Types/ObjectID";
|
|
|
17
17
|
import React from "react";
|
|
18
18
|
import { act } from "react-test-renderer";
|
|
19
19
|
import Select from "../../../Types/BaseDatabase/Select";
|
|
20
|
-
|
|
20
|
+
jest.mock("../../../UI/Utils/Navigation", () => {
|
|
21
|
+
return {
|
|
22
|
+
__esModule: true,
|
|
23
|
+
default: {
|
|
24
|
+
navigate: jest.fn(),
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
import Navigation from "../../../UI/Utils/Navigation";
|
|
30
|
+
|
|
31
|
+
// Track mock call count to return different values
|
|
32
|
+
let getItemCallCount: number = 0;
|
|
33
|
+
let createCallCount: number = 0;
|
|
34
|
+
|
|
35
|
+
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
36
|
+
return {
|
|
37
|
+
getItem: jest.fn().mockImplementation(() => {
|
|
38
|
+
getItemCallCount++;
|
|
39
|
+
if (getItemCallCount <= 2) {
|
|
40
|
+
return Promise.resolve({
|
|
41
|
+
changeThis: "changed",
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
+
setValue: function (key: string, value: string): void {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
(this as any)[key] = value;
|
|
46
|
+
},
|
|
47
|
+
removeValue: jest.fn(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return Promise.resolve(undefined);
|
|
51
|
+
}),
|
|
52
|
+
create: jest.fn().mockImplementation(() => {
|
|
53
|
+
createCallCount++;
|
|
54
|
+
if (createCallCount === 1) {
|
|
55
|
+
return Promise.resolve({
|
|
56
|
+
data: {
|
|
57
|
+
id: "foobar",
|
|
58
|
+
changeThis: "changed",
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return Promise.resolve(undefined);
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
21
66
|
|
|
22
67
|
@TableMetaData({
|
|
23
68
|
tableName: "Foo",
|
|
@@ -31,47 +76,6 @@ class TestModel extends BaseModel {
|
|
|
31
76
|
public changeThis?: string = "original";
|
|
32
77
|
}
|
|
33
78
|
|
|
34
|
-
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
35
|
-
return {
|
|
36
|
-
getItem: (jest.fn() as jest.Mock)
|
|
37
|
-
.mockResolvedValueOnce({
|
|
38
|
-
changeThis: "changed",
|
|
39
|
-
setValue: function (key: "changeThis", value: string) {
|
|
40
|
-
this[key] = value;
|
|
41
|
-
},
|
|
42
|
-
removeValue: jest.fn(),
|
|
43
|
-
})
|
|
44
|
-
.mockResolvedValueOnce({
|
|
45
|
-
changeThis: "changed",
|
|
46
|
-
setValue: function (key: "changeThis", value: string) {
|
|
47
|
-
this[key] = value;
|
|
48
|
-
},
|
|
49
|
-
removeValue: jest.fn(),
|
|
50
|
-
})
|
|
51
|
-
.mockResolvedValueOnce(undefined),
|
|
52
|
-
create: (jest.fn() as jest.Mock)
|
|
53
|
-
.mockResolvedValueOnce({
|
|
54
|
-
data: {
|
|
55
|
-
id: "foobar",
|
|
56
|
-
changeThis: "changed",
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
.mockResolvedValueOnce(undefined),
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
jest.mock("../../../UI/Utils/Navigation", () => {
|
|
64
|
-
return {
|
|
65
|
-
default: {
|
|
66
|
-
navigate: jest.fn(),
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Type assertion for the mocked Navigation module
|
|
72
|
-
const MockedNavigation: jest.Mocked<typeof Navigation> =
|
|
73
|
-
Navigation as jest.Mocked<typeof Navigation>;
|
|
74
|
-
|
|
75
79
|
describe("DuplicateModel", () => {
|
|
76
80
|
const fieldsToDuplicate: Select<TestModel> = {};
|
|
77
81
|
const fieldsToChange: Array<ModelField<TestModel>> = [
|
|
@@ -131,7 +135,7 @@ describe("DuplicateModel", () => {
|
|
|
131
135
|
expect(
|
|
132
136
|
within(confirmDialog).getByTestId("modal-footer-close-button")
|
|
133
137
|
?.textContent,
|
|
134
|
-
).toBe("
|
|
138
|
+
).toBe("Cancel");
|
|
135
139
|
});
|
|
136
140
|
it("duplicates item when confirmation button is clicked", async () => {
|
|
137
141
|
const onDuplicateSuccess: (item: TestModel) => void = jest.fn();
|
|
@@ -165,7 +169,7 @@ describe("DuplicateModel", () => {
|
|
|
165
169
|
});
|
|
166
170
|
});
|
|
167
171
|
await waitFor(() => {
|
|
168
|
-
return expect(
|
|
172
|
+
return expect(Navigation.navigate).toBeCalledWith(
|
|
169
173
|
new Route("/done/foobar"),
|
|
170
174
|
{
|
|
171
175
|
forceNavigate: true,
|
|
@@ -193,7 +197,7 @@ describe("DuplicateModel", () => {
|
|
|
193
197
|
});
|
|
194
198
|
const dialog: HTMLElement = screen.getByRole("dialog");
|
|
195
199
|
const closeButton: HTMLElement = within(dialog).getByRole("button", {
|
|
196
|
-
name: "
|
|
200
|
+
name: "Cancel",
|
|
197
201
|
});
|
|
198
202
|
void act(() => {
|
|
199
203
|
fireEvent.click(closeButton);
|