feat: Admin Area General Settings and Categories 1.03
This commit is contained in:
@@ -6,6 +6,7 @@ process.env.UPLOAD_SIZE_LIMIT = '1mb';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import sharp from 'sharp';
|
||||
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { INestApplication, ValidationPipe } from '@nestjs/common';
|
||||
@@ -117,11 +118,18 @@ describe('Uploads endpoint - /uploads/logo (admin only)', () => {
|
||||
it('uploads a small image and returns publicUrl + originalFilename', async () => {
|
||||
const { agent, csrf } = await primeCsrf();
|
||||
const originalName = `My Logo ${Date.now()}.PNG`;
|
||||
// Generate a real, decodable PNG with sharp so the upload path
|
||||
// exercises its full image-validation policy.
|
||||
const png = await sharp({
|
||||
create: { width: 32, height: 32, channels: 3, background: { r: 10, g: 20, b: 30 } },
|
||||
})
|
||||
.png()
|
||||
.toBuffer();
|
||||
const res = await agent
|
||||
.post('/api/v1/uploads/logo')
|
||||
.set('Authorization', `Bearer ${adminToken}`)
|
||||
.set('X-CSRF-Token', csrf)
|
||||
.attach('file', Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]), originalName)
|
||||
.attach('file', png, originalName)
|
||||
.expect(201);
|
||||
|
||||
expect(res.body).toHaveProperty('publicUrl');
|
||||
@@ -155,4 +163,48 @@ describe('Uploads endpoint - /uploads/logo (admin only)', () => {
|
||||
.attach('file', big, 'big.png')
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
it('rejects a plain-text payload labeled as an image', async () => {
|
||||
const { agent, csrf } = await primeCsrf();
|
||||
const res = await agent
|
||||
.post('/api/v1/uploads/logo')
|
||||
.set('Authorization', `Bearer ${adminToken}`)
|
||||
.set('X-CSRF-Token', csrf)
|
||||
.attach('file', Buffer.from('not an image'), { filename: 'logo.png', contentType: 'image/png' });
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body?.message).toMatch(/valid PNG|JPEG|GIF|WebP/i);
|
||||
|
||||
const after = fs.existsSync(process.env.UPLOAD_DIR!)
|
||||
? fs.readdirSync(process.env.UPLOAD_DIR!)
|
||||
: [];
|
||||
expect(after.some((f) => f.endsWith('.png') && f.includes('logo'))).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects a corrupt GIF payload', async () => {
|
||||
const { agent, csrf } = await primeCsrf();
|
||||
// GIF89a header followed by a truncated/invalid body.
|
||||
const corruptGif = Buffer.concat([
|
||||
Buffer.from('GIF89a', 'ascii'),
|
||||
Buffer.alloc(8, 0x00),
|
||||
Buffer.from([0xff, 0xff, 0xff]),
|
||||
]);
|
||||
const res = await agent
|
||||
.post('/api/v1/uploads/logo')
|
||||
.set('Authorization', `Bearer ${adminToken}`)
|
||||
.set('X-CSRF-Token', csrf)
|
||||
.attach('file', corruptGif, { filename: 'malformed.gif', contentType: 'image/gif' });
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body?.message).toMatch(/valid PNG|JPEG|GIF|WebP/i);
|
||||
});
|
||||
|
||||
it('rejects an 8-byte corrupt PNG payload', async () => {
|
||||
const { agent, csrf } = await primeCsrf();
|
||||
const res = await agent
|
||||
.post('/api/v1/uploads/logo')
|
||||
.set('Authorization', `Bearer ${adminToken}`)
|
||||
.set('X-CSRF-Token', csrf)
|
||||
.attach('file', Buffer.alloc(8, 0x00), { filename: 'bad.png', contentType: 'image/png' });
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body?.message).toMatch(/valid PNG|JPEG|GIF|WebP/i);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user