gongxiangp2/lib/__tests__/performance-survey-processed-images.test.ts

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')
})
})