91 lines
3.3 KiB
TypeScript
91 lines
3.3 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import {
|
|
readPerformanceSurveyWebpDimensions,
|
|
validatePerformanceSurveyProcessedImages,
|
|
} from '@/lib/performance-survey-processed-images'
|
|
|
|
function record(overrides: Record<string, unknown> = {}) {
|
|
return {
|
|
uploadId: 'upload-1',
|
|
mimeType: 'image/webp',
|
|
width: 1600,
|
|
height: 1500,
|
|
kind: 'slice',
|
|
sourceName: '详情长图.png',
|
|
sourceIndex: 0,
|
|
sliceIndex: 0,
|
|
sliceCount: 1,
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
function vp8xHeader(width: number, height: number) {
|
|
const buffer = Buffer.alloc(30)
|
|
buffer.write('RIFF', 0, 'ascii')
|
|
buffer.write('WEBP', 8, 'ascii')
|
|
buffer.write('VP8X', 12, 'ascii')
|
|
buffer.writeUIntLE(width - 1, 24, 3)
|
|
buffer.writeUIntLE(height - 1, 27, 3)
|
|
return buffer
|
|
}
|
|
|
|
describe('performance survey processed image contract', () => {
|
|
test('accepts one optional preview plus ordered slices from one long source', () => {
|
|
const groups = validatePerformanceSurveyProcessedImages([
|
|
record({ uploadId: 'slice-2', sliceIndex: 1, sliceCount: 2, height: 800 }),
|
|
record({ uploadId: 'preview', kind: 'preview', width: 720, height: 560, sliceCount: 2 }),
|
|
record({ uploadId: 'slice-1', sliceIndex: 0, sliceCount: 2 }),
|
|
])
|
|
|
|
expect(groups).toHaveLength(1)
|
|
expect(groups[0].preview?.uploadId).toBe('preview')
|
|
expect(groups[0].slices.map((item) => item.uploadId)).toEqual(['slice-1', 'slice-2'])
|
|
})
|
|
|
|
test('accepts pre-cut files as independent source groups without previews', () => {
|
|
const groups = validatePerformanceSurveyProcessedImages([
|
|
record({ uploadId: 'part-1', sourceName: '1.webp' }),
|
|
record({ uploadId: 'part-2', sourceName: '2.webp', sourceIndex: 1 }),
|
|
])
|
|
|
|
expect(groups).toHaveLength(2)
|
|
expect(groups.every((group) => group.preview === null && group.sliceCount === 1)).toBe(true)
|
|
})
|
|
|
|
test('rejects missing or duplicated slice positions', () => {
|
|
expect(() => validatePerformanceSurveyProcessedImages([
|
|
record({ uploadId: 'slice-1', sliceIndex: 0, sliceCount: 2 }),
|
|
record({ uploadId: 'slice-duplicate', sliceIndex: 0, sliceCount: 2 }),
|
|
])).toThrow('切片序号不连续')
|
|
})
|
|
|
|
test('limits final ordered slices to 60 per work item', () => {
|
|
const sixtySlices = Array.from({ length: 60 }, (_, index) => record({
|
|
uploadId: `long-${index}`,
|
|
sliceIndex: index,
|
|
sliceCount: 60,
|
|
}))
|
|
expect(validatePerformanceSurveyProcessedImages(sixtySlices)[0].slices).toHaveLength(60)
|
|
|
|
expect(() => validatePerformanceSurveyProcessedImages([
|
|
...sixtySlices,
|
|
record({ uploadId: 'part-61', sourceName: '2.webp', sourceIndex: 1 }),
|
|
])).toThrow('最多上传 60 张有序切片')
|
|
})
|
|
|
|
test('requires safe WebP dimensions declared by the browser', () => {
|
|
expect(() => validatePerformanceSurveyProcessedImages([
|
|
record({ mimeType: 'image/png' }),
|
|
])).toThrow('只接受 WebP')
|
|
expect(() => validatePerformanceSurveyProcessedImages([
|
|
record({ height: 1501 }),
|
|
])).toThrow('图片高度无效')
|
|
})
|
|
|
|
test('reads VP8X dimensions without decoding image pixels', () => {
|
|
expect(readPerformanceSurveyWebpDimensions(vp8xHeader(1600, 900))).toEqual({ width: 1600, height: 900 })
|
|
expect(() => readPerformanceSurveyWebpDimensions(Buffer.from('not-webp'))).toThrow('不是有效的 WebP')
|
|
})
|
|
})
|