chore: migrate tests from tests-ui/ to colocate with source files (#7811)

## Summary

Migrates all unit tests from `tests-ui/` to colocate with their source
files in `src/`, improving discoverability and maintainability.

## Changes

- **What**: Relocated all unit tests to be adjacent to the code they
test, following the `<source>.test.ts` naming convention
- **Config**: Updated `vitest.config.ts` to remove `tests-ui` include
pattern and `@tests-ui` alias
- **Docs**: Moved testing documentation to `docs/testing/` with updated
paths and patterns

## Review Focus

- Migration patterns documented in
`temp/plans/migrate-tests-ui-to-src.md`
- Tests use `@/` path aliases instead of relative imports
- Shared fixtures placed in `__fixtures__/` directories

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7811-chore-migrate-tests-from-tests-ui-to-colocate-with-source-files-2da6d73d36508147a4cce85365dee614)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Alexander Brown
2026-01-05 16:32:24 -08:00
committed by GitHub
parent 832588c7a9
commit 10feb1fd5b
272 changed files with 483 additions and 1239 deletions

View File

@@ -0,0 +1,197 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useImageLoader } from '@/composables/maskeditor/useImageLoader'
const mockCanvasManager = {
invalidateCanvas: vi.fn().mockResolvedValue(undefined),
updateMaskColor: vi.fn().mockResolvedValue(undefined)
}
const mockStore = {
imgCanvas: null as any,
maskCanvas: null as any,
rgbCanvas: null as any,
imgCtx: null as any,
maskCtx: null as any,
image: null as any
}
const mockDataStore = {
inputData: null as any
}
vi.mock('@/stores/maskEditorStore', () => ({
useMaskEditorStore: vi.fn(() => mockStore)
}))
vi.mock('@/stores/maskEditorDataStore', () => ({
useMaskEditorDataStore: vi.fn(() => mockDataStore)
}))
vi.mock('@/composables/maskeditor/useCanvasManager', () => ({
useCanvasManager: vi.fn(() => mockCanvasManager)
}))
vi.mock('@vueuse/core', () => ({
createSharedComposable: (fn: any) => fn
}))
describe('useImageLoader', () => {
let mockBaseImage: HTMLImageElement
let mockMaskImage: HTMLImageElement
let mockPaintImage: HTMLImageElement
beforeEach(() => {
vi.clearAllMocks()
mockBaseImage = {
width: 512,
height: 512
} as HTMLImageElement
mockMaskImage = {
width: 512,
height: 512
} as HTMLImageElement
mockPaintImage = {
width: 512,
height: 512
} as HTMLImageElement
mockStore.imgCtx = {
clearRect: vi.fn()
}
mockStore.maskCtx = {
clearRect: vi.fn()
}
mockStore.imgCanvas = {
width: 0,
height: 0
}
mockStore.maskCanvas = {
width: 0,
height: 0
}
mockStore.rgbCanvas = {
width: 0,
height: 0
}
mockDataStore.inputData = {
baseLayer: { image: mockBaseImage },
maskLayer: { image: mockMaskImage },
paintLayer: { image: mockPaintImage }
}
})
describe('loadImages', () => {
it('should load images successfully', async () => {
const loader = useImageLoader()
const result = await loader.loadImages()
expect(result).toBe(mockBaseImage)
expect(mockStore.image).toBe(mockBaseImage)
})
it('should set canvas dimensions', async () => {
const loader = useImageLoader()
await loader.loadImages()
expect(mockStore.maskCanvas.width).toBe(512)
expect(mockStore.maskCanvas.height).toBe(512)
expect(mockStore.rgbCanvas.width).toBe(512)
expect(mockStore.rgbCanvas.height).toBe(512)
})
it('should clear canvas contexts', async () => {
const loader = useImageLoader()
await loader.loadImages()
expect(mockStore.imgCtx.clearRect).toHaveBeenCalledWith(0, 0, 0, 0)
expect(mockStore.maskCtx.clearRect).toHaveBeenCalledWith(0, 0, 0, 0)
})
it('should call canvasManager methods', async () => {
const loader = useImageLoader()
await loader.loadImages()
expect(mockCanvasManager.invalidateCanvas).toHaveBeenCalledWith(
mockBaseImage,
mockMaskImage,
mockPaintImage
)
expect(mockCanvasManager.updateMaskColor).toHaveBeenCalled()
})
it('should handle missing paintLayer', async () => {
mockDataStore.inputData = {
baseLayer: { image: mockBaseImage },
maskLayer: { image: mockMaskImage },
paintLayer: null
}
const loader = useImageLoader()
await loader.loadImages()
expect(mockCanvasManager.invalidateCanvas).toHaveBeenCalledWith(
mockBaseImage,
mockMaskImage,
null
)
})
it('should throw error when no input data', async () => {
mockDataStore.inputData = null
const loader = useImageLoader()
await expect(loader.loadImages()).rejects.toThrow(
'No input data available in dataStore'
)
})
it('should throw error when canvas elements missing', async () => {
mockStore.imgCanvas = null
const loader = useImageLoader()
await expect(loader.loadImages()).rejects.toThrow(
'Canvas elements or contexts not available'
)
})
it('should throw error when contexts missing', async () => {
mockStore.imgCtx = null
const loader = useImageLoader()
await expect(loader.loadImages()).rejects.toThrow(
'Canvas elements or contexts not available'
)
})
it('should handle different image dimensions', async () => {
mockBaseImage.width = 1024
mockBaseImage.height = 768
const loader = useImageLoader()
await loader.loadImages()
expect(mockStore.maskCanvas.width).toBe(1024)
expect(mockStore.maskCanvas.height).toBe(768)
expect(mockStore.rgbCanvas.width).toBe(1024)
expect(mockStore.rgbCanvas.height).toBe(768)
})
})
})