UNPKG

@shopify/shop-minis-react

Version:

React component library for Shopify Shop Minis with Tailwind CSS v4 support (source-only, requires TypeScript)

315 lines (255 loc) 8.56 kB
import {describe, expect, it, vi, beforeEach} from 'vitest' import {resizeImage} from './resizeImage' describe('resizeImage', () => { let mockCanvas: any let mockContext: any let mockImage: any beforeEach(() => { // Mock canvas context mockContext = { drawImage: vi.fn(), } // Mock canvas mockCanvas = { width: 0, height: 0, getContext: vi.fn(() => mockContext), toBlob: vi.fn(), } // Mock document.createElement const originalCreateElement = document.createElement document.createElement = vi.fn((tag: string) => { if (tag === 'canvas') { return mockCanvas as any } return originalCreateElement(tag) }) // Mock URL methods global.URL.createObjectURL = vi.fn(() => 'blob:mock-url') global.URL.revokeObjectURL = vi.fn() // Mock Image constructor mockImage = { width: 3000, height: 4000, onload: null as any, onerror: null as any, src: '', } global.Image = vi.fn(() => mockImage) as any }) describe('Quality settings', () => { it('returns original file for "original" quality', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) const result = await resizeImage({ file: originalFile, quality: 'original', }) expect(result).toBe(originalFile) expect(global.Image).not.toHaveBeenCalled() expect(document.createElement).not.toHaveBeenCalled() }) it('resizes to 1080px for low quality', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) // Set up canvas toBlob to call callback mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) // Trigger image load after src is set global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any const resultPromise = resizeImage({ file: originalFile, quality: 'low', }) await new Promise(resolve => setTimeout(resolve, 10)) const result = await resultPromise expect(result).toBeInstanceOf(File) expect(result.type).toBe('image/jpeg') expect(result.name).toBe('test.jpg') // Check canvas dimensions were set correctly (maintaining aspect ratio) expect(mockCanvas.width).toBe(810) // 1080 * (3000/4000) expect(mockCanvas.height).toBe(1080) }) it('resizes to 1600px for medium quality', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any const result = await resizeImage({ file: originalFile, quality: 'medium', }) expect(result).toBeInstanceOf(File) expect(mockCanvas.width).toBe(1200) // 1600 * (3000/4000) expect(mockCanvas.height).toBe(1600) }) it('resizes to 2048px for high quality', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any const result = await resizeImage({ file: originalFile, quality: 'high', }) expect(result).toBeInstanceOf(File) expect(mockCanvas.width).toBe(1536) // 2048 * (3000/4000) expect(mockCanvas.height).toBe(2048) }) }) describe('Custom quality', () => { it('uses custom size when provided', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any const result = await resizeImage({ file: originalFile, quality: 'low', customQuality: {size: 500, compression: 0.6}, }) expect(result).toBeInstanceOf(File) expect(mockCanvas.width).toBe(375) // 500 * (3000/4000) expect(mockCanvas.height).toBe(500) }) }) describe('Aspect ratio handling', () => { it('maintains aspect ratio for landscape images', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) // Set landscape dimensions mockImage.width = 4000 mockImage.height = 3000 mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any await resizeImage({ file: originalFile, quality: 'low', }) expect(mockCanvas.width).toBe(1080) expect(mockCanvas.height).toBe(810) // 1080 * (3000/4000) }) it('does not resize if image is smaller than target size', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) // Set small dimensions mockImage.width = 800 mockImage.height = 600 mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any await resizeImage({ file: originalFile, quality: 'high', }) // Should maintain original dimensions expect(mockCanvas.width).toBe(800) expect(mockCanvas.height).toBe(600) }) }) describe('Error handling', () => { it('rejects when image fails to load', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onerror) img.onerror() }, 0) return img }) as any await expect( resizeImage({ file: originalFile, quality: 'medium', }) ).rejects.toThrow('Failed to load image') expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:mock-url') }) }) describe('Resource cleanup', () => { it('revokes object URL after successful resize', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) mockCanvas.toBlob.mockImplementation((callback: any) => { const blob = new Blob(['resized'], {type: 'image/jpeg'}) callback(blob) }) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onload) img.onload() }, 0) return img }) as any await resizeImage({ file: originalFile, quality: 'medium', }) expect(URL.createObjectURL).toHaveBeenCalledWith(originalFile) expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:mock-url') }) it('revokes object URL even when error occurs', async () => { const originalFile = new File(['test'], 'test.jpg', {type: 'image/jpeg'}) global.Image = vi.fn(() => { const img = mockImage setTimeout(() => { if (img.onerror) img.onerror() }, 0) return img }) as any try { await resizeImage({ file: originalFile, quality: 'medium', }) } catch { // Expected to throw } expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:mock-url') }) }) })