import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { setActivePinia, createPinia } from 'pinia' import { useImagesStore } from '@/stores/images' import type { Image } from '@/types' const makeImage = (overrides: Partial = {}): Image => ({ id: 1, originalFilename: 'photo.jpg', thumbnailUrl: '/thumb/1.jpg', originalUrl: '/orig/1.jpg', uploadedAt: '2026-01-01T00:00:00Z', approvedDeviceIds: [], cropParams: null, stickerState: null, ...overrides, }) describe('images store', () => { beforeEach(() => { vi.unstubAllGlobals() vi.restoreAllMocks() setActivePinia(createPinia()) }) afterEach(() => { // unstubAllGlobals is handled in beforeEach so stubs don't leak // even if a test throws before afterEach runs }) it('fetchImages success populates images and clears loading', async () => { const mockImages = [makeImage(), makeImage({ id: 2 })] vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockImages), })) const store = useImagesStore() await store.fetchImages() expect(store.images).toEqual(mockImages) expect(store.loading).toBe(false) expect(store.error).toBeNull() }) it('fetchImages network error sets error state', async () => { vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('Net error'))) const store = useImagesStore() await store.fetchImages() expect(store.images).toEqual([]) expect(store.error).toBe('Net error') expect(store.loading).toBe(false) }) it('uploadImage prepends to images list on success', async () => { const existing = makeImage({ id: 1 }) const newImage = makeImage({ id: 2 }) vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(newImage), })) const store = useImagesStore() store.images = [existing] const file = new File(['data'], 'photo.jpg', { type: 'image/jpeg' }) const result = await store.uploadImage(file) expect(result).toEqual(newImage) expect(store.images[0]).toEqual(newImage) expect(store.images).toHaveLength(2) }) it('uploadImage throws with error message on failure', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: false, json: () => Promise.resolve({ error: 'File too large' }), })) const store = useImagesStore() const file = new File(['data'], 'photo.jpg', { type: 'image/jpeg' }) await expect(store.uploadImage(file)).rejects.toThrow('File too large') }) it('deleteImage removes image from list', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true })) const store = useImagesStore() store.images = [makeImage({ id: 1 }), makeImage({ id: 2 })] await store.deleteImage(1) expect(store.images).toHaveLength(1) expect(store.images[0].id).toBe(2) }) it('deleteImage throws on failure', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: false })) const store = useImagesStore() store.images = [makeImage()] await expect(store.deleteImage(1)).rejects.toThrow('Delete failed') }) it('setApproval updates image in list', async () => { const original = makeImage({ id: 1, approvedDeviceIds: [] }) const updated = makeImage({ id: 1, approvedDeviceIds: [42] }) vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(updated), })) const store = useImagesStore() store.images = [original] await store.setApproval(1, 42, true) expect(store.images[0].approvedDeviceIds).toEqual([42]) }) it('fetchPendingCount stores the count', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ count: 5 }), })) const store = useImagesStore() await store.fetchPendingCount() expect(store.pendingCount).toBe(5) }) it('approveShared decrements pendingCount', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ id: 1, status: 'approved' }), })) const store = useImagesStore() store.pendingCount = 3 await store.approveShared(1, [42]) expect(store.pendingCount).toBe(2) }) it('declineShared decrements pendingCount', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ id: 1, status: 'declined' }), })) const store = useImagesStore() store.pendingCount = 2 await store.declineShared(1) expect(store.pendingCount).toBe(1) }) })