refactor: eliminate unsafe type assertions from Group 2 test files (#8258)

## Summary
Improved type safety in test files by eliminating unsafe type assertions
and adopting official testing patterns. Reduced unsafe `as unknown as`
type assertions and eliminated all `null!` assertions.

## Changes
- **Adopted @pinia/testing patterns**
- Replaced manual Pinia store mocking with `createTestingPinia()` in
`useSelectionState.test.ts`
  - Eliminated ~120 lines of mock boilerplate
- Created `createMockSettingStore()` helper to replace duplicated store
mocks in `useCoreCommands.test.ts`

- **Eliminated unsafe null assertions**
- Created explicit `MockMaskEditorStore` interface with proper nullable
types in `useCanvasTools.test.ts`
- Replaced `null!` initializations with `null` and used `!` at point of
use or `?.` for optional chaining

- **Made partial mock intent explicit**
- Updated test utilities in `litegraphTestUtils.ts` to use explicit
`Partial<T>` typing
- Changed cast pattern from `as T` to `as Partial<T> as T` to show
incomplete mock intent
- Applied to `createMockLGraphNode()`, `createMockPositionable()`, and
`createMockLGraphGroup()`

- **Created centralized mock utilities** in
`src/utils/__tests__/litegraphTestUtils.ts`
- `createMockLGraphNode()`, `createMockPositionable()`,
`createMockLGraphGroup()`, `createMockSubgraphNode()`
  - Updated 8+ test files to use centralized utilities
- Used union types `Partial<T> | Record<string, unknown>` for flexible
mock creation

## Results
-  0 typecheck errors
-  0 lint errors  
-  All tests passing in modified files
-  Eliminated all `null!` assertions
-  Reduced unsafe double-cast patterns significantly

## Files Modified (18)
- `src/components/graph/SelectionToolbox.test.ts`
-
`src/components/graph/selectionToolbox/{BypassButton,ColorPickerButton,ExecuteButton}.test.ts`
- `src/components/sidebar/tabs/queue/ResultGallery.test.ts`
- `src/composables/canvas/useSelectedLiteGraphItems.test.ts`
- `src/composables/graph/{useGraphHierarchy,useSelectionState}.test.ts`
-
`src/composables/maskeditor/{useCanvasHistory,useCanvasManager,useCanvasTools,useCanvasTransform}.test.ts`
- `src/composables/node/{useNodePricing,useWatchWidget}.test.ts`
- `src/composables/{useBrowserTabTitle,useCoreCommands}.test.ts`
- `src/utils/__tests__/litegraphTestUtils.ts`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8258-refactor-eliminate-unsafe-type-assertions-from-Group-2-test-files-2f16d73d365081549c65fd546cc7c765)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: AustinMroz <austin@comfy.org>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
This commit is contained in:
Johnpaul Chiwetelu
2026-01-24 05:10:35 +01:00
committed by GitHub
parent 6b6b467e68
commit b1d8bf0b13
24 changed files with 785 additions and 658 deletions

View File

