@oneuptime/common 9.2.18 → 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/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +78 -1
- package/Server/Utils/Workspace/Slack/Slack.ts +80 -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/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +59 -2
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +61 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.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
|
@@ -2,15 +2,7 @@ import FilePicker from "../../../UI/Components/FilePicker/FilePicker";
|
|
|
2
2
|
import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
|
|
3
3
|
import { describe, expect, beforeEach, jest } from "@jest/globals";
|
|
4
4
|
import "@testing-library/jest-dom/extend-expect";
|
|
5
|
-
import {
|
|
6
|
-
fireEvent,
|
|
7
|
-
queryAllByAttribute,
|
|
8
|
-
queryByAttribute,
|
|
9
|
-
queryByTestId,
|
|
10
|
-
render,
|
|
11
|
-
screen,
|
|
12
|
-
waitFor,
|
|
13
|
-
} from "@testing-library/react";
|
|
5
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
14
6
|
import HTTPResponse from "../../../Types/API/HTTPResponse";
|
|
15
7
|
import MimeType from "../../../Types/File/MimeType";
|
|
16
8
|
import ObjectID from "../../../Types/ObjectID";
|
|
@@ -22,6 +14,8 @@ import Faker from "../../../Utils/Faker";
|
|
|
22
14
|
|
|
23
15
|
const mockOnChange: MockFunction = getJestMockFunction();
|
|
24
16
|
const mockOnBlur: MockFunction = getJestMockFunction();
|
|
17
|
+
const mockOnFocus: MockFunction = getJestMockFunction();
|
|
18
|
+
const mockOnClick: MockFunction = getJestMockFunction();
|
|
25
19
|
|
|
26
20
|
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
27
21
|
return {
|
|
@@ -39,6 +33,11 @@ interface DefaultProps {
|
|
|
39
33
|
value?: FileModel[] | undefined;
|
|
40
34
|
isMultiFilePicker?: boolean;
|
|
41
35
|
readOnly?: boolean;
|
|
36
|
+
placeholder?: string;
|
|
37
|
+
onFocus?: () => void;
|
|
38
|
+
onClick?: () => void;
|
|
39
|
+
error?: string;
|
|
40
|
+
dataTestId?: string;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
interface DataTransfer {
|
|
@@ -55,25 +54,22 @@ type MockCreateResponseFunction = (
|
|
|
55
54
|
const mockCreateResponse: MockCreateResponseFunction = async (
|
|
56
55
|
file: File,
|
|
57
56
|
): Promise<HTTPResponse<FileModel>> => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
isPublic: true,
|
|
66
|
-
},
|
|
67
|
-
{},
|
|
68
|
-
);
|
|
57
|
+
const fileModel: FileModel = new FileModel();
|
|
58
|
+
fileModel.file = Buffer.from(await file.arrayBuffer());
|
|
59
|
+
fileModel.name = file.name;
|
|
60
|
+
fileModel.fileType = file.type as MimeType;
|
|
61
|
+
fileModel.slug = file.name;
|
|
62
|
+
fileModel.isPublic = true;
|
|
63
|
+
return new HTTPResponse(200, fileModel as any, {});
|
|
69
64
|
};
|
|
70
65
|
|
|
71
|
-
type MockFileModelFunction = (file: File) => Promise<FileModel>;
|
|
66
|
+
type MockFileModelFunction = (file: File, id?: string) => Promise<FileModel>;
|
|
72
67
|
|
|
73
68
|
const mockFileModel: MockFileModelFunction = async (
|
|
74
69
|
file: File,
|
|
70
|
+
id?: string,
|
|
75
71
|
): Promise<FileModel> => {
|
|
76
|
-
const fileModel: FileModel = new FileModel(new ObjectID("123"));
|
|
72
|
+
const fileModel: FileModel = new FileModel(new ObjectID(id || "123"));
|
|
77
73
|
fileModel.name = file.name;
|
|
78
74
|
fileModel.fileType = file.type as MimeType;
|
|
79
75
|
fileModel.slug = file.name;
|
|
@@ -82,17 +78,16 @@ const mockFileModel: MockFileModelFunction = async (
|
|
|
82
78
|
return fileModel;
|
|
83
79
|
};
|
|
84
80
|
|
|
85
|
-
type MockFileFunction = () => File;
|
|
81
|
+
type MockFileFunction = (name?: string) => File;
|
|
86
82
|
|
|
87
|
-
const mockFile: MockFileFunction = (): File => {
|
|
83
|
+
const mockFile: MockFileFunction = (name?: string): File => {
|
|
88
84
|
const mockArrayBuffer: MockFunction = getJestMockFunction();
|
|
89
85
|
mockArrayBuffer.mockResolvedValue(new ArrayBuffer(10)); // Mocked array buffer of size 10
|
|
90
86
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
);
|
|
87
|
+
const fileName: string = name || Faker.generateRandomString() + ".png";
|
|
88
|
+
const file: File = new File([Faker.generateRandomString()], fileName, {
|
|
89
|
+
type: MimeType.png,
|
|
90
|
+
});
|
|
96
91
|
file.arrayBuffer = mockArrayBuffer;
|
|
97
92
|
return file;
|
|
98
93
|
};
|
|
@@ -106,89 +101,115 @@ const defaultProps: DefaultProps = {
|
|
|
106
101
|
};
|
|
107
102
|
|
|
108
103
|
describe("FilePicker", () => {
|
|
109
|
-
const MOCK_FILE_URL: string = "https://mock-file-url";
|
|
110
|
-
|
|
111
|
-
beforeAll(() => {
|
|
112
|
-
global.URL.createObjectURL = jest.fn(() => {
|
|
113
|
-
return MOCK_FILE_URL;
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
afterAll(() => {
|
|
118
|
-
(
|
|
119
|
-
global.URL.createObjectURL as jest.MockedFunction<
|
|
120
|
-
typeof global.URL.createObjectURL
|
|
121
|
-
>
|
|
122
|
-
).mockRestore();
|
|
123
|
-
});
|
|
124
|
-
|
|
125
104
|
beforeEach(() => {
|
|
105
|
+
jest.clearAllMocks();
|
|
126
106
|
delete defaultProps.isMultiFilePicker;
|
|
127
107
|
delete defaultProps.initialValue;
|
|
128
108
|
delete defaultProps.value;
|
|
129
109
|
delete defaultProps.readOnly;
|
|
110
|
+
delete defaultProps.placeholder;
|
|
111
|
+
delete defaultProps.onFocus;
|
|
112
|
+
delete defaultProps.onClick;
|
|
113
|
+
delete defaultProps.error;
|
|
114
|
+
delete defaultProps.dataTestId;
|
|
130
115
|
});
|
|
131
116
|
|
|
117
|
+
// Basic rendering tests
|
|
132
118
|
it("should render without crashing", () => {
|
|
133
119
|
render(<FilePicker {...defaultProps} />);
|
|
134
|
-
expect(screen.getByText("Upload
|
|
135
|
-
expect(screen.getByRole("complementary")).toBeInTheDocument(); // aside element
|
|
120
|
+
expect(screen.getByText("Upload files")).toBeInTheDocument();
|
|
136
121
|
});
|
|
137
122
|
|
|
138
|
-
it("should render with
|
|
139
|
-
defaultProps.
|
|
140
|
-
|
|
141
|
-
expect(
|
|
142
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
143
|
-
).toBeInTheDocument();
|
|
123
|
+
it("should render with custom placeholder text", () => {
|
|
124
|
+
defaultProps.placeholder = "Drop your files here";
|
|
125
|
+
render(<FilePicker {...defaultProps} />);
|
|
126
|
+
expect(screen.getByText("Drop your files here")).toBeInTheDocument();
|
|
144
127
|
});
|
|
145
128
|
|
|
146
|
-
it("should
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
).
|
|
129
|
+
it("should display allowed mime types", () => {
|
|
130
|
+
render(<FilePicker {...defaultProps} />);
|
|
131
|
+
expect(screen.getByText(/PNG/)).toBeInTheDocument();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should display max file size message", () => {
|
|
135
|
+
render(<FilePicker {...defaultProps} />);
|
|
136
|
+
expect(screen.getByText(/Max 10MB each/)).toBeInTheDocument();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Initial value tests - NEW TESTS replacing skipped ones
|
|
140
|
+
it("should render with initial value and display file name", async () => {
|
|
141
|
+
const file: File = mockFile("test-document.png");
|
|
142
|
+
defaultProps.initialValue = await mockFileModel(file);
|
|
143
|
+
render(<FilePicker {...defaultProps} />);
|
|
144
|
+
|
|
145
|
+
expect(screen.getByText("test-document.png")).toBeInTheDocument();
|
|
146
|
+
expect(screen.getByText("Uploaded files")).toBeInTheDocument();
|
|
154
147
|
});
|
|
155
148
|
|
|
156
|
-
it("should render with initial value
|
|
149
|
+
it("should render with initial value and show Remove button", async () => {
|
|
150
|
+
const file: File = mockFile("my-file.png");
|
|
151
|
+
defaultProps.initialValue = await mockFileModel(file);
|
|
152
|
+
render(<FilePicker {...defaultProps} />);
|
|
153
|
+
|
|
154
|
+
expect(screen.getByText("Remove")).toBeInTheDocument();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("should render with initial value as array and display all file names", async () => {
|
|
158
|
+
const file1: File = mockFile("first-file.png");
|
|
159
|
+
const file2: File = mockFile("second-file.png");
|
|
157
160
|
defaultProps.initialValue = [
|
|
158
|
-
await mockFileModel(
|
|
159
|
-
await mockFileModel(
|
|
161
|
+
await mockFileModel(file1, "id1"),
|
|
162
|
+
await mockFileModel(file2, "id2"),
|
|
160
163
|
];
|
|
161
164
|
render(<FilePicker {...defaultProps} />);
|
|
162
|
-
|
|
163
|
-
expect(
|
|
164
|
-
|
|
165
|
-
);
|
|
165
|
+
|
|
166
|
+
expect(screen.getByText("first-file.png")).toBeInTheDocument();
|
|
167
|
+
expect(screen.getByText("second-file.png")).toBeInTheDocument();
|
|
168
|
+
expect(screen.getAllByText("Remove")).toHaveLength(2);
|
|
166
169
|
});
|
|
167
170
|
|
|
168
|
-
it("should render with value array
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
it("should render with initial value array and show Uploaded files section", async () => {
|
|
172
|
+
const file1: File = mockFile("doc1.png");
|
|
173
|
+
const file2: File = mockFile("doc2.png");
|
|
174
|
+
defaultProps.initialValue = [
|
|
175
|
+
await mockFileModel(file1, "id1"),
|
|
176
|
+
await mockFileModel(file2, "id2"),
|
|
177
|
+
];
|
|
178
|
+
render(<FilePicker {...defaultProps} />);
|
|
179
|
+
|
|
180
|
+
expect(screen.getByText("Uploaded files")).toBeInTheDocument();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Value prop tests - NEW TESTS replacing skipped ones
|
|
184
|
+
it("should render with value array containing one element", async () => {
|
|
185
|
+
const file: File = mockFile("single-file.png");
|
|
186
|
+
defaultProps.value = [await mockFileModel(file)];
|
|
187
|
+
render(<FilePicker {...defaultProps} />);
|
|
188
|
+
|
|
189
|
+
expect(screen.getByText("single-file.png")).toBeInTheDocument();
|
|
190
|
+
expect(screen.getByText("Uploaded files")).toBeInTheDocument();
|
|
174
191
|
});
|
|
175
192
|
|
|
176
|
-
it("should render with value array
|
|
193
|
+
it("should render with value array containing multiple elements", async () => {
|
|
194
|
+
const file1: File = mockFile("file-a.png");
|
|
195
|
+
const file2: File = mockFile("file-b.png");
|
|
196
|
+
const file3: File = mockFile("file-c.png");
|
|
177
197
|
defaultProps.value = [
|
|
178
|
-
await mockFileModel(
|
|
179
|
-
await mockFileModel(
|
|
198
|
+
await mockFileModel(file1, "a"),
|
|
199
|
+
await mockFileModel(file2, "b"),
|
|
200
|
+
await mockFileModel(file3, "c"),
|
|
180
201
|
];
|
|
181
202
|
render(<FilePicker {...defaultProps} />);
|
|
182
|
-
const { container } = render(<FilePicker {...defaultProps} />);
|
|
183
|
-
expect(queryAllByAttribute("src", container, MOCK_FILE_URL)).toHaveLength(
|
|
184
|
-
2,
|
|
185
|
-
);
|
|
186
|
-
});
|
|
187
203
|
|
|
188
|
-
|
|
189
|
-
|
|
204
|
+
expect(screen.getByText("file-a.png")).toBeInTheDocument();
|
|
205
|
+
expect(screen.getByText("file-b.png")).toBeInTheDocument();
|
|
206
|
+
expect(screen.getByText("file-c.png")).toBeInTheDocument();
|
|
207
|
+
expect(screen.getAllByText("Remove")).toHaveLength(3);
|
|
208
|
+
});
|
|
190
209
|
|
|
191
|
-
|
|
210
|
+
// Upload tests - NEW TESTS replacing skipped ones
|
|
211
|
+
it("should upload a file when dropped and display its name", async () => {
|
|
212
|
+
const file: File = mockFile("uploaded-doc.png");
|
|
192
213
|
const data: DataTransfer = {
|
|
193
214
|
dataTransfer: {
|
|
194
215
|
files: [file],
|
|
@@ -202,23 +223,20 @@ describe("FilePicker", () => {
|
|
|
202
223
|
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
|
203
224
|
).mockResolvedValue(createResponse);
|
|
204
225
|
|
|
205
|
-
|
|
226
|
+
render(<FilePicker {...defaultProps} />);
|
|
206
227
|
|
|
207
|
-
const dropzone: HTMLElement = screen.
|
|
208
|
-
|
|
228
|
+
const dropzone: HTMLElement = screen.getByText("Upload files");
|
|
229
|
+
await act(async () => {
|
|
230
|
+
fireEvent.drop(dropzone, data);
|
|
231
|
+
});
|
|
209
232
|
|
|
210
233
|
await waitFor(() => {
|
|
211
|
-
expect(
|
|
212
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
213
|
-
).not.toBeInTheDocument();
|
|
234
|
+
expect(screen.getByText("uploaded-doc.png")).toBeInTheDocument();
|
|
214
235
|
});
|
|
215
236
|
});
|
|
216
237
|
|
|
217
|
-
it(
|
|
218
|
-
const file: File = mockFile();
|
|
219
|
-
file.arrayBuffer = getJestMockFunction().mockRejectedValue(
|
|
220
|
-
new Error("File too large"),
|
|
221
|
-
);
|
|
238
|
+
it("should call onChange callback after successful upload", async () => {
|
|
239
|
+
const file: File = mockFile("callback-test.png");
|
|
222
240
|
const data: DataTransfer = {
|
|
223
241
|
dataTransfer: {
|
|
224
242
|
files: [file],
|
|
@@ -226,20 +244,26 @@ describe("FilePicker", () => {
|
|
|
226
244
|
},
|
|
227
245
|
};
|
|
228
246
|
|
|
229
|
-
const
|
|
247
|
+
const createResponse: HTTPResponse<FileModel> =
|
|
248
|
+
await mockCreateResponse(file);
|
|
249
|
+
(
|
|
250
|
+
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
|
251
|
+
).mockResolvedValue(createResponse);
|
|
230
252
|
|
|
231
|
-
|
|
232
|
-
|
|
253
|
+
render(<FilePicker {...defaultProps} />);
|
|
254
|
+
|
|
255
|
+
const dropzone: HTMLElement = screen.getByText("Upload files");
|
|
256
|
+
await act(async () => {
|
|
257
|
+
fireEvent.drop(dropzone, data);
|
|
258
|
+
});
|
|
233
259
|
|
|
234
260
|
await waitFor(() => {
|
|
235
|
-
expect(
|
|
236
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
237
|
-
).not.toBeInTheDocument();
|
|
261
|
+
expect(mockOnChange).toHaveBeenCalled();
|
|
238
262
|
});
|
|
239
263
|
});
|
|
240
264
|
|
|
241
|
-
it("should
|
|
242
|
-
const file: File = mockFile();
|
|
265
|
+
it("should call onBlur callback after successful upload", async () => {
|
|
266
|
+
const file: File = mockFile("blur-test.png");
|
|
243
267
|
const data: DataTransfer = {
|
|
244
268
|
dataTransfer: {
|
|
245
269
|
files: [file],
|
|
@@ -253,25 +277,20 @@ describe("FilePicker", () => {
|
|
|
253
277
|
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
|
254
278
|
).mockResolvedValue(createResponse);
|
|
255
279
|
|
|
256
|
-
|
|
280
|
+
render(<FilePicker {...defaultProps} />);
|
|
257
281
|
|
|
258
|
-
const dropzone: HTMLElement = screen.
|
|
282
|
+
const dropzone: HTMLElement = screen.getByText("Upload files");
|
|
259
283
|
await act(async () => {
|
|
260
284
|
fireEvent.drop(dropzone, data);
|
|
261
285
|
});
|
|
262
286
|
|
|
263
287
|
await waitFor(() => {
|
|
264
|
-
expect(mockOnChange).toHaveBeenCalledWith([createResponse.data]);
|
|
265
|
-
expect(mockOnBlur).toHaveBeenCalled();
|
|
266
288
|
expect(mockOnBlur).toHaveBeenCalled();
|
|
267
|
-
expect(
|
|
268
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
269
|
-
).toBeInTheDocument();
|
|
270
289
|
});
|
|
271
290
|
});
|
|
272
291
|
|
|
273
|
-
it("should
|
|
274
|
-
const file: File = mockFile();
|
|
292
|
+
it("should display Uploaded files section after upload", async () => {
|
|
293
|
+
const file: File = mockFile("section-test.png");
|
|
275
294
|
const data: DataTransfer = {
|
|
276
295
|
dataTransfer: {
|
|
277
296
|
files: [file],
|
|
@@ -285,35 +304,52 @@ describe("FilePicker", () => {
|
|
|
285
304
|
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
|
286
305
|
).mockResolvedValue(createResponse);
|
|
287
306
|
|
|
288
|
-
|
|
307
|
+
render(<FilePicker {...defaultProps} />);
|
|
289
308
|
|
|
290
|
-
const dropzone: HTMLElement = screen.
|
|
309
|
+
const dropzone: HTMLElement = screen.getByText("Upload files");
|
|
291
310
|
await act(async () => {
|
|
292
311
|
fireEvent.drop(dropzone, data);
|
|
293
312
|
});
|
|
294
313
|
|
|
295
314
|
await waitFor(() => {
|
|
296
|
-
expect(
|
|
297
|
-
expect(mockOnBlur).toHaveBeenCalled();
|
|
298
|
-
expect(mockOnBlur).toHaveBeenCalled();
|
|
299
|
-
expect(
|
|
300
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
301
|
-
).toBeInTheDocument();
|
|
315
|
+
expect(screen.getByText("Uploaded files")).toBeInTheDocument();
|
|
302
316
|
});
|
|
303
317
|
});
|
|
304
318
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
319
|
+
// Delete file tests - NEW TESTS replacing skipped ones
|
|
320
|
+
it("should remove file when Remove button is clicked", async () => {
|
|
321
|
+
const file: File = mockFile("removable-file.png");
|
|
322
|
+
defaultProps.initialValue = await mockFileModel(file);
|
|
323
|
+
render(<FilePicker {...defaultProps} />);
|
|
324
|
+
|
|
325
|
+
expect(screen.getByText("removable-file.png")).toBeInTheDocument();
|
|
326
|
+
|
|
327
|
+
const removeButton: HTMLElement = screen.getByText("Remove");
|
|
328
|
+
await act(async () => {
|
|
329
|
+
fireEvent.click(removeButton);
|
|
308
330
|
});
|
|
309
331
|
|
|
310
|
-
(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
332
|
+
expect(screen.queryByText("removable-file.png")).not.toBeInTheDocument();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("should call onChange with empty array when last file is removed", async () => {
|
|
336
|
+
const file: File = mockFile("last-file.png");
|
|
337
|
+
defaultProps.initialValue = await mockFileModel(file);
|
|
338
|
+
render(<FilePicker {...defaultProps} />);
|
|
339
|
+
|
|
340
|
+
const removeButton: HTMLElement = screen.getByText("Remove");
|
|
341
|
+
await act(async () => {
|
|
342
|
+
fireEvent.click(removeButton);
|
|
314
343
|
});
|
|
315
344
|
|
|
316
|
-
|
|
345
|
+
expect(mockOnChange).toHaveBeenCalledWith([]);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// ReadOnly tests
|
|
349
|
+
it("should not upload file when dropped and readOnly is true", async () => {
|
|
350
|
+
defaultProps.readOnly = true;
|
|
351
|
+
|
|
352
|
+
const file: File = mockFile("readonly-test.png");
|
|
317
353
|
const data: DataTransfer = {
|
|
318
354
|
dataTransfer: {
|
|
319
355
|
files: [file],
|
|
@@ -321,32 +357,103 @@ describe("FilePicker", () => {
|
|
|
321
357
|
},
|
|
322
358
|
};
|
|
323
359
|
|
|
324
|
-
|
|
325
|
-
|
|
360
|
+
(
|
|
361
|
+
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
|
362
|
+
).mockResolvedValue(await mockCreateResponse(file));
|
|
326
363
|
|
|
327
|
-
|
|
364
|
+
render(<FilePicker {...defaultProps} />);
|
|
328
365
|
|
|
329
|
-
const dropzone: HTMLElement = screen.getByLabelText("Upload
|
|
330
|
-
|
|
331
|
-
|
|
366
|
+
const dropzone: HTMLElement = screen.getByLabelText("Upload files");
|
|
367
|
+
fireEvent.drop(dropzone, data);
|
|
368
|
+
|
|
369
|
+
await waitFor(() => {
|
|
370
|
+
expect(ModelAPI.create).not.toHaveBeenCalled();
|
|
332
371
|
});
|
|
372
|
+
});
|
|
333
373
|
|
|
334
|
-
|
|
374
|
+
it("should render in read-only mode without errors", () => {
|
|
375
|
+
defaultProps.readOnly = true;
|
|
376
|
+
render(<FilePicker {...defaultProps} />);
|
|
335
377
|
|
|
336
|
-
|
|
378
|
+
// Component should still render in read-only mode
|
|
379
|
+
expect(screen.getByText("Upload files")).toBeInTheDocument();
|
|
380
|
+
});
|
|
337
381
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
382
|
+
// Error handling tests
|
|
383
|
+
it("should display error prop when provided", () => {
|
|
384
|
+
defaultProps.error = "Something went wrong";
|
|
385
|
+
render(<FilePicker {...defaultProps} />);
|
|
386
|
+
|
|
387
|
+
expect(screen.getByTestId("error-message")).toBeInTheDocument();
|
|
388
|
+
expect(screen.getByText("Something went wrong")).toBeInTheDocument();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("should not display error message when error prop is not provided", () => {
|
|
392
|
+
render(<FilePicker {...defaultProps} />);
|
|
393
|
+
|
|
394
|
+
expect(screen.queryByTestId("error-message")).not.toBeInTheDocument();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Callback tests
|
|
398
|
+
it("should call onFocus when dropzone is clicked", () => {
|
|
399
|
+
defaultProps.onFocus = mockOnFocus;
|
|
400
|
+
render(<FilePicker {...defaultProps} />);
|
|
401
|
+
|
|
402
|
+
const container: HTMLElement = screen
|
|
403
|
+
.getByText("Upload files")
|
|
404
|
+
.closest("div")!.parentElement!.parentElement!;
|
|
405
|
+
fireEvent.click(container);
|
|
406
|
+
|
|
407
|
+
expect(mockOnFocus).toHaveBeenCalled();
|
|
346
408
|
});
|
|
347
409
|
|
|
348
|
-
it("should
|
|
349
|
-
|
|
410
|
+
it("should call onClick when dropzone is clicked", () => {
|
|
411
|
+
defaultProps.onClick = mockOnClick;
|
|
412
|
+
render(<FilePicker {...defaultProps} />);
|
|
413
|
+
|
|
414
|
+
const container: HTMLElement = screen
|
|
415
|
+
.getByText("Upload files")
|
|
416
|
+
.closest("div")!.parentElement!.parentElement!;
|
|
417
|
+
fireEvent.click(container);
|
|
418
|
+
|
|
419
|
+
expect(mockOnClick).toHaveBeenCalled();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Data test id
|
|
423
|
+
it("should render with custom data-testid", () => {
|
|
424
|
+
defaultProps.dataTestId = "custom-file-picker";
|
|
425
|
+
render(<FilePicker {...defaultProps} />);
|
|
426
|
+
|
|
427
|
+
expect(screen.getByTestId("custom-file-picker")).toBeInTheDocument();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Multi-file picker tests
|
|
431
|
+
it("should show Add more files text when files exist and isMultiFilePicker is true", async () => {
|
|
432
|
+
defaultProps.isMultiFilePicker = true;
|
|
433
|
+
const file: File = mockFile("existing.png");
|
|
434
|
+
defaultProps.initialValue = await mockFileModel(file);
|
|
435
|
+
render(<FilePicker {...defaultProps} />);
|
|
436
|
+
|
|
437
|
+
expect(screen.getByText("Add more files")).toBeInTheDocument();
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// File without file attribute test
|
|
441
|
+
it("should not render if file is missing the file attribute", async () => {
|
|
442
|
+
const file: FileModel = await mockFileModel(mockFile("no-buffer.png"));
|
|
443
|
+
delete file.file;
|
|
444
|
+
defaultProps.initialValue = file;
|
|
445
|
+
render(<FilePicker {...defaultProps} />);
|
|
446
|
+
|
|
447
|
+
// File name should still be shown but file size won't be available
|
|
448
|
+
expect(screen.getByText("no-buffer.png")).toBeInTheDocument();
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Error on arrayBuffer test
|
|
452
|
+
it("should handle error when file arrayBuffer fails", async () => {
|
|
453
|
+
const file: File = mockFile("error-file.png");
|
|
454
|
+
file.arrayBuffer = getJestMockFunction().mockRejectedValue(
|
|
455
|
+
new Error("File too large"),
|
|
456
|
+
);
|
|
350
457
|
const data: DataTransfer = {
|
|
351
458
|
dataTransfer: {
|
|
352
459
|
files: [file],
|
|
@@ -354,40 +461,13 @@ describe("FilePicker", () => {
|
|
|
354
461
|
},
|
|
355
462
|
};
|
|
356
463
|
|
|
357
|
-
|
|
358
|
-
await mockCreateResponse(file);
|
|
359
|
-
(
|
|
360
|
-
ModelAPI.create as jest.MockedFunction<typeof ModelAPI.create>
|
|
361
|
-
).mockResolvedValue(createResponse);
|
|
362
|
-
|
|
363
|
-
const { container } = render(<FilePicker {...defaultProps} />);
|
|
364
|
-
|
|
365
|
-
const dropzone: HTMLElement = screen.getByLabelText("Upload a file");
|
|
366
|
-
await act(async () => {
|
|
367
|
-
fireEvent.drop(dropzone, data);
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
await waitFor(() => {
|
|
371
|
-
// file should be in the dropzone
|
|
372
|
-
expect(
|
|
373
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
374
|
-
).toBeInTheDocument();
|
|
375
|
-
});
|
|
464
|
+
render(<FilePicker {...defaultProps} />);
|
|
376
465
|
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
if (deleteIcon) {
|
|
380
|
-
await act(async () => {
|
|
381
|
-
fireEvent.click(deleteIcon.childNodes.item(0), data);
|
|
382
|
-
});
|
|
383
|
-
}
|
|
466
|
+
const dropzone: HTMLElement = screen.getByLabelText("Upload files");
|
|
467
|
+
fireEvent.drop(dropzone, data);
|
|
384
468
|
|
|
385
469
|
await waitFor(() => {
|
|
386
|
-
|
|
387
|
-
expect(mockOnChange).toHaveBeenCalledWith([createResponse.data]);
|
|
388
|
-
expect(
|
|
389
|
-
queryByAttribute("src", container, MOCK_FILE_URL),
|
|
390
|
-
).not.toBeInTheDocument();
|
|
470
|
+
expect(screen.queryByText("error-file.png")).not.toBeInTheDocument();
|
|
391
471
|
});
|
|
392
472
|
});
|
|
393
473
|
});
|
|
@@ -92,7 +92,9 @@ describe("List", () => {
|
|
|
92
92
|
|
|
93
93
|
it("handles onNavigateToPage callback", () => {
|
|
94
94
|
render(<List {...defaultProps} />);
|
|
95
|
-
|
|
95
|
+
// There are multiple "Next" elements (mobile and desktop), get the first one
|
|
96
|
+
const nextButtons: HTMLElement[] = screen.getAllByText("Next");
|
|
97
|
+
fireEvent.click(nextButtons[0]!);
|
|
96
98
|
|
|
97
99
|
expect(defaultProps.onNavigateToPage).toHaveBeenCalledWith(2, 5);
|
|
98
100
|
});
|
|
@@ -61,7 +61,8 @@ describe("MarkdownEditor", () => {
|
|
|
61
61
|
const textarea: HTMLTextAreaElement = screen.getByRole(
|
|
62
62
|
"textbox",
|
|
63
63
|
) as HTMLTextAreaElement;
|
|
64
|
-
|
|
64
|
+
// jsdom doesn't properly reflect spellcheck property, so we check the attribute
|
|
65
|
+
expect(textarea.getAttribute("spellcheck")).toBe("true");
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
test("should enable spell check when disableSpellCheck is undefined", () => {
|
|
@@ -76,7 +77,7 @@ describe("MarkdownEditor", () => {
|
|
|
76
77
|
const textarea: HTMLTextAreaElement = screen.getByRole(
|
|
77
78
|
"textbox",
|
|
78
79
|
) as HTMLTextAreaElement;
|
|
79
|
-
expect(textarea.spellcheck).toBe(true);
|
|
80
|
+
expect(textarea.getAttribute("spellcheck")).toBe("true");
|
|
80
81
|
});
|
|
81
82
|
|
|
82
83
|
test("should disable spell check when disableSpellCheck is true", () => {
|
|
@@ -91,7 +92,7 @@ describe("MarkdownEditor", () => {
|
|
|
91
92
|
const textarea: HTMLTextAreaElement = screen.getByRole(
|
|
92
93
|
"textbox",
|
|
93
94
|
) as HTMLTextAreaElement;
|
|
94
|
-
expect(textarea.spellcheck).toBe(false);
|
|
95
|
+
expect(textarea.getAttribute("spellcheck")).toBe("false");
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
test("should handle spell check prop changes", () => {
|
|
@@ -106,7 +107,7 @@ describe("MarkdownEditor", () => {
|
|
|
106
107
|
let textarea: HTMLTextAreaElement = screen.getByRole(
|
|
107
108
|
"textbox",
|
|
108
109
|
) as HTMLTextAreaElement;
|
|
109
|
-
expect(textarea.spellcheck).toBe(true);
|
|
110
|
+
expect(textarea.getAttribute("spellcheck")).toBe("true");
|
|
110
111
|
|
|
111
112
|
rerender(
|
|
112
113
|
<MarkdownEditor
|
|
@@ -117,7 +118,7 @@ describe("MarkdownEditor", () => {
|
|
|
117
118
|
);
|
|
118
119
|
|
|
119
120
|
textarea = screen.getByRole("textbox") as HTMLTextAreaElement;
|
|
120
|
-
expect(textarea.spellcheck).toBe(false);
|
|
121
|
+
expect(textarea.getAttribute("spellcheck")).toBe("false");
|
|
121
122
|
});
|
|
122
123
|
|
|
123
124
|
test("should show help text", () => {
|
|
@@ -23,7 +23,7 @@ describe("MasterPage", () => {
|
|
|
23
23
|
it("should render correctly with isLoading", () => {
|
|
24
24
|
render(<MasterPage {...defaultProps} isLoading />);
|
|
25
25
|
|
|
26
|
-
const loader: HTMLElement = screen.
|
|
26
|
+
const loader: HTMLElement = screen.getByTestId("bar-loader");
|
|
27
27
|
expect(loader).toBeInTheDocument();
|
|
28
28
|
});
|
|
29
29
|
|