Skip to content

Commit c0a0254

Browse files
committed
tests: upload.service
1 parent 3b98932 commit c0a0254

4 files changed

Lines changed: 1022 additions & 3 deletions

File tree

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"scripts": {
4545
"start": "concurrently \"yarn start:css\" \"react-scripts start\"",
4646
"build": "yarn run build:css && react-scripts build",
47-
"test": "react-scripts test",
47+
"test": "vitest run src/",
4848
"eject": "react-scripts eject",
4949
"start:css": "tailwindcss -w -i ./src/styles/index.css -o ./src/styles/index.generated.css",
5050
"build:css": "tailwindcss -m -i ./src/styles/index.css -o ./src/styles/index.generated.css",
@@ -74,12 +74,14 @@
7474
"@types/bytes": "^3.1.1",
7575
"@types/lodash.throttle": "^4.1.7",
7676
"@types/mime-types": "^2.1.1",
77+
"@vitejs/plugin-react": "^4.3.4",
7778
"autoprefixer": "^10.4.7",
7879
"concurrently": "^7.2.2",
7980
"postcss": "^8.4.14",
8081
"postcss-cli": "^9.1.0",
8182
"prettier": "^2.7.1",
8283
"prettier-plugin-tailwindcss": "^0.1.11",
83-
"tailwindcss": "^3.1.4"
84+
"tailwindcss": "^3.1.4",
85+
"vitest": "^2.1.8"
8486
}
8587
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { vi, describe, it, expect, beforeEach, Mock } from "vitest";
2+
import { getCaptchaToken } from "../lib/auth";
3+
import {
4+
CreateSendLinksResponse,
5+
SendLink,
6+
UploadService,
7+
} from "./upload.service";
8+
import { FileWithPath } from "react-dropzone";
9+
import { SendItemData } from "../models/SendItem";
10+
import axios from "axios";
11+
12+
vi.mock("axios");
13+
14+
vi.mock("../lib/auth", () => ({
15+
getCaptchaToken: vi.fn().mockResolvedValue("mock-token"),
16+
}));
17+
18+
vi.mock("./upload.service", async () => {
19+
const mod = await vi.importActual<typeof import("./upload.service")>(
20+
"./upload.service"
21+
);
22+
return {
23+
...mod,
24+
};
25+
});
26+
27+
const mockSendLink: SendLink = {
28+
id: "mock-id-12345",
29+
name: "example-file.txt",
30+
type: "file",
31+
size: 1024,
32+
networkId: "network-id-67890",
33+
encryptionKey: "encryption-key-abcdef",
34+
parent_folder: null,
35+
};
36+
37+
const mockSendLinkFolder: SendLink = {
38+
id: "mock-id-54321",
39+
name: "example-folder",
40+
type: "folder",
41+
size: 0,
42+
networkId: "network-id-09876",
43+
encryptionKey: "encryption-key-zyxwvu",
44+
parent_folder: "parent-folder-id",
45+
};
46+
47+
const mockCreateSendLinksResponse: CreateSendLinksResponse = {
48+
id: "mock-id-12345",
49+
title: "Example Send Link",
50+
subject: "Example Subject",
51+
code: "mock-code-abcdef",
52+
sender: "mock-sender@example.com",
53+
receivers: ["receiver1@example.com", "receiver2@example.com"],
54+
views: 5,
55+
userId: 42,
56+
items: [
57+
{
58+
id: "item-id-1",
59+
name: "example-file.txt",
60+
type: "file",
61+
size: 1024, // 1 KB
62+
networkId: "network-id-67890",
63+
encryptionKey: "encryption-key-abcdef",
64+
parent_folder: null,
65+
},
66+
{
67+
id: "item-id-2",
68+
name: "example-folder",
69+
type: "folder",
70+
size: 0,
71+
networkId: "network-id-09876",
72+
encryptionKey: "encryption-key-zyxwvu",
73+
parent_folder: "parent-folder-id",
74+
},
75+
],
76+
createdAt: new Date().toISOString(),
77+
updatedAt: new Date().toISOString(),
78+
expirationAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
79+
};
80+
81+
beforeEach(() => {
82+
vi.clearAllMocks();
83+
(getCaptchaToken as Mock).mockResolvedValue("mock-token");
84+
(axios.post as Mock).mockResolvedValue({ data: mockCreateSendLinksResponse });
85+
});
86+
87+
describe("upload.service", () => {
88+
it("When the uploadFiles() is done, then should call storeSendLinks() and ensure getCaptchaToken() is called once", async () => {
89+
const uploadFilesSpy = vi.spyOn(UploadService, "uploadFiles");
90+
const storeSendLinksSpy = vi.spyOn(UploadService, "storeSendLinks");
91+
92+
const axiosPostSpy = vi.spyOn(axios, "post");
93+
94+
uploadFilesSpy.mockResolvedValue([mockSendLink, mockSendLinkFolder]);
95+
96+
const result = await UploadService.uploadFilesAndGetLink([
97+
{
98+
id: "1",
99+
name: "file1.txt",
100+
type: "file",
101+
size: 100,
102+
file: {} as unknown as FileWithPath,
103+
} as unknown as SendItemData,
104+
{
105+
id: "2",
106+
name: "file2.txt",
107+
type: "file",
108+
size: 200,
109+
file: {} as unknown as FileWithPath,
110+
} as unknown as SendItemData,
111+
]);
112+
113+
expect(uploadFilesSpy).toHaveBeenCalledTimes(1);
114+
expect(getCaptchaToken).toHaveBeenCalledTimes(1);
115+
expect(storeSendLinksSpy).toHaveBeenCalledTimes(1);
116+
expect(storeSendLinksSpy).toHaveBeenCalledWith(
117+
expect.objectContaining({
118+
items: expect.any(Array),
119+
code: expect.any(String),
120+
mnemonic: expect.any(String),
121+
plainCode: expect.any(String),
122+
})
123+
);
124+
expect(axiosPostSpy).toHaveBeenCalledTimes(1);
125+
expect(uploadFilesSpy.mock.invocationCallOrder[0]).toBeLessThan(
126+
(getCaptchaToken as Mock).mock.invocationCallOrder[0]
127+
);
128+
expect((getCaptchaToken as Mock).mock.invocationCallOrder[0]).toBeLessThan(
129+
axiosPostSpy.mock.invocationCallOrder[0]
130+
);
131+
expect(result).toContain("/download/");
132+
expect(result).toContain("?code=");
133+
});
134+
135+
it("When storeSendLinks() is called, then getCaptchaToken() should be called before all", async () => {
136+
const storeSendLinksSpy = vi.spyOn(UploadService, "storeSendLinks");
137+
vi.spyOn(UploadService, "uploadFiles").mockResolvedValue([mockSendLink]);
138+
const axiosPostSpy = vi.spyOn(axios, "post");
139+
140+
await UploadService.uploadFilesAndGetLink([
141+
{
142+
id: "1",
143+
name: "file1.txt",
144+
type: "file",
145+
size: 100,
146+
file: {} as unknown as FileWithPath,
147+
} as unknown as SendItemData,
148+
]);
149+
150+
expect(getCaptchaToken).toHaveBeenCalled();
151+
expect(storeSendLinksSpy).toHaveBeenCalled();
152+
expect(storeSendLinksSpy.mock.invocationCallOrder[0]).toBeLessThan(
153+
(getCaptchaToken as Mock).mock.invocationCallOrder[0]
154+
);
155+
expect((getCaptchaToken as Mock).mock.invocationCallOrder[0]).toBeLessThan(
156+
axiosPostSpy.mock.invocationCallOrder[0]
157+
);
158+
});
159+
});