@@ -5,9 +5,26 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createI18n } from 'vue-i18n'
import SelectionToolbox from '@/components/graph/SelectionToolbox.vue'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { useExtensionService } from '@/services/extensionService'
import {
createMockCanvas,
createMockPositionable
} from '@/utils/__tests__/litegraphTestUtils'
function createMockExtensionService(): ReturnType<typeof useExtensionService> {
return {
extensionCommands: { value: new Map() },
loadExtensions: vi.fn(),
registerExtension: vi.fn(),
invokeExtensions: vi.fn(() => []),
invokeExtensionsAsync: vi.fn()
} as Partial<ReturnType<typeof useExtensionService>> as ReturnType<
typeof useExtensionService
>
}
// Mock the composables and services
vi.mock('@/renderer/core/canvas/useCanvasInteractions', () => ({
@@ -112,12 +129,7 @@ describe('SelectionToolbox', () => {
canvasStore = useCanvasStore()
// Mock the canvas to avoid "getCanvas: canvas is null" errors
canvasStore.canvas = {
setDirty: vi.fn(),
state: {
selectionChanged: false
}
} as any
canvasStore.canvas = createMockCanvas()
vi.resetAllMocks()
})
@@ -184,30 +196,27 @@ describe('SelectionToolbox', () => {
describe('Button Visibility Logic', () => {
beforeEach(() => {
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
})
it('should show info button only for single selections', () => {
// Single node selection
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.info-button').exists()).toBe(true)
// Multiple node selection
canvasStore.selectedItems = [
{ type: 'TestNode1' },
{ type: 'TestNode2' }
] as any
createMockPositionable(),
createMockPositionable()
]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(wrapper2.find('.info-button').exists()).toBe(false)
})
it('should not show info button when node definition is not found', () => {
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
// mock nodedef and return null
nodeDefMock = null
// remount component
@@ -217,7 +226,7 @@ describe('SelectionToolbox', () => {
it('should show color picker for all selections', () => {
// Single node selection
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('[data-testid="color-picker-button"]').exists()).toBe(
true
@@ -225,9 +234,9 @@ describe('SelectionToolbox', () => {
// Multiple node selection
canvasStore.selectedItems = [
{ type: 'TestNode1' },
{ type: 'TestNode2' }
] as any
createMockPositionable(),
createMockPositionable()
]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(
@@ -237,15 +246,15 @@ describe('SelectionToolbox', () => {
it('should show frame nodes only for multiple selections', () => {
// Single node selection
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.frame-nodes').exists()).toBe(false)
// Multiple node selection
canvasStore.selectedItems = [
{ type: 'TestNode1' },
{ type: 'TestNode2' }
] as any
createMockPositionable(),
createMockPositionable()
]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(wrapper2.find('.frame-nodes').exists()).toBe(true)
@@ -253,22 +262,22 @@ describe('SelectionToolbox', () => {
it('should show bypass button for appropriate selections', () => {
// Single node selection
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('[data-testid="bypass-button"]').exists()).toBe(true)
// Multiple node selection
canvasStore.selectedItems = [
{ type: 'TestNode1' },
{ type: 'TestNode2' }
] as any
createMockPositionable(),
createMockPositionable()
]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(wrapper2.find('[data-testid="bypass-button"]').exists()).toBe(true)
})
it('should show common buttons for all selections', () => {
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('[data-testid="delete-button"]').exists()).toBe(true)
@@ -286,13 +295,13 @@ describe('SelectionToolbox', () => {
// Single image node
isImageNodeSpy.mockReturnValue(true)
canvasStore.selectedItems = [{ type: 'ImageNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.mask-editor-button').exists()).toBe(true)
// Single non-image node
isImageNodeSpy.mockReturnValue(false)
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(wrapper2.find('.mask-editor-button').exists()).toBe(false)
@@ -304,13 +313,13 @@ describe('SelectionToolbox', () => {
// Single Load3D node
isLoad3dNodeSpy.mockReturnValue(true)
canvasStore.selectedItems = [{ type: 'Load3DNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.load-3d-viewer-button').exists()).toBe(true)
// Single non-Load3D node
isLoad3dNodeSpy.mockReturnValue(false)
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(wrapper2.find('.load-3d-viewer-button').exists()).toBe(false)
@@ -326,17 +335,17 @@ describe('SelectionToolbox', () => {
// With output node selected
isOutputNodeSpy.mockReturnValue(true)
filterOutputNodesSpy.mockReturnValue([{ type: 'SaveImage' }] as any)
canvasStore.selectedItems = [
{ type: 'SaveImage', constructor: { nodeData: { output_node: true } } }
] as any
filterOutputNodesSpy.mockReturnValue([
{ type: 'SaveImage' }
] as LGraphNode[])
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.execute-button').exists()).toBe(true)
// Without output node selected
isOutputNodeSpy.mockReturnValue(false)
filterOutputNodesSpy.mockReturnValue([])
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
wrapper.unmount()
const wrapper2 = mountComponent()
expect(wrapper2.find('.execute-button').exists()).toBe(false)
@@ -352,7 +361,7 @@ describe('SelectionToolbox', () => {
describe('Divider Visibility Logic', () => {
it('should show dividers between button groups when both groups have buttons', () => {
// Setup single node to show info + other buttons
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
const dividers = wrapper.findAll('.vertical-divider')
@@ -378,10 +387,13 @@ describe('SelectionToolbox', () => {
['test-command', { id: 'test-command', title: 'Test Command' }]
])
},
invokeExtensions: vi.fn(() => ['test-command'])
} as any)
loadExtensions: vi.fn(),
registerExtension: vi.fn(),
invokeExtensions: vi.fn(() => ['test-command']),
invokeExtensionsAsync: vi.fn()
} as ReturnType<typeof useExtensionService>)
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.extension-command-button').exists()).toBe(true)
@@ -389,12 +401,9 @@ describe('SelectionToolbox', () => {
it('should not render extension commands when none available', () => {
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
expect(wrapper.find('.extension-command-button').exists()).toBe(false)
@@ -404,12 +413,9 @@ describe('SelectionToolbox', () => {
describe('Container Styling', () => {
it('should apply minimap container styles', () => {
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
const panel = wrapper.find('.panel')
@@ -418,12 +424,9 @@ describe('SelectionToolbox', () => {
it('should have correct CSS classes', () => {
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
const panel = wrapper.find('.panel')
@@ -435,12 +438,9 @@ describe('SelectionToolbox', () => {
it('should handle animation class conditionally', () => {
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
const panel = wrapper.find('.panel')
@@ -453,16 +453,18 @@ describe('SelectionToolbox', () => {
const mockCanvasInteractions = vi.mocked(useCanvasInteractions)
const forwardEventToCanvasSpy = vi.fn()
mockCanvasInteractions.mockReturnValue({
forwardEventToCanvas: forwardEventToCanvasSpy
} as any)
handleWheel: vi.fn(),
handlePointer: vi.fn(),
forwardEventToCanvas: forwardEventToCanvasSpy,
shouldHandleNodePointerEvents: { value: true } as ReturnType<
typeof useCanvasInteractions
>['shouldHandleNodePointerEvents']
} as ReturnType<typeof useCanvasInteractions>)
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
canvasStore.selectedItems = [{ type: 'TestNode' }] as any
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = mountComponent()
const panel = wrapper.find('.panel')
@@ -475,10 +477,7 @@ describe('SelectionToolbox', () => {
describe('No Selection State', () => {
beforeEach(() => {
const mockExtensionService = vi.mocked(useExtensionService)
mockExtensionService.mockReturnValue({
extensionCommands: { value: new Map() },
invokeExtensions: vi.fn(() => [])
} as any)
mockExtensionService.mockReturnValue(createMockExtensionService())
})
it('should hide most buttons when no items selected', () => {

View File

@@ -6,14 +6,14 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createI18n } from 'vue-i18n'
import BypassButton from '@/components/graph/selectionToolbox/BypassButton.vue'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { LGraphEventMode } from '@/lib/litegraph/src/litegraph'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCommandStore } from '@/stores/commandStore'
import { createMockLGraphNode } from '@/utils/__tests__/litegraphTestUtils'
const mockLGraphNode = {
type: 'TestNode',
title: 'Test Node',
mode: LGraphEventMode.ALWAYS
function getMockLGraphNode(): LGraphNode {
return createMockLGraphNode({ type: 'TestNode' })
}
vi.mock('@/utils/litegraphUtil', () => ({
@@ -59,21 +59,21 @@ describe('BypassButton', () => {
}
it('should render bypass button', () => {
canvasStore.selectedItems = [mockLGraphNode] as any
canvasStore.selectedItems = [getMockLGraphNode()]
const wrapper = mountComponent()
const button = wrapper.find('button')
expect(button.exists()).toBe(true)
})
it('should have correct test id', () => {
canvasStore.selectedItems = [mockLGraphNode] as any
canvasStore.selectedItems = [getMockLGraphNode()]
const wrapper = mountComponent()
const button = wrapper.find('[data-testid="bypass-button"]')
expect(button.exists()).toBe(true)
})
it('should execute bypass command when clicked', async () => {
canvasStore.selectedItems = [mockLGraphNode] as any
canvasStore.selectedItems = [getMockLGraphNode()]
const executeSpy = vi.spyOn(commandStore, 'execute').mockResolvedValue()
const wrapper = mountComponent()
@@ -85,8 +85,11 @@ describe('BypassButton', () => {
})
it('should show bypassed styling when node is bypassed', async () => {
const bypassedNode = { ...mockLGraphNode, mode: LGraphEventMode.BYPASS }
canvasStore.selectedItems = [bypassedNode] as any
const bypassedNode: Partial<LGraphNode> = {
...getMockLGraphNode(),
mode: LGraphEventMode.BYPASS
}
canvasStore.selectedItems = [bypassedNode as LGraphNode]
vi.spyOn(commandStore, 'execute').mockResolvedValue()
const wrapper = mountComponent()
@@ -100,7 +103,7 @@ describe('BypassButton', () => {
it('should handle multiple selected items', () => {
vi.spyOn(commandStore, 'execute').mockResolvedValue()
canvasStore.selectedItems = [mockLGraphNode, mockLGraphNode] as any
canvasStore.selectedItems = [getMockLGraphNode(), getMockLGraphNode()]
const wrapper = mountComponent()
const button = wrapper.find('button')
expect(button.exists()).toBe(true)

View File

@@ -1,3 +1,4 @@
import type { Mock } from 'vitest'
import { mount } from '@vue/test-utils'
import { createPinia, setActivePinia } from 'pinia'
import PrimeVue from 'primevue/config'
@@ -8,7 +9,20 @@ import { createI18n } from 'vue-i18n'
// Import after mocks
import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import type { LoadedComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { createMockPositionable } from '@/utils/__tests__/litegraphTestUtils'
function createMockWorkflow(
overrides: Partial<LoadedComfyWorkflow> = {}
): LoadedComfyWorkflow {
return {
changeTracker: {
checkState: vi.fn() as Mock
},
...overrides
} as Partial<LoadedComfyWorkflow> as LoadedComfyWorkflow
}
// Mock the litegraph module
vi.mock('@/lib/litegraph/src/litegraph', async () => {
@@ -70,11 +84,7 @@ describe('ColorPickerButton', () => {
canvasStore.selectedItems = []
// Mock workflow store
workflowStore.activeWorkflow = {
changeTracker: {
checkState: vi.fn()
}
} as any
workflowStore.activeWorkflow = createMockWorkflow()
})
const createWrapper = () => {
@@ -90,13 +100,13 @@ describe('ColorPickerButton', () => {
it('should render when nodes are selected', () => {
// Add a mock node to selectedItems
canvasStore.selectedItems = [{ type: 'LGraphNode' } as any]
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = createWrapper()
expect(wrapper.find('button').exists()).toBe(true)
})
it('should toggle color picker visibility on button click', async () => {
canvasStore.selectedItems = [{ type: 'LGraphNode' } as any]
canvasStore.selectedItems = [createMockPositionable()]
const wrapper = createWrapper()
const button = wrapper.find('button')

View File

@@ -1,23 +1,16 @@
import { mount } from '@vue/test-utils'
import { createPinia, setActivePinia } from 'pinia'
import { createTestingPinia } from '@pinia/testing'
import { setActivePinia } from 'pinia'
import PrimeVue from 'primevue/config'
import Tooltip from 'primevue/tooltip'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createI18n } from 'vue-i18n'
import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue'
import type { LGraphCanvas, LGraphNode } from '@/lib/litegraph/src/litegraph'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCommandStore } from '@/stores/commandStore'
// Mock the stores
vi.mock('@/renderer/core/canvas/canvasStore', () => ({
useCanvasStore: vi.fn()
}))
vi.mock('@/stores/commandStore', () => ({
useCommandStore: vi.fn()
}))
// Mock the utils
vi.mock('@/utils/litegraphUtil', () => ({
isLGraphNode: vi.fn((node) => !!node?.type)
@@ -37,10 +30,8 @@ vi.mock('@/composables/graph/useSelectionState', () => ({
}))
describe('ExecuteButton', () => {
let mockCanvas: any
let mockCanvasStore: any
let mockCommandStore: any
let mockSelectedNodes: any[]
let mockCanvas: LGraphCanvas
let mockSelectedNodes: LGraphNode[]
const i18n = createI18n({
legacy: false,
@@ -57,27 +48,27 @@ describe('ExecuteButton', () => {
})
beforeEach(async () => {
setActivePinia(createPinia())
// Set up Pinia with testing utilities
setActivePinia(
createTestingPinia({
createSpy: vi.fn
})
)
// Reset mocks
mockCanvas = {
const partialCanvas: Partial<LGraphCanvas> = {
setDirty: vi.fn()
}
mockCanvas = partialCanvas as Partial<LGraphCanvas> as LGraphCanvas
mockSelectedNodes = []
mockCanvasStore = {
getCanvas: vi.fn(() => mockCanvas),
selectedItems: []
}
// Get store instances and mock methods
const canvasStore = useCanvasStore()
const commandStore = useCommandStore()
mockCommandStore = {
execute: vi.fn()
}
// Setup store mocks
vi.mocked(useCanvasStore).mockReturnValue(mockCanvasStore as any)
vi.mocked(useCommandStore).mockReturnValue(mockCommandStore as any)
vi.spyOn(canvasStore, 'getCanvas').mockReturnValue(mockCanvas)
vi.spyOn(commandStore, 'execute').mockResolvedValue()
// Update the useSelectionState mock
const { useSelectionState } = vi.mocked(
@@ -87,7 +78,7 @@ describe('ExecuteButton', () => {
selectedNodes: {
value: mockSelectedNodes
}
} as any)
} as ReturnType<typeof useSelectionState>)
vi.clearAllMocks()
})
@@ -114,15 +105,16 @@ describe('ExecuteButton', () => {
describe('Click Handler', () => {
it('should execute Comfy.QueueSelectedOutputNodes command on click', async () => {
const commandStore = useCommandStore()
const wrapper = mountComponent()
const button = wrapper.find('button')
await button.trigger('click')
expect(mockCommandStore.execute).toHaveBeenCalledWith(
expect(commandStore.execute).toHaveBeenCalledWith(
'Comfy.QueueSelectedOutputNodes'
)
expect(mockCommandStore.execute).toHaveBeenCalledTimes(1)
expect(commandStore.execute).toHaveBeenCalledTimes(1)
})
})
})

View File

@@ -92,7 +92,7 @@ describe('ResultGallery', () => {
}
},
props: {
allGalleryItems: mockGalleryItems as unknown as ResultItemImpl[],
allGalleryItems: mockGalleryItems as ResultItemImpl[],
activeIndex: 0,
...props
},
@@ -117,7 +117,10 @@ describe('ResultGallery', () => {
const wrapper = mountGallery({ activeIndex: -1 })
// Initially galleryVisible should be false
const vm: any = wrapper.vm
type GalleryVM = typeof wrapper.vm & {
galleryVisible: boolean
}
const vm = wrapper.vm as GalleryVM
expect(vm.galleryVisible).toBe(false)
// Change activeIndex
@@ -167,7 +170,11 @@ describe('ResultGallery', () => {
expect(galleria.exists()).toBe(true)
// Check that our PT props for positioning work correctly
const pt = galleria.props('pt') as any
interface GalleriaPT {
prevButton?: { style?: string }
nextButton?: { style?: string }
}
const pt = galleria.props('pt') as GalleriaPT
expect(pt?.prevButton?.style).toContain('position: fixed')
expect(pt?.nextButton?.style).toContain('position: fixed')
})

View File

@@ -4,6 +4,10 @@ import { nextTick } from 'vue'
import BaseThumbnail from '@/components/templates/thumbnails/BaseThumbnail.vue'
type ComponentInstance = InstanceType<typeof BaseThumbnail> & {
error: boolean
}
vi.mock('@vueuse/core', () => ({
useEventListener: vi.fn()
}))
@@ -45,7 +49,7 @@ describe('BaseThumbnail', () => {
it('shows error state when image fails to load', async () => {
const wrapper = mountThumbnail()
const vm = wrapper.vm as any
const vm = wrapper.vm as ComponentInstance
// Manually set error since useEventListener is mocked
vm.error = true