82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { mkdtemp, readFile, rm } from 'fs/promises'
|
|
import os from 'os'
|
|
import path from 'path'
|
|
|
|
import { uploadPublicDisplayToS3 } from '@/lib/public-display'
|
|
import { saveTaskDetailPreview } from '@/lib/task-detail-preview-storage'
|
|
|
|
jest.mock('@/lib/public-display', () => ({
|
|
...jest.requireActual('@/lib/public-display'),
|
|
uploadPublicDisplayToS3: jest.fn(),
|
|
}))
|
|
|
|
describe('task-detail-preview-storage', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
test('公开预览仍沿用既有 public-display 路径', async () => {
|
|
const buffer = Buffer.from('public-preview')
|
|
;(uploadPublicDisplayToS3 as jest.Mock).mockResolvedValue(
|
|
'https://s3.example/public-display/task-detail/material-1/detail/cover.webp',
|
|
)
|
|
|
|
const result = await saveTaskDetailPreview(
|
|
buffer,
|
|
'material-1',
|
|
'detail',
|
|
'cover.webp',
|
|
false,
|
|
)
|
|
|
|
expect(result).toBe('https://s3.example/public-display/task-detail/material-1/detail/cover.webp')
|
|
expect(uploadPublicDisplayToS3).toHaveBeenCalledWith(
|
|
buffer,
|
|
'task-detail/material-1/detail/cover.webp',
|
|
'image/webp',
|
|
)
|
|
})
|
|
|
|
test('私密预览写入本地 uploads/materials 私有目录并返回相对存储路径', async () => {
|
|
const uploadRoot = await mkdtemp(path.join(os.tmpdir(), 'task-detail-preview-storage-'))
|
|
const previousUploadDir = process.env.UPLOAD_DIR
|
|
process.env.UPLOAD_DIR = uploadRoot
|
|
|
|
try {
|
|
const first = await saveTaskDetailPreview(
|
|
Buffer.from('private-preview-1'),
|
|
'material-1',
|
|
'detail',
|
|
'bad/../封面?.webp',
|
|
true,
|
|
)
|
|
const second = await saveTaskDetailPreview(
|
|
Buffer.from('private-preview-2'),
|
|
'material-1',
|
|
'detail',
|
|
'bad/../封面?.webp',
|
|
true,
|
|
)
|
|
|
|
expect(first).toMatch(/^uploads\/materials\/material-1\/private-previews\/detail\/.+\.webp$/)
|
|
expect(second).toMatch(/^uploads\/materials\/material-1\/private-previews\/detail\/.+\.webp$/)
|
|
expect(second).not.toBe(first)
|
|
expect(uploadPublicDisplayToS3).not.toHaveBeenCalled()
|
|
|
|
const firstAbsolutePath = path.join(uploadRoot, first.replace(/^uploads\//, '').replace(/\//g, path.sep))
|
|
const secondAbsolutePath = path.join(uploadRoot, second.replace(/^uploads\//, '').replace(/\//g, path.sep))
|
|
await expect(readFile(firstAbsolutePath)).resolves.toEqual(Buffer.from('private-preview-1'))
|
|
await expect(readFile(secondAbsolutePath)).resolves.toEqual(Buffer.from('private-preview-2'))
|
|
} finally {
|
|
if (previousUploadDir === undefined) {
|
|
delete process.env.UPLOAD_DIR
|
|
} else {
|
|
process.env.UPLOAD_DIR = previousUploadDir
|
|
}
|
|
await rm(uploadRoot, { recursive: true, force: true })
|
|
}
|
|
})
|
|
})
|