test(server): add gallery resize test, adapt upload tests
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
import { describe, it, expect, afterEach } from 'vitest'
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { persistMultipartImages } from '../upload-images.js'
|
import { persistMultipartImages } from '../upload-images.js'
|
||||||
@@ -6,7 +6,7 @@ import { persistMultipartImages } from '../upload-images.js'
|
|||||||
const UPLOADS_DIR = path.join(process.cwd(), 'uploads')
|
const UPLOADS_DIR = path.join(process.cwd(), 'uploads')
|
||||||
const TEST_PREFIX = 'upload-test-'
|
const TEST_PREFIX = 'upload-test-'
|
||||||
|
|
||||||
describe('persistMultipartImages with eager mode', () => {
|
describe('persistMultipartImages with eager=false', () => {
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
const files = await fs.promises.readdir(UPLOADS_DIR).catch(() => [])
|
const files = await fs.promises.readdir(UPLOADS_DIR).catch(() => [])
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
@@ -16,50 +16,6 @@ describe('persistMultipartImages with eager mode', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns WebP URLs when eager=true', async () => {
|
|
||||||
const sharp = (await import('sharp')).default
|
|
||||||
const testImagePath = path.join(UPLOADS_DIR, `${TEST_PREFIX}original.png`)
|
|
||||||
|
|
||||||
const filesBefore = await fs.promises.readdir(UPLOADS_DIR)
|
|
||||||
|
|
||||||
await sharp({ create: { width: 100, height: 100, channels: 3, background: { r: 255, g: 0, b: 0 } } })
|
|
||||||
.png()
|
|
||||||
.toFile(testImagePath)
|
|
||||||
|
|
||||||
const mockRequest = {
|
|
||||||
isMultipart: () => true,
|
|
||||||
parts: async function* () {
|
|
||||||
const buffer = await fs.promises.readFile(testImagePath)
|
|
||||||
yield {
|
|
||||||
file: true,
|
|
||||||
filename: 'test.png',
|
|
||||||
toBuffer: async () => buffer,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const urls = await persistMultipartImages(mockRequest, {
|
|
||||||
maxFiles: 1,
|
|
||||||
maxFileBytes: 20 * 1024 * 1024,
|
|
||||||
subdir: '',
|
|
||||||
eager: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(urls).toHaveLength(1)
|
|
||||||
expect(urls[0]).toMatch(/\/uploads\/[a-f0-9-]+\.webp$/)
|
|
||||||
|
|
||||||
// Verify the intermediate PNG file written by persistMultipartImages was deleted
|
|
||||||
const filesAfter = await fs.promises.readdir(UPLOADS_DIR)
|
|
||||||
const newPngFiles = filesAfter.filter(
|
|
||||||
(f) =>
|
|
||||||
!filesBefore.includes(f) &&
|
|
||||||
f.endsWith('.png') &&
|
|
||||||
f !== path.basename(testImagePath) &&
|
|
||||||
!f.startsWith('test-eager-uuid-'),
|
|
||||||
)
|
|
||||||
expect(newPngFiles).toHaveLength(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('returns original format URLs when eager=false', async () => {
|
it('returns original format URLs when eager=false', async () => {
|
||||||
const sharp = (await import('sharp')).default
|
const sharp = (await import('sharp')).default
|
||||||
const testImagePath = path.join(UPLOADS_DIR, `${TEST_PREFIX}original2.png`)
|
const testImagePath = path.join(UPLOADS_DIR, `${TEST_PREFIX}original2.png`)
|
||||||
@@ -90,34 +46,4 @@ describe('persistMultipartImages with eager mode', () => {
|
|||||||
expect(urls[0]).toMatch(/\/uploads\/[a-f0-9-]+\.png$/)
|
expect(urls[0]).toMatch(/\/uploads\/[a-f0-9-]+\.png$/)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('cleans up original file on eager processing error', async () => {
|
|
||||||
const invalidBuffer = Buffer.from('not an image')
|
|
||||||
|
|
||||||
const filesBefore = await fs.promises.readdir(UPLOADS_DIR)
|
|
||||||
|
|
||||||
const mockRequest = {
|
|
||||||
isMultipart: () => true,
|
|
||||||
parts: async function* () {
|
|
||||||
yield {
|
|
||||||
file: true,
|
|
||||||
filename: 'test.png',
|
|
||||||
toBuffer: async () => invalidBuffer,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
persistMultipartImages(mockRequest, {
|
|
||||||
maxFiles: 1,
|
|
||||||
maxFileBytes: 20 * 1024 * 1024,
|
|
||||||
subdir: '',
|
|
||||||
eager: true,
|
|
||||||
}),
|
|
||||||
).rejects.toThrow()
|
|
||||||
|
|
||||||
// The intermediate file written by persistMultipartImages should be cleaned up
|
|
||||||
const filesAfter = await fs.promises.readdir(UPLOADS_DIR)
|
|
||||||
const newFiles = filesAfter.filter((f) => !filesBefore.includes(f) && f !== '.cache')
|
|
||||||
expect(newFiles).toHaveLength(0)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
|
||||||
|
const UPLOADS_DIR = path.join(process.cwd(), 'uploads')
|
||||||
|
|
||||||
|
import { generateAllSizes, convertOriginalToWebp } from '../../../lib/image-resize.js'
|
||||||
|
|
||||||
|
describe('Admin gallery resize integration', () => {
|
||||||
|
const testUuid = 'gallery-test-resize-uuid'
|
||||||
|
const testOriginalPath = path.join(UPLOADS_DIR, `${testUuid}.png`)
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const sharp = (await import('sharp')).default
|
||||||
|
await sharp({ create: { width: 200, height: 200, channels: 3, background: { r: 255, g: 0, b: 0 } } })
|
||||||
|
.png()
|
||||||
|
.toFile(testOriginalPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await fs.promises.unlink(testOriginalPath).catch(() => {})
|
||||||
|
const webpPath = path.join(UPLOADS_DIR, `${testUuid}.webp`)
|
||||||
|
await fs.promises.unlink(webpPath).catch(() => {})
|
||||||
|
const cacheDir = path.join(UPLOADS_DIR, '.cache')
|
||||||
|
for (const width of [320, 640, 1024, 1600]) {
|
||||||
|
for (const format of ['avif', 'webp']) {
|
||||||
|
await fs.promises.unlink(path.join(cacheDir, `${testUuid}_w${width}.${format}`)).catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generateAllSizes + convertOriginalToWebp works on raw upload', async () => {
|
||||||
|
await generateAllSizes(testUuid, '', testOriginalPath)
|
||||||
|
const newUrl = await convertOriginalToWebp(testUuid, '')
|
||||||
|
|
||||||
|
expect(newUrl).toBe(`/uploads/${testUuid}.webp`)
|
||||||
|
|
||||||
|
// Verify original PNG is deleted
|
||||||
|
const pngExists = await fs.promises.access(testOriginalPath).then(() => true).catch(() => false)
|
||||||
|
expect(pngExists).toBe(false)
|
||||||
|
|
||||||
|
// Verify cached files exist
|
||||||
|
const cacheDir = path.join(UPLOADS_DIR, '.cache')
|
||||||
|
for (const width of [320, 640, 1024, 1600]) {
|
||||||
|
for (const format of ['avif', 'webp']) {
|
||||||
|
const cachePath = path.join(cacheDir, `${testUuid}_w${width}.${format}`)
|
||||||
|
const exists = await fs.promises.access(cachePath).then(() => true).catch(() => false)
|
||||||
|
expect(exists).toBe(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify webp original exists
|
||||||
|
const webpExists = await fs.promises.access(path.join(UPLOADS_DIR, `${testUuid}.webp`)).then(() => true).catch(() => false)
|
||||||
|
expect(webpExists).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user