Skip to content

Commit 13d7518

Browse files
author
skychx
committed
feat(meida-utils): add test cases
1 parent a33b112 commit 13d7518

File tree

2 files changed

+353
-2
lines changed

2 files changed

+353
-2
lines changed

packages/media-utils/src/compressor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class ImageCompressor {
2929
* Compress image and return Buffer without writing to file
3030
* @param imageBuffer Image Buffer
3131
*/
32-
async compressToBuffer(imageBuffer: Uint8Array) {
32+
async compressToBuffer(imageBuffer: Buffer) {
3333
// Choose appropriate compression plugin
3434
const plugins = this.getPluginsForFormat();
3535

@@ -39,7 +39,7 @@ export class ImageCompressor {
3939
});
4040
}
4141

42-
async compressToBase64(imageBuffer: Uint8Array) {
42+
async compressToBase64(imageBuffer: Buffer) {
4343
// Compress image to Buffer
4444
const compressedBuffer = await this.compressToBuffer(imageBuffer);
4545

Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
import { describe, it, expect, beforeAll } from 'vitest';
2+
import { readFileSync } from 'fs';
3+
import { join } from 'path';
4+
import { ImageCompressor } from '../src/compressor';
5+
6+
describe('ImageCompressor', () => {
7+
let testImages: { [key: string]: Buffer } = {};
8+
9+
beforeAll(() => {
10+
// Load test images
11+
const imageFiles = [
12+
'logo_240_223.png',
13+
'logo_240_223.jpeg',
14+
'VP8_240_223.webp',
15+
'VP8X_240_223.webp',
16+
'VP8L_240_223.webp',
17+
'logo_240_223.gif',
18+
'logo_240_223.bmp',
19+
];
20+
21+
imageFiles.forEach((filename) => {
22+
try {
23+
const imagePath = join(__dirname, 'images', filename);
24+
testImages[filename] = readFileSync(imagePath);
25+
} catch (error) {
26+
console.warn(`Could not load test image: ${filename}`, error);
27+
}
28+
});
29+
});
30+
31+
describe('Constructor', () => {
32+
it('should use default options when no options provided', () => {
33+
const compressor = new ImageCompressor();
34+
35+
expect(compressor.options.quality).toBe(80);
36+
expect(compressor.options.format).toBe('webp');
37+
expect(compressor.options.width).toBeUndefined();
38+
expect(compressor.options.height).toBeUndefined();
39+
});
40+
41+
it('should use custom options when provided', () => {
42+
const options = {
43+
quality: 60,
44+
format: 'jpeg' as const,
45+
width: 800,
46+
height: 600,
47+
};
48+
const compressor = new ImageCompressor(options);
49+
50+
expect(compressor.options.quality).toBe(60);
51+
expect(compressor.options.format).toBe('jpeg');
52+
expect(compressor.options.width).toBe(800);
53+
expect(compressor.options.height).toBe(600);
54+
});
55+
56+
it('should merge default and custom options', () => {
57+
const compressor = new ImageCompressor({ quality: 90 });
58+
59+
expect(compressor.options.quality).toBe(90);
60+
expect(compressor.options.format).toBe('webp'); // default
61+
expect(compressor.options.width).toBeUndefined();
62+
});
63+
});
64+
65+
describe('compressToBuffer', () => {
66+
it('should compress PNG image to WebP format by default', async () => {
67+
const compressor = new ImageCompressor();
68+
const originalBuffer = testImages['logo_240_223.png'];
69+
70+
if (!originalBuffer) {
71+
console.warn('PNG test image not available, skipping test');
72+
return;
73+
}
74+
75+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
76+
77+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
78+
expect(compressedBuffer[0]).toBe(0x52);
79+
expect(compressedBuffer[1]).toBe(0x49);
80+
});
81+
82+
it('should compress to JPEG format when specified', async () => {
83+
const compressor = new ImageCompressor({ format: 'jpeg', quality: 75 });
84+
const originalBuffer = testImages['logo_240_223.png'];
85+
86+
if (!originalBuffer) {
87+
console.warn('PNG test image not available, skipping test');
88+
return;
89+
}
90+
91+
const compressedBuffer =
92+
await compressor.compressToBuffer(originalBuffer);
93+
94+
console.log(
95+
'original Buffer:',
96+
originalBuffer[0].toString(16),
97+
originalBuffer[1].toString(16),
98+
);
99+
100+
console.log(
101+
'Compressed Buffer:',
102+
compressedBuffer[0].toString(16),
103+
compressedBuffer[1].toString(16),
104+
);
105+
106+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
107+
// JPEG signature check
108+
expect(compressedBuffer[0]).toBe(0xff);
109+
expect(compressedBuffer[1]).toBe(0xd8);
110+
});
111+
112+
it('should compress to PNG format when specified', async () => {
113+
const compressor = new ImageCompressor({ format: 'png', quality: 85 });
114+
const originalBuffer = testImages['logo_240_223.jpeg'];
115+
116+
if (!originalBuffer) {
117+
console.warn('JPEG test image not available, skipping test');
118+
return;
119+
}
120+
121+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
122+
123+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
124+
expect(compressedBuffer.length).toBeGreaterThan(0);
125+
// PNG signature check
126+
expect(compressedBuffer[0]).toBe(0x89);
127+
expect(compressedBuffer[1]).toBe(0x50);
128+
expect(compressedBuffer[2]).toBe(0x4e);
129+
expect(compressedBuffer[3]).toBe(0x47);
130+
});
131+
132+
it('should compress WebP images', async () => {
133+
const compressor = new ImageCompressor({ format: 'webp', quality: 70 });
134+
const originalBuffer = testImages['VP8_240_223.webp'];
135+
136+
if (!originalBuffer) {
137+
console.warn('WebP test image not available, skipping test');
138+
return;
139+
}
140+
141+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
142+
143+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
144+
expect(compressedBuffer.length).toBeGreaterThan(0);
145+
});
146+
147+
it('should handle different quality levels', async () => {
148+
const originalBuffer = testImages['logo_240_223.png'];
149+
150+
if (!originalBuffer) {
151+
console.warn('PNG test image not available, skipping test');
152+
return;
153+
}
154+
155+
const highQualityCompressor = new ImageCompressor({ quality: 95 });
156+
const lowQualityCompressor = new ImageCompressor({ quality: 30 });
157+
158+
const highQualityBuffer = await highQualityCompressor.compressToBuffer(originalBuffer);
159+
const lowQualityBuffer = await lowQualityCompressor.compressToBuffer(originalBuffer);
160+
161+
expect(highQualityBuffer.length).toBeGreaterThan(lowQualityBuffer.length);
162+
});
163+
164+
it('should handle BMP images', async () => {
165+
const compressor = new ImageCompressor();
166+
const originalBuffer = testImages['logo_240_223.bmp'];
167+
168+
if (!originalBuffer) {
169+
console.warn('BMP test image not available, skipping test');
170+
return;
171+
}
172+
173+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
174+
175+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
176+
expect(compressedBuffer.length).toBeGreaterThan(0);
177+
expect(compressedBuffer.length).toBeLessThan(originalBuffer.length);
178+
});
179+
180+
it('should handle GIF images', async () => {
181+
const compressor = new ImageCompressor();
182+
const originalBuffer = testImages['logo_240_223.gif'];
183+
184+
if (!originalBuffer) {
185+
console.warn('GIF test image not available, skipping test');
186+
return;
187+
}
188+
189+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
190+
191+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
192+
expect(compressedBuffer.length).toBeGreaterThan(0);
193+
});
194+
195+
it('should throw error for invalid image data', async () => {
196+
const compressor = new ImageCompressor();
197+
const invalidBuffer = Buffer.from([1, 2, 3, 4, 5])
198+
199+
await expect(compressor.compressToBuffer(invalidBuffer)).rejects.toThrow();
200+
});
201+
});
202+
203+
describe.skip('compressToBase64', () => {
204+
it('should compress image and return base64 string', async () => {
205+
const compressor = new ImageCompressor();
206+
const originalBuffer = testImages['logo_240_223.png'];
207+
208+
if (!originalBuffer) {
209+
console.warn('PNG test image not available, skipping test');
210+
return;
211+
}
212+
213+
const base64String = await compressor.compressToBase64(originalBuffer);
214+
215+
expect(typeof base64String).toBe('string');
216+
expect(base64String.length).toBeGreaterThan(0);
217+
expect(base64String).toMatch(/^[A-Za-z0-9+/=]+$/); // Valid base64 pattern
218+
});
219+
220+
it('should return different base64 strings for different quality settings', async () => {
221+
const originalBuffer = testImages['logo_240_223.jpeg'];
222+
223+
if (!originalBuffer) {
224+
console.warn('JPEG test image not available, skipping test');
225+
return;
226+
}
227+
228+
const highQualityCompressor = new ImageCompressor({ quality: 90 });
229+
const lowQualityCompressor = new ImageCompressor({ quality: 40 });
230+
231+
const highQualityBase64 = await highQualityCompressor.compressToBase64(originalBuffer);
232+
const lowQualityBase64 = await lowQualityCompressor.compressToBase64(originalBuffer);
233+
234+
expect(highQualityBase64).not.toBe(lowQualityBase64);
235+
expect(highQualityBase64.length).toBeGreaterThan(lowQualityBase64.length);
236+
});
237+
238+
it('should handle different image formats', async () => {
239+
const formats = ['jpeg', 'png', 'webp'] as const;
240+
const originalBuffer = testImages['logo_240_223.png'];
241+
242+
if (!originalBuffer) {
243+
console.warn('PNG test image not available, skipping test');
244+
return;
245+
}
246+
247+
for (const format of formats) {
248+
const compressor = new ImageCompressor({ format, quality: 75 });
249+
const base64String = await compressor.compressToBase64(originalBuffer);
250+
251+
expect(typeof base64String).toBe('string');
252+
expect(base64String.length).toBeGreaterThan(0);
253+
}
254+
});
255+
});
256+
257+
describe.skip('getOptionsDescription', () => {
258+
it('should return description with quality and format only', () => {
259+
const compressor = new ImageCompressor({ quality: 75, format: 'jpeg' });
260+
const description = compressor.getOptionsDescription();
261+
262+
expect(description).toBe('Quality: 75, Format: jpeg');
263+
});
264+
265+
it('should include width when specified', () => {
266+
const compressor = new ImageCompressor({ quality: 80, format: 'webp', width: 800 });
267+
const description = compressor.getOptionsDescription();
268+
269+
expect(description).toBe('Quality: 80, Format: webp, Width: 800px');
270+
});
271+
272+
it('should include height when specified', () => {
273+
const compressor = new ImageCompressor({ quality: 60, format: 'png', height: 600 });
274+
const description = compressor.getOptionsDescription();
275+
276+
expect(description).toBe('Quality: 60, Format: png, Height: 600px');
277+
});
278+
279+
it('should include both width and height when specified', () => {
280+
const compressor = new ImageCompressor({
281+
quality: 90,
282+
format: 'jpeg',
283+
width: 1024,
284+
height: 768
285+
});
286+
const description = compressor.getOptionsDescription();
287+
288+
expect(description).toBe('Quality: 90, Format: jpeg, Width: 1024px, Height: 768px');
289+
});
290+
291+
it('should show default options description', () => {
292+
const compressor = new ImageCompressor();
293+
const description = compressor.getOptionsDescription();
294+
295+
expect(description).toBe('Quality: 80, Format: webp');
296+
});
297+
});
298+
299+
describe.skip('Edge Cases', () => {
300+
it('should handle extremely small images', async () => {
301+
// This would require a very small valid image file
302+
const compressor = new ImageCompressor();
303+
const originalBuffer = testImages['logo_240_223.png'];
304+
305+
if (!originalBuffer) {
306+
console.warn('PNG test image not available, skipping test');
307+
return;
308+
}
309+
310+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
311+
expect(compressedBuffer.length).toBeGreaterThan(0);
312+
});
313+
314+
it('should handle quality edge values', async () => {
315+
const originalBuffer = testImages['logo_240_223.png'];
316+
317+
if (!originalBuffer) {
318+
console.warn('PNG test image not available, skipping test');
319+
return;
320+
}
321+
322+
// Test minimum quality
323+
const minQualityCompressor = new ImageCompressor({ quality: 1 });
324+
const minQualityBuffer = await minQualityCompressor.compressToBuffer(originalBuffer);
325+
expect(minQualityBuffer.length).toBeGreaterThan(0);
326+
327+
// Test maximum quality
328+
const maxQualityCompressor = new ImageCompressor({ quality: 100 });
329+
const maxQualityBuffer = await maxQualityCompressor.compressToBuffer(originalBuffer);
330+
expect(maxQualityBuffer.length).toBeGreaterThan(0);
331+
});
332+
333+
it('should handle different WebP variants', async () => {
334+
const compressor = new ImageCompressor({ format: 'webp', quality: 75 });
335+
const webpVariants = ['VP8_240_223.webp', 'VP8X_240_223.webp', 'VP8L_240_223.webp'];
336+
337+
for (const variant of webpVariants) {
338+
const originalBuffer = testImages[variant];
339+
340+
if (!originalBuffer) {
341+
console.warn(`${variant} test image not available, skipping`);
342+
continue;
343+
}
344+
345+
const compressedBuffer = await compressor.compressToBuffer(originalBuffer);
346+
expect(compressedBuffer).toBeInstanceOf(Uint8Array);
347+
expect(compressedBuffer.length).toBeGreaterThan(0);
348+
}
349+
});
350+
});
351+
});

0 commit comments

Comments
 (0)