import { canUseBrandKnowledgeLegacyServerPreview, prepareBrandKnowledgePreviewInBrowser, } from '@/lib/brand-knowledge-image-browser' import { BRAND_KNOWLEDGE_PREVIEW_SINGLE_IMAGE_MAX_HEIGHT, planBrandKnowledgePreviewSlices, shouldSliceBrandKnowledgePreview, } from '@/lib/performance-survey-image-source-guard' const mockPreparePerformanceSurveyImagesInBrowser = jest.fn() jest.mock('@/lib/performance-survey-image-browser', () => ({ preparePerformanceSurveyImagesInBrowser: (...args: unknown[]) => ( mockPreparePerformanceSurveyImagesInBrowser(...args) ), })) describe('brand knowledge preview browser processing', () => { beforeEach(() => { jest.clearAllMocks() mockPreparePerformanceSurveyImagesInBrowser.mockResolvedValue([ { file: new File(['one'], 'long-001.webp', { type: 'image/webp' }), kind: 'slice' }, { file: new File(['two'], 'long-002.webp', { type: 'image/webp' }), kind: 'slice' }, ]) }) test('uses 3000px as the inclusive single-image boundary', () => { expect(BRAND_KNOWLEDGE_PREVIEW_SINGLE_IMAGE_MAX_HEIGHT).toBe(3_000) expect(shouldSliceBrandKnowledgePreview(2_999)).toBe(false) expect(shouldSliceBrandKnowledgePreview(3_000)).toBe(false) expect(shouldSliceBrandKnowledgePreview(3_001)).toBe(true) expect(planBrandKnowledgePreviewSlices(3_000, 1_200, 1_500)).toEqual({ sliceHeightLimit: 1_200, sliceCount: 1, }) expect(planBrandKnowledgePreviewSlices(3_001, 1_200, 1_500)).toEqual({ sliceHeightLimit: 600, sliceCount: 2, }) }) test('uses the dedicated 120MP brand profile and returns ordered slices', async () => { const controller = new AbortController() const source = new File(['image'], 'long.jpg', { type: 'image/jpeg' }) const result = await prepareBrandKnowledgePreviewInBrowser(source, undefined, { signal: controller.signal, timeoutMs: 12_345, }) expect(result.map((item) => item.file.name)).toEqual(['long-001.webp', 'long-002.webp']) expect(mockPreparePerformanceSurveyImagesInBrowser).toHaveBeenCalledWith( [source], undefined, { profile: 'brand_knowledge_preview', signal: controller.signal, timeoutMs: 12_345, }, ) }) test('allows server fallback only when the image header is within 60 million pixels', async () => { function pngFile(width: number, height: number) { const bytes = new Uint8Array(24) bytes.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) const view = new DataView(bytes.buffer) view.setUint32(16, width) view.setUint32(20, height) return { name: 'preview.png', size: bytes.byteLength, slice: () => ({ arrayBuffer: async () => bytes.buffer }), } as unknown as File } await expect(canUseBrandKnowledgeLegacyServerPreview(pngFile(10_000, 6_000))).resolves.toBe(true) await expect(canUseBrandKnowledgeLegacyServerPreview(pngFile(10_000, 6_001))).resolves.toBe(false) }) test('rejects browser output that exceeds the derived preview byte limits', async () => { mockPreparePerformanceSurveyImagesInBrowser.mockResolvedValue([{ file: { name: 'huge.webp', size: 10 * 1024 * 1024 + 1 }, kind: 'slice', }]) await expect(prepareBrandKnowledgePreviewInBrowser( new File(['image'], 'long.jpg', { type: 'image/jpeg' }), )).rejects.toThrow('单个切片过大') }) })