vitest.config.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// vitest.config.ts
2+
import replace from "@rollup/plugin-replace";
3+
import react from "@vitejs/plugin-react";
4+
import path from "path";
5+
import { defineConfig } from "vitest/config";
6+
7+
export default defineConfig({
8+
plugins: [
9+
react(),
10+
replace({
11+
preventAssignment: true,
12+
"process.browser": true,
13+
}),
14+
],
15+
resolve: {
16+
alias: {
17+
// eslint-disable-next-line no-undef
18+
app: path.resolve(__dirname, "./src/app"),
19+
crypto: "crypto-browserify", // Resolve `crypto` to `crypto-browserify`
20+
stream: "stream-browserify",
21+
},
22+
},
23+
test: {
24+
environment: "jsdom",
25+
globals: true,
26+
setupFiles: "./src/setupTests.ts",
27+
exclude: ["node_modules", "dist"],
28+
include: [
29+
"src/**/*.test.{ts,tsx,js,jsx}",
30+
"test/unit/**/*.test.{ts,tsx,js,jsx}",
31+
],
32+
// coverage: {
33+
// provider: "istanbul",
34+
// reporter: ["text", "lcov"],
35+
// reportsDirectory: "./coverage",
36+
// include: ["src/**/*.{js,ts,jsx,tsx}", "test/unit/**/*.{js,ts,jsx,tsx}"],
37+
// },
38+
},
39+
optimizeDeps: {
40+
esbuildOptions: {
41+
// Node.js global to browser globalThis
42+
define: {
43+
global: "globalThis",
44+
},
45+
},
46+
},
47+
});

0 commit comments

Comments
 (0)