Skip to content

Commit b6c21c4

Browse files
committed
test(nestjs-tools-fastify-upload): add e2e tests
1 parent dbfb6e9 commit b6c21c4

File tree

2 files changed

+239
-0
lines changed

2 files changed

+239
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { Controller, Post, StreamableFile, UseInterceptors } from '@nestjs/common';
2+
import { join } from 'node:path';
3+
4+
import {
5+
AnyFilesInterceptor,
6+
DiskStorage,
7+
DiskStorageFile,
8+
FileFieldsInterceptor,
9+
FileInterceptor,
10+
FilesInterceptor,
11+
MemoryStorage,
12+
MemoryStorageFile,
13+
StreamStorage,
14+
StreamStorageFile,
15+
UploadedFile,
16+
UploadedFiles,
17+
} from '../../';
18+
19+
@Controller()
20+
export class AppController {
21+
@Post('single')
22+
@UseInterceptors(
23+
FileInterceptor('file', {
24+
storage: new MemoryStorage(),
25+
}),
26+
)
27+
uploadSingleFile(@UploadedFile() file: MemoryStorageFile): {
28+
success: boolean;
29+
} {
30+
return { success: !!file };
31+
}
32+
33+
@Post('multiple')
34+
@UseInterceptors(FilesInterceptor('file', 10, { storage: new MemoryStorage() }))
35+
uploadMultipleFiles(@UploadedFiles() files: MemoryStorageFile[]): {
36+
success: boolean;
37+
fileCount: number;
38+
} {
39+
return { success: !!files.length, fileCount: files.length };
40+
}
41+
42+
@Post('any')
43+
@UseInterceptors(AnyFilesInterceptor({ storage: new MemoryStorage() }))
44+
uploadAnyFiles(@UploadedFiles() files: MemoryStorageFile[]): {
45+
success: boolean;
46+
fileCount: number;
47+
} {
48+
return { success: !!files.length, fileCount: files.length };
49+
}
50+
51+
@Post('fields')
52+
@UseInterceptors(
53+
FileFieldsInterceptor([{ name: 'profile' }, { name: 'avatar' }], {
54+
storage: new MemoryStorage(),
55+
}),
56+
)
57+
uploadFileFieldsFiles(
58+
@UploadedFiles()
59+
files: {
60+
profile?: MemoryStorageFile[];
61+
avatar?: MemoryStorageFile[];
62+
},
63+
): { success: boolean; fileCount: number } {
64+
return {
65+
success: !!((files.profile?.length ?? 0) + (files.avatar?.length ?? 0)),
66+
fileCount: (files.profile?.length ?? 0) + (files.avatar?.length ?? 0),
67+
};
68+
}
69+
70+
@Post('single-stream')
71+
@UseInterceptors(
72+
FileInterceptor('file', {
73+
storage: new StreamStorage(),
74+
}),
75+
)
76+
streamSingleFile(@UploadedFile() file: StreamStorageFile): StreamableFile {
77+
return new StreamableFile(file.stream);
78+
}
79+
80+
@Post('single-disk')
81+
@UseInterceptors(
82+
FileInterceptor('file', {
83+
storage: new DiskStorage({
84+
removeAfter: true,
85+
}),
86+
dest: join(process.cwd(), 'uploads'),
87+
}),
88+
)
89+
persistSingleFile(@UploadedFile() file: DiskStorageFile): {
90+
success: boolean;
91+
filepath: string;
92+
} {
93+
return { success: !!file, filepath: file.path };
94+
}
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import FastifyMultipart from '@fastify/multipart';
2+
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
3+
import { Test } from '@nestjs/testing';
4+
import * as FormData from 'form-data';
5+
import { createReadStream } from 'node:fs';
6+
import { readFile } from 'node:fs/promises';
7+
import { join } from 'node:path';
8+
9+
import { AppController } from './app.controller';
10+
11+
// eslint-disable-next-line max-lines-per-function
12+
describe('Fastify File Upload', () => {
13+
let app: NestFastifyApplication;
14+
beforeEach(async () => {
15+
const modRef = await Test.createTestingModule({
16+
controllers: [AppController],
17+
}).compile();
18+
app = modRef.createNestApplication(new FastifyAdapter());
19+
20+
await app.register(FastifyMultipart);
21+
22+
await app.init();
23+
});
24+
25+
afterEach(async () => {
26+
await app?.close();
27+
});
28+
29+
it('should upload a single file', async () => {
30+
const form = new FormData();
31+
form.append('file', await readFile(join(process.cwd(), 'package.json')), {
32+
contentType: 'application/json',
33+
filename: 'package.json',
34+
});
35+
//
36+
const response = await app.inject({
37+
method: 'POST',
38+
url: '/single',
39+
body: form.getBuffer(),
40+
headers: form.getHeaders(),
41+
});
42+
//
43+
expect(response.statusCode).toBe(201);
44+
expect(response.json()).toEqual({ success: true });
45+
});
46+
47+
it('should upload multiple files', async () => {
48+
const form = new FormData();
49+
form.append('file', createReadStream(join(process.cwd(), 'package.json')));
50+
form.append('file', createReadStream(join(process.cwd(), '.eslintrc.json')));
51+
form.append('nonFile', 'Hello World!');
52+
//
53+
const response = await app.inject({
54+
method: 'POST',
55+
url: '/multiple',
56+
payload: form,
57+
headers: form.getHeaders(),
58+
});
59+
//
60+
expect(response.statusCode).toBe(201);
61+
expect(response.json()).toEqual({ success: true, fileCount: 2 });
62+
});
63+
64+
it('should upload any files', async () => {
65+
const form = new FormData();
66+
form.append('fil', createReadStream(join(process.cwd(), 'package.json')));
67+
form.append('field', 'Hello World!');
68+
//
69+
const response = await app.inject({
70+
method: 'POST',
71+
url: '/any',
72+
payload: form,
73+
headers: form.getHeaders(),
74+
});
75+
//
76+
expect(response.statusCode).toBe(201);
77+
expect(response.json()).toEqual({ success: true, fileCount: 1 });
78+
});
79+
80+
it('should upload single file fields', async () => {
81+
const form = new FormData();
82+
form.append('profile', createReadStream(join(process.cwd(), 'package.json')));
83+
//
84+
const response = await app.inject({
85+
method: 'POST',
86+
url: '/fields',
87+
payload: form,
88+
headers: form.getHeaders(),
89+
});
90+
//
91+
expect(response.statusCode).toBe(201);
92+
expect(response.json()).toEqual({ success: true, fileCount: 1 });
93+
});
94+
95+
it('should upload multiple file fields', async () => {
96+
const form = new FormData();
97+
form.append('profile', createReadStream(join(process.cwd(), 'package.json')));
98+
form.append('avatar', createReadStream(join(process.cwd(), '.eslintrc.json')));
99+
//
100+
const response = await app.inject({
101+
method: 'POST',
102+
url: '/fields',
103+
payload: form,
104+
headers: form.getHeaders(),
105+
});
106+
//
107+
expect(response.statusCode).toBe(201);
108+
expect(response.json()).toEqual({ success: true, fileCount: 2 });
109+
});
110+
111+
it('should upload a single file to stream', async () => {
112+
const form = new FormData();
113+
const file = await readFile(join(process.cwd(), 'package.json'));
114+
form.append('file', file);
115+
//
116+
const response = await app.inject({
117+
method: 'POST',
118+
url: '/single-stream',
119+
payload: form,
120+
headers: form.getHeaders(),
121+
});
122+
//
123+
expect(response.statusCode).toBe(201);
124+
expect(response.body).toEqual(file.toString());
125+
});
126+
127+
it('should upload a single file to disk', async () => {
128+
const form = new FormData();
129+
form.append('file', createReadStream(join(process.cwd(), 'package.json')));
130+
//
131+
const response = await app.inject({
132+
method: 'POST',
133+
url: '/single-disk',
134+
payload: form,
135+
headers: form.getHeaders(),
136+
});
137+
//
138+
expect(response.statusCode).toBe(201);
139+
expect(response.json()).toEqual({
140+
success: true,
141+
filepath: expect.any(String),
142+
});
143+
});
144+
});

0 commit comments

Comments
 (0)