mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-09 17:40:09 +00:00
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:
committed by
GitHub
parent
6b6b467e68
commit
b1d8bf0b13
@@ -11,13 +11,18 @@ vi.mock('@/platform/distribution/types', () => ({
|
||||
|
||||
const downloadFileMock = vi.fn()
|
||||
vi.mock('@/base/common/downloadUtil', () => ({
|
||||
downloadFile: (...args: any[]) => downloadFileMock(...args)
|
||||
downloadFile: (url: string, filename?: string) => {
|
||||
if (filename === undefined) {
|
||||
return downloadFileMock(url)
|
||||
}
|
||||
return downloadFileMock(url, filename)
|
||||
}
|
||||
}))
|
||||
|
||||
const copyToClipboardMock = vi.fn()
|
||||
vi.mock('@/composables/useCopyToClipboard', () => ({
|
||||
useCopyToClipboard: () => ({
|
||||
copyToClipboard: (...args: any[]) => copyToClipboardMock(...args)
|
||||
copyToClipboard: (text: string) => copyToClipboardMock(text)
|
||||
})
|
||||
}))
|
||||
|
||||
@@ -30,8 +35,8 @@ vi.mock('@/i18n', () => ({
|
||||
|
||||
const mapTaskOutputToAssetItemMock = vi.fn()
|
||||
vi.mock('@/platform/assets/composables/media/assetMappers', () => ({
|
||||
mapTaskOutputToAssetItem: (...args: any[]) =>
|
||||
mapTaskOutputToAssetItemMock(...args)
|
||||
mapTaskOutputToAssetItem: (taskItem: TaskItemImpl, output: ResultItemImpl) =>
|
||||
mapTaskOutputToAssetItemMock(taskItem, output)
|
||||
}))
|
||||
|
||||
const mediaAssetActionsMock = {
|
||||
@@ -67,14 +72,16 @@ const interruptMock = vi.fn()
|
||||
const deleteItemMock = vi.fn()
|
||||
vi.mock('@/scripts/api', () => ({
|
||||
api: {
|
||||
interrupt: (...args: any[]) => interruptMock(...args),
|
||||
deleteItem: (...args: any[]) => deleteItemMock(...args)
|
||||
interrupt: (runningPromptId: string | null) =>
|
||||
interruptMock(runningPromptId),
|
||||
deleteItem: (type: string, id: string) => deleteItemMock(type, id)
|
||||
}
|
||||
}))
|
||||
|
||||
const downloadBlobMock = vi.fn()
|
||||
vi.mock('@/scripts/utils', () => ({
|
||||
downloadBlob: (...args: any[]) => downloadBlobMock(...args)
|
||||
downloadBlob: (filename: string, blob: Blob) =>
|
||||
downloadBlobMock(filename, blob)
|
||||
}))
|
||||
|
||||
const dialogServiceMock = {
|
||||
@@ -94,11 +101,14 @@ vi.mock('@/services/litegraphService', () => ({
|
||||
useLitegraphService: () => litegraphServiceMock
|
||||
}))
|
||||
|
||||
const nodeDefStoreMock = {
|
||||
nodeDefsByName: {} as Record<string, any>
|
||||
const nodeDefStoreMock: {
|
||||
nodeDefsByName: Record<string, Partial<ComfyNodeDefImpl>>
|
||||
} = {
|
||||
nodeDefsByName: {}
|
||||
}
|
||||
vi.mock('@/stores/nodeDefStore', () => ({
|
||||
useNodeDefStore: () => nodeDefStoreMock
|
||||
useNodeDefStore: () => nodeDefStoreMock,
|
||||
ComfyNodeDefImpl: class {}
|
||||
}))
|
||||
|
||||
const queueStoreMock = {
|
||||
@@ -118,12 +128,13 @@ vi.mock('@/stores/executionStore', () => ({
|
||||
|
||||
const getJobWorkflowMock = vi.fn()
|
||||
vi.mock('@/services/jobOutputCache', () => ({
|
||||
getJobWorkflow: (...args: any[]) => getJobWorkflowMock(...args)
|
||||
getJobWorkflow: (jobId: string) => getJobWorkflowMock(jobId)
|
||||
}))
|
||||
|
||||
const createAnnotatedPathMock = vi.fn()
|
||||
vi.mock('@/utils/createAnnotatedPath', () => ({
|
||||
createAnnotatedPath: (...args: any[]) => createAnnotatedPathMock(...args)
|
||||
createAnnotatedPath: (filename: string, subfolder: string, type: string) =>
|
||||
createAnnotatedPathMock(filename, subfolder, type)
|
||||
}))
|
||||
|
||||
const appendJsonExtMock = vi.fn((value: string) =>
|
||||
@@ -135,7 +146,8 @@ vi.mock('@/utils/formatUtil', () => ({
|
||||
}))
|
||||
|
||||
import { useJobMenu } from '@/composables/queue/useJobMenu'
|
||||
import type { TaskItemImpl } from '@/stores/queueStore'
|
||||
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
|
||||
import type { ResultItemImpl, TaskItemImpl } from '@/stores/queueStore'
|
||||
|
||||
type MockTaskRef = Record<string, unknown>
|
||||
|
||||
@@ -193,9 +205,9 @@ describe('useJobMenu', () => {
|
||||
}))
|
||||
createAnnotatedPathMock.mockReturnValue('annotated-path')
|
||||
nodeDefStoreMock.nodeDefsByName = {
|
||||
LoadImage: { id: 'LoadImage' },
|
||||
LoadVideo: { id: 'LoadVideo' },
|
||||
LoadAudio: { id: 'LoadAudio' }
|
||||
LoadImage: { name: 'LoadImage' },
|
||||
LoadVideo: { name: 'LoadVideo' },
|
||||
LoadAudio: { name: 'LoadAudio' }
|
||||
}
|
||||
// Default: no workflow available via lazy loading
|
||||
getJobWorkflowMock.mockResolvedValue(undefined)
|
||||
@@ -257,7 +269,7 @@ describe('useJobMenu', () => {
|
||||
['initialization', interruptMock, deleteItemMock]
|
||||
])('cancels %s job via interrupt', async (state) => {
|
||||
const { cancelJob } = mountJobMenu()
|
||||
setCurrentItem(createJobItem({ state: state as any }))
|
||||
setCurrentItem(createJobItem({ state: state as JobListItem['state'] }))
|
||||
|
||||
await cancelJob()
|
||||
|
||||
@@ -292,7 +304,9 @@ describe('useJobMenu', () => {
|
||||
setCurrentItem(
|
||||
createJobItem({
|
||||
state: 'failed',
|
||||
taskRef: { errorMessage: 'Something went wrong' } as any
|
||||
taskRef: {
|
||||
errorMessage: 'Something went wrong'
|
||||
} as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
@@ -324,7 +338,7 @@ describe('useJobMenu', () => {
|
||||
errorMessage: 'CUDA out of memory',
|
||||
executionError,
|
||||
createTime: 12345
|
||||
} as any
|
||||
} as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
@@ -344,7 +358,9 @@ describe('useJobMenu', () => {
|
||||
setCurrentItem(
|
||||
createJobItem({
|
||||
state: 'failed',
|
||||
taskRef: { errorMessage: 'Job failed with error' } as any
|
||||
taskRef: {
|
||||
errorMessage: 'Job failed with error'
|
||||
} as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
@@ -366,7 +382,7 @@ describe('useJobMenu', () => {
|
||||
setCurrentItem(
|
||||
createJobItem({
|
||||
state: 'failed',
|
||||
taskRef: { errorMessage: undefined } as any
|
||||
taskRef: { errorMessage: undefined } as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
@@ -514,7 +530,12 @@ describe('useJobMenu', () => {
|
||||
|
||||
it('ignores add-to-current entry when preview missing entirely', async () => {
|
||||
const { jobMenuEntries } = mountJobMenu()
|
||||
setCurrentItem(createJobItem({ state: 'completed', taskRef: {} as any }))
|
||||
setCurrentItem(
|
||||
createJobItem({
|
||||
state: 'completed',
|
||||
taskRef: {} as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
await nextTick()
|
||||
const entry = findActionEntry(jobMenuEntries.value, 'add-to-current')
|
||||
@@ -543,7 +564,12 @@ describe('useJobMenu', () => {
|
||||
|
||||
it('ignores download request when preview missing', async () => {
|
||||
const { jobMenuEntries } = mountJobMenu()
|
||||
setCurrentItem(createJobItem({ state: 'completed', taskRef: {} as any }))
|
||||
setCurrentItem(
|
||||
createJobItem({
|
||||
state: 'completed',
|
||||
taskRef: {} as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
await nextTick()
|
||||
const entry = findActionEntry(jobMenuEntries.value, 'download')
|
||||
@@ -751,7 +777,7 @@ describe('useJobMenu', () => {
|
||||
setCurrentItem(
|
||||
createJobItem({
|
||||
state: 'failed',
|
||||
taskRef: { errorMessage: 'Some error' } as any
|
||||
taskRef: { errorMessage: 'Some error' } as Partial<TaskItemImpl>
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user