mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-08 08:08:04 +00:00
Compare commits
6 Commits
austin/pos
...
fix/highli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c330529da8 | ||
|
|
50d339e2ba | ||
|
|
ed10909f38 | ||
|
|
65ff23c5af | ||
|
|
6ce60a11a4 | ||
|
|
3b5d124029 |
@@ -18,7 +18,8 @@ Basic setup for testing Pinia stores:
|
||||
|
||||
```typescript
|
||||
// Example from: tests-ui/tests/store/workflowStore.test.ts
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useWorkflowStore } from '@/domains/workflow/ui/stores/workflowStore'
|
||||
@@ -27,8 +28,8 @@ describe('useWorkflowStore', () => {
|
||||
let store: ReturnType<typeof useWorkflowStore>
|
||||
|
||||
beforeEach(() => {
|
||||
// Create a fresh pinia and activate it for each test
|
||||
setActivePinia(createPinia())
|
||||
// Create a fresh testing pinia and activate it for each test
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
// Initialize the store
|
||||
store = useWorkflowStore()
|
||||
|
||||
76
src/composables/graph/useGraphErrorState.ts
Normal file
76
src/composables/graph/useGraphErrorState.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { watch } from 'vue'
|
||||
|
||||
import type { LGraphNode, Subgraph } from '@/lib/litegraph/src/litegraph'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useGraphErrorStateStore } from '@/stores/graphErrorStateStore'
|
||||
import { parseNodeLocatorId } from '@/types/nodeIdentification'
|
||||
import {
|
||||
findSubgraphByUuid,
|
||||
forEachNode,
|
||||
forEachSubgraphNode
|
||||
} from '@/utils/graphTraversalUtil'
|
||||
|
||||
export function useGraphErrorState(): void {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
watch(
|
||||
() => store.version,
|
||||
() => {
|
||||
const rootGraph = app.rootGraph
|
||||
if (!rootGraph) return
|
||||
|
||||
forEachNode(rootGraph, (node) => {
|
||||
node.has_errors = false
|
||||
if (node.inputs) {
|
||||
for (const slot of node.inputs) {
|
||||
slot.hasErrors = false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
for (const [nodeId, keys] of store.keysByNode) {
|
||||
if (keys.size === 0) continue
|
||||
|
||||
const parsed = parseNodeLocatorId(nodeId)
|
||||
if (!parsed) continue
|
||||
|
||||
const targetGraph = parsed.subgraphUuid
|
||||
? findSubgraphByUuid(rootGraph, parsed.subgraphUuid)
|
||||
: rootGraph
|
||||
if (!targetGraph) continue
|
||||
|
||||
const node = targetGraph.getNodeById(parsed.localNodeId)
|
||||
if (!node) continue
|
||||
|
||||
node.has_errors = true
|
||||
|
||||
for (const key of keys) {
|
||||
const error = store.errorsByKey.get(key)
|
||||
if (error && error.target.kind === 'slot' && node.inputs) {
|
||||
const slotName = error.target.slotName
|
||||
const slot = node.inputs.find((s) => s.name === slotName)
|
||||
if (slot) {
|
||||
slot.hasErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
propagateErrorToParents(node)
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
}
|
||||
|
||||
function propagateErrorToParents(node: LGraphNode): void {
|
||||
const subgraph = node.graph as Subgraph | undefined
|
||||
if (!subgraph || subgraph.isRootGraph) return
|
||||
|
||||
const subgraphId = subgraph.id
|
||||
if (!subgraphId) return
|
||||
|
||||
forEachSubgraphNode(app.rootGraph, subgraphId, (subgraphNode) => {
|
||||
subgraphNode.has_errors = true
|
||||
propagateErrorToParents(subgraphNode)
|
||||
})
|
||||
}
|
||||
122
src/composables/graph/useRequiredConnectionValidator.test.ts
Normal file
122
src/composables/graph/useRequiredConnectionValidator.test.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useGraphErrorStateStore } from '@/stores/graphErrorStateStore'
|
||||
|
||||
vi.mock('@/scripts/api', () => ({
|
||||
api: {
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn()
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('@/scripts/app', () => ({
|
||||
app: {
|
||||
rootGraph: null
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('@/stores/nodeDefStore', () => ({
|
||||
useNodeDefStore: vi.fn(() => ({
|
||||
nodeDefsByName: {}
|
||||
}))
|
||||
}))
|
||||
|
||||
vi.mock('@/utils/graphTraversalUtil', () => ({
|
||||
forEachNode: vi.fn()
|
||||
}))
|
||||
|
||||
describe('useRequiredConnectionValidator', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('store integration', () => {
|
||||
it('adds errors for missing required connections', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:missing:1:model',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'model' },
|
||||
code: 'MISSING_REQUIRED_INPUT'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(store.hasSlotError('1', 'model')).toBe(true)
|
||||
expect(store.hasErrorsForNode('1')).toBe(true)
|
||||
})
|
||||
|
||||
it('clears errors when connections are made', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:missing:1:model',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'model' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(store.hasSlotError('1', 'model')).toBe(true)
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: []
|
||||
})
|
||||
|
||||
expect(store.hasSlotError('1', 'model')).toBe(false)
|
||||
})
|
||||
|
||||
it('preserves backend errors when frontend errors change', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'backend',
|
||||
errors: [
|
||||
{
|
||||
key: 'backend:node:2',
|
||||
source: 'backend',
|
||||
target: { kind: 'node', nodeId: '2' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:missing:1:model',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'model' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(true)
|
||||
expect(store.hasErrorsForNode('2')).toBe(true)
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: []
|
||||
})
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(false)
|
||||
expect(store.hasErrorsForNode('2')).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
74
src/composables/graph/useRequiredConnectionValidator.ts
Normal file
74
src/composables/graph/useRequiredConnectionValidator.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { onUnmounted } from 'vue'
|
||||
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useGraphErrorStateStore } from '@/stores/graphErrorStateStore'
|
||||
import type { GraphError } from '@/stores/graphErrorStateStore'
|
||||
import { useNodeDefStore } from '@/stores/nodeDefStore'
|
||||
import { createNodeLocatorId } from '@/types/nodeIdentification'
|
||||
import { forEachNode } from '@/utils/graphTraversalUtil'
|
||||
|
||||
export function useRequiredConnectionValidator(): void {
|
||||
const errorStore = useGraphErrorStateStore()
|
||||
const nodeDefStore = useNodeDefStore()
|
||||
|
||||
function validate(): void {
|
||||
const rootGraph = app.rootGraph
|
||||
if (!rootGraph) return
|
||||
|
||||
const errors: GraphError[] = []
|
||||
|
||||
forEachNode(rootGraph, (node: LGraphNode) => {
|
||||
const nodeDef = nodeDefStore.nodeDefsByName[node.type ?? '']
|
||||
if (!nodeDef?.input?.required) return
|
||||
|
||||
const subgraphId =
|
||||
node.graph && !node.graph.isRootGraph ? node.graph.id : null
|
||||
const locatorId = subgraphId
|
||||
? createNodeLocatorId(subgraphId, node.id)
|
||||
: String(node.id)
|
||||
|
||||
for (const inputName of Object.keys(nodeDef.input.required)) {
|
||||
const slot = node.inputs?.find((s) => s.name === inputName)
|
||||
|
||||
const hasConnection = slot?.link !== null && slot?.link !== undefined
|
||||
const hasWidgetValue = hasWidgetValueForInput(node, inputName)
|
||||
|
||||
if (!hasConnection && !hasWidgetValue) {
|
||||
errors.push({
|
||||
key: `frontend:missing:${locatorId}:${inputName}`,
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: locatorId, slotName: inputName },
|
||||
code: 'MISSING_REQUIRED_INPUT'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
errorStore.execute({ type: 'REPLACE_SOURCE', source: 'frontend', errors })
|
||||
}
|
||||
|
||||
function hasWidgetValueForInput(
|
||||
node: LGraphNode,
|
||||
inputName: string
|
||||
): boolean {
|
||||
if (!node.widgets) return false
|
||||
const widget = node.widgets.find((w) => w.name === inputName)
|
||||
if (!widget) return false
|
||||
return (
|
||||
widget.value !== undefined && widget.value !== null && widget.value !== ''
|
||||
)
|
||||
}
|
||||
|
||||
const debouncedValidate = useDebounceFn(validate, 200)
|
||||
|
||||
api.addEventListener('graphChanged', debouncedValidate)
|
||||
|
||||
onUnmounted(() => {
|
||||
api.removeEventListener('graphChanged', debouncedValidate)
|
||||
})
|
||||
|
||||
validate()
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type * as VueI18nModule from 'vue-i18n'
|
||||
|
||||
@@ -79,7 +80,7 @@ describe('useSubscriptionCredits', () => {
|
||||
let authStore: ReturnType<typeof useFirebaseAuthStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
authStore = useFirebaseAuthStore()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { until } from '@vueuse/core'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -40,7 +41,7 @@ describe('useVersionCompatibilityStore', () => {
|
||||
let mockSettingStore: { get: ReturnType<typeof vi.fn> }
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
// Clear the mock dismissal storage
|
||||
mockDismissalStorage.value = {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
@@ -66,7 +67,7 @@ describe('useWorkflowStore', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useWorkflowStore()
|
||||
bookmarkStore = useWorkflowBookmarkStore()
|
||||
vi.clearAllMocks()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type * as I18n from 'vue-i18n'
|
||||
|
||||
@@ -108,7 +109,7 @@ describe('useWorkflowPersistence', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date('2025-01-01T00:00:00Z'))
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
localStorage.clear()
|
||||
sessionStorage.clear()
|
||||
vi.clearAllMocks()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useTeamWorkspaceStore } from './teamWorkspaceStore'
|
||||
@@ -111,7 +112,7 @@ const mockMemberWorkspace = {
|
||||
|
||||
describe('useTeamWorkspaceStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
vi.stubGlobal('localStorage', mockLocalStorage)
|
||||
sessionStorage.clear()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
@@ -15,7 +16,7 @@ vi.mock('@/stores/workspace/colorPaletteStore', () => ({
|
||||
|
||||
describe('useMinimapSettings', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
@@ -29,7 +30,7 @@ const makeNodeData = (overrides: Partial<VueNodeData> = {}): VueNodeData => ({
|
||||
})
|
||||
|
||||
const setupMockStores = () => {
|
||||
const pinia = createPinia()
|
||||
const pinia = createTestingPinia({ stubActions: false })
|
||||
setActivePinia(pinia)
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable vue/one-component-per-file */
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia } from 'pinia'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
@@ -84,7 +84,7 @@ const mountSlots = (nodeData: VueNodeData, readonly = false) => {
|
||||
})
|
||||
return mount(NodeSlots, {
|
||||
global: {
|
||||
plugins: [i18n, createPinia()],
|
||||
plugins: [i18n, createTestingPinia({ stubActions: false })],
|
||||
stubs: {
|
||||
InputSlot: InputSlotStub,
|
||||
OutputSlot: OutputSlotStub
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { CORE_KEYBINDINGS } from '@/constants/coreKeybindings'
|
||||
@@ -30,7 +31,7 @@ describe('keybindingService - Escape key handling', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
// Mock command store execute
|
||||
const commandStore = useCommandStore()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { app } from '@/scripts/app'
|
||||
@@ -68,7 +69,7 @@ describe('keybindingService - Event Forwarding', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
// Mock command store execute
|
||||
const commandStore = useCommandStore()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -83,7 +84,7 @@ describe('useComfyRegistryStore', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
mockRegistryService = {
|
||||
isLoading: ref(false),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
@@ -11,7 +12,7 @@ const MockComponent = defineComponent({
|
||||
|
||||
describe('dialogStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
describe('priority system', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import { useDomWidgetStore } from '@/stores/domWidgetStore'
|
||||
@@ -30,7 +31,7 @@ describe('domWidgetStore', () => {
|
||||
let store: ReturnType<typeof useDomWidgetStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useDomWidgetStore()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { app } from '@/scripts/app'
|
||||
@@ -59,7 +60,7 @@ describe('useExecutionStore - NodeLocatorId conversions', () => {
|
||||
mockNodeIdToNodeLocatorId.mockReset()
|
||||
mockNodeLocatorIdToNodeExecutionId.mockReset()
|
||||
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useExecutionStore()
|
||||
})
|
||||
|
||||
@@ -137,7 +138,7 @@ describe('useExecutionStore - Node Error Lookups', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useExecutionStore()
|
||||
})
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ import type {
|
||||
} from '@/schemas/apiSchema'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useGraphErrorStateStore } from '@/stores/graphErrorStateStore'
|
||||
import type { GraphError } from '@/stores/graphErrorStateStore'
|
||||
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
|
||||
import type { NodeLocatorId } from '@/types/nodeIdentification'
|
||||
import { createNodeLocatorId } from '@/types/nodeIdentification'
|
||||
import { forEachNode, getNodeByExecutionId } from '@/utils/graphTraversalUtil'
|
||||
|
||||
interface QueuedPrompt {
|
||||
/**
|
||||
@@ -584,59 +585,47 @@ export const useExecutionStore = defineStore('execution', () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update node and slot error flags when validation errors change.
|
||||
* Propagates errors up subgraph chains.
|
||||
* Sync backend validation errors to centralized graph error store.
|
||||
* The store handles flag updates and subgraph propagation.
|
||||
*/
|
||||
watch(lastNodeErrors, () => {
|
||||
if (!app.rootGraph) return
|
||||
const errorStore = useGraphErrorStateStore()
|
||||
|
||||
// Clear all error flags
|
||||
forEachNode(app.rootGraph, (node) => {
|
||||
node.has_errors = false
|
||||
if (node.inputs) {
|
||||
for (const slot of node.inputs) {
|
||||
slot.hasErrors = false
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!lastNodeErrors.value) {
|
||||
errorStore.execute({ type: 'CLEAR_SOURCE', source: 'backend' })
|
||||
return
|
||||
}
|
||||
|
||||
if (!lastNodeErrors.value) return
|
||||
const errors: GraphError[] = []
|
||||
|
||||
// Set error flags on nodes and slots
|
||||
for (const [executionId, nodeError] of Object.entries(
|
||||
lastNodeErrors.value
|
||||
)) {
|
||||
const node = getNodeByExecutionId(app.rootGraph, executionId)
|
||||
if (!node) continue
|
||||
const locatorId = executionIdToNodeLocatorId(executionId)
|
||||
if (!locatorId) continue
|
||||
|
||||
node.has_errors = true
|
||||
errors.push({
|
||||
key: `backend:node:${locatorId}`,
|
||||
source: 'backend',
|
||||
target: { kind: 'node', nodeId: locatorId },
|
||||
message: nodeError.errors[0]?.message
|
||||
})
|
||||
|
||||
// Mark input slots with errors
|
||||
if (node.inputs) {
|
||||
for (const error of nodeError.errors) {
|
||||
const slotName = error.extra_info?.input_name
|
||||
if (!slotName) continue
|
||||
|
||||
const slot = node.inputs.find((s) => s.name === slotName)
|
||||
if (slot) {
|
||||
slot.hasErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate errors to parent subgraph nodes
|
||||
const parts = executionId.split(':')
|
||||
for (let i = parts.length - 1; i > 0; i--) {
|
||||
const parentExecutionId = parts.slice(0, i).join(':')
|
||||
const parentNode = getNodeByExecutionId(
|
||||
app.rootGraph,
|
||||
parentExecutionId
|
||||
)
|
||||
if (parentNode) {
|
||||
parentNode.has_errors = true
|
||||
for (const error of nodeError.errors) {
|
||||
const slotName = error.extra_info?.input_name
|
||||
if (slotName) {
|
||||
errors.push({
|
||||
key: `backend:slot:${locatorId}:${slotName}`,
|
||||
source: 'backend',
|
||||
target: { kind: 'slot', nodeId: locatorId, slotName },
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: error.message
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorStore.execute({ type: 'REPLACE_SOURCE', source: 'backend', errors })
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FirebaseError } from 'firebase/app'
|
||||
import * as firebaseAuth from 'firebase/auth'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import * as vuefire from 'vuefire'
|
||||
|
||||
@@ -153,7 +154,7 @@ describe('useFirebaseAuthStore', () => {
|
||||
})
|
||||
|
||||
// Initialize Pinia
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useFirebaseAuthStore()
|
||||
|
||||
// Reset and set up getIdToken mock
|
||||
@@ -175,7 +176,7 @@ describe('useFirebaseAuthStore', () => {
|
||||
|
||||
vi.mocked(vuefire.useFirebaseAuth).mockReturnValue(mockAuth as any)
|
||||
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useFirebaseAuthStore()
|
||||
})
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
}
|
||||
|
||||
const createCustomer = async (): Promise<CreateCustomerResponse> => {
|
||||
const authHeader = await getFirebaseAuthHeader()
|
||||
const authHeader = await getAuthHeader()
|
||||
if (!authHeader) {
|
||||
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
|
||||
}
|
||||
|
||||
257
src/stores/graphErrorStateStore.test.ts
Normal file
257
src/stores/graphErrorStateStore.test.ts
Normal file
@@ -0,0 +1,257 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import { useGraphErrorStateStore } from './graphErrorStateStore'
|
||||
import type { GraphError } from './graphErrorStateStore'
|
||||
|
||||
describe('graphErrorStateStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
})
|
||||
|
||||
describe('REPLACE_SOURCE command', () => {
|
||||
it('adds errors for a source', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
const errors: GraphError[] = [
|
||||
{
|
||||
key: 'frontend:slot:123:model',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '123', slotName: 'model' },
|
||||
code: 'MISSING_REQUIRED_INPUT'
|
||||
}
|
||||
]
|
||||
|
||||
store.execute({ type: 'REPLACE_SOURCE', source: 'frontend', errors })
|
||||
|
||||
expect(store.hasErrorsForNode('123')).toBe(true)
|
||||
expect(store.hasSlotError('123', 'model')).toBe(true)
|
||||
expect(store.version).toBe(1)
|
||||
})
|
||||
|
||||
it('replaces all errors for a source', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:1:a',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'a' }
|
||||
},
|
||||
{
|
||||
key: 'frontend:slot:2:b',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '2', slotName: 'b' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(true)
|
||||
expect(store.hasErrorsForNode('2')).toBe(true)
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:3:c',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '3', slotName: 'c' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(false)
|
||||
expect(store.hasErrorsForNode('2')).toBe(false)
|
||||
expect(store.hasErrorsForNode('3')).toBe(true)
|
||||
})
|
||||
|
||||
it('preserves errors from other sources', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'backend',
|
||||
errors: [
|
||||
{
|
||||
key: 'backend:node:1',
|
||||
source: 'backend',
|
||||
target: { kind: 'node', nodeId: '1' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:2:a',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '2', slotName: 'a' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(true)
|
||||
expect(store.hasErrorsForNode('2')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('CLEAR_SOURCE command', () => {
|
||||
it('clears errors for a source', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:1:a',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'a' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
store.execute({ type: 'CLEAR_SOURCE', source: 'frontend' })
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(false)
|
||||
})
|
||||
|
||||
it('preserves other sources', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'backend',
|
||||
errors: [
|
||||
{
|
||||
key: 'backend:node:1',
|
||||
source: 'backend',
|
||||
target: { kind: 'node', nodeId: '1' }
|
||||
}
|
||||
]
|
||||
})
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:2:a',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '2', slotName: 'a' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
store.execute({ type: 'CLEAR_SOURCE', source: 'frontend' })
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(true)
|
||||
expect(store.hasErrorsForNode('2')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('CLEAR_ALL command', () => {
|
||||
it('clears all errors', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'backend',
|
||||
errors: [
|
||||
{
|
||||
key: 'backend:node:1',
|
||||
source: 'backend',
|
||||
target: { kind: 'node', nodeId: '1' }
|
||||
}
|
||||
]
|
||||
})
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:2:a',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '2', slotName: 'a' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
store.execute({ type: 'CLEAR_ALL' })
|
||||
|
||||
expect(store.hasErrorsForNode('1')).toBe(false)
|
||||
expect(store.hasErrorsForNode('2')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getErrorsForNode', () => {
|
||||
it('returns all errors for a node', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:slot:1:a',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'a' }
|
||||
},
|
||||
{
|
||||
key: 'frontend:slot:1:b',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'b' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const errors = store.getErrorsForNode('1')
|
||||
expect(errors).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('returns empty array for node without errors', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
expect(store.getErrorsForNode('999')).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSlotErrors', () => {
|
||||
it('returns only slot errors for specific slot', () => {
|
||||
const store = useGraphErrorStateStore()
|
||||
|
||||
store.execute({
|
||||
type: 'REPLACE_SOURCE',
|
||||
source: 'frontend',
|
||||
errors: [
|
||||
{
|
||||
key: 'frontend:node:1',
|
||||
source: 'frontend',
|
||||
target: { kind: 'node', nodeId: '1' }
|
||||
},
|
||||
{
|
||||
key: 'frontend:slot:1:model',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'model' }
|
||||
},
|
||||
{
|
||||
key: 'frontend:slot:1:clip',
|
||||
source: 'frontend',
|
||||
target: { kind: 'slot', nodeId: '1', slotName: 'clip' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const slotErrors = store.getSlotErrors('1', 'model')
|
||||
expect(slotErrors).toHaveLength(1)
|
||||
expect(slotErrors[0].target).toEqual({
|
||||
kind: 'slot',
|
||||
nodeId: '1',
|
||||
slotName: 'model'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
144
src/stores/graphErrorStateStore.ts
Normal file
144
src/stores/graphErrorStateStore.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { shallowRef } from 'vue'
|
||||
|
||||
import type { NodeLocatorId } from '@/types/nodeIdentification'
|
||||
|
||||
type GraphErrorSource = 'frontend' | 'backend'
|
||||
|
||||
type GraphErrorTarget =
|
||||
| { kind: 'node'; nodeId: NodeLocatorId }
|
||||
| { kind: 'slot'; nodeId: NodeLocatorId; slotName: string }
|
||||
|
||||
export interface GraphError {
|
||||
key: string
|
||||
source: GraphErrorSource
|
||||
target: GraphErrorTarget
|
||||
code?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
type GraphErrorCommand =
|
||||
| { type: 'REPLACE_SOURCE'; source: GraphErrorSource; errors: GraphError[] }
|
||||
| { type: 'CLEAR_SOURCE'; source: GraphErrorSource }
|
||||
| { type: 'CLEAR_ALL' }
|
||||
|
||||
export const useGraphErrorStateStore = defineStore('graphErrorState', () => {
|
||||
const errorsByKey = shallowRef(new Map<string, GraphError>())
|
||||
const keysBySource = shallowRef(new Map<GraphErrorSource, Set<string>>())
|
||||
const keysByNode = shallowRef(new Map<NodeLocatorId, Set<string>>())
|
||||
const version = shallowRef(0)
|
||||
|
||||
function addErrorInternal(error: GraphError): void {
|
||||
const newErrorsByKey = new Map(errorsByKey.value)
|
||||
newErrorsByKey.set(error.key, error)
|
||||
errorsByKey.value = newErrorsByKey
|
||||
|
||||
const newKeysBySource = new Map(keysBySource.value)
|
||||
if (!newKeysBySource.has(error.source)) {
|
||||
newKeysBySource.set(error.source, new Set())
|
||||
}
|
||||
newKeysBySource.get(error.source)!.add(error.key)
|
||||
keysBySource.value = newKeysBySource
|
||||
|
||||
const nodeId = error.target.nodeId
|
||||
const newKeysByNode = new Map(keysByNode.value)
|
||||
if (!newKeysByNode.has(nodeId)) {
|
||||
newKeysByNode.set(nodeId, new Set())
|
||||
}
|
||||
newKeysByNode.get(nodeId)!.add(error.key)
|
||||
keysByNode.value = newKeysByNode
|
||||
}
|
||||
|
||||
function clearSourceInternal(source: GraphErrorSource): void {
|
||||
const keys = keysBySource.value.get(source)
|
||||
if (!keys || keys.size === 0) return
|
||||
|
||||
const newErrorsByKey = new Map(errorsByKey.value)
|
||||
const newKeysByNode = new Map(keysByNode.value)
|
||||
|
||||
for (const key of keys) {
|
||||
const error = newErrorsByKey.get(key)
|
||||
if (error) {
|
||||
const nodeId = error.target.nodeId
|
||||
const nodeKeys = newKeysByNode.get(nodeId)
|
||||
if (nodeKeys) {
|
||||
const newNodeKeys = new Set(nodeKeys)
|
||||
newNodeKeys.delete(key)
|
||||
if (newNodeKeys.size === 0) {
|
||||
newKeysByNode.delete(nodeId)
|
||||
} else {
|
||||
newKeysByNode.set(nodeId, newNodeKeys)
|
||||
}
|
||||
}
|
||||
newErrorsByKey.delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
errorsByKey.value = newErrorsByKey
|
||||
keysByNode.value = newKeysByNode
|
||||
|
||||
const newKeysBySource = new Map(keysBySource.value)
|
||||
newKeysBySource.delete(source)
|
||||
keysBySource.value = newKeysBySource
|
||||
}
|
||||
|
||||
function execute(command: GraphErrorCommand): void {
|
||||
switch (command.type) {
|
||||
case 'REPLACE_SOURCE': {
|
||||
clearSourceInternal(command.source)
|
||||
for (const error of command.errors) {
|
||||
addErrorInternal(error)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'CLEAR_SOURCE': {
|
||||
clearSourceInternal(command.source)
|
||||
break
|
||||
}
|
||||
case 'CLEAR_ALL': {
|
||||
errorsByKey.value = new Map()
|
||||
keysBySource.value = new Map()
|
||||
keysByNode.value = new Map()
|
||||
break
|
||||
}
|
||||
}
|
||||
version.value++
|
||||
}
|
||||
|
||||
function getErrorsForNode(nodeId: NodeLocatorId): GraphError[] {
|
||||
const keys = keysByNode.value.get(nodeId)
|
||||
if (!keys) return []
|
||||
return [...keys]
|
||||
.map((k) => errorsByKey.value.get(k))
|
||||
.filter((e): e is GraphError => e !== undefined)
|
||||
}
|
||||
|
||||
function hasErrorsForNode(nodeId: NodeLocatorId): boolean {
|
||||
const keys = keysByNode.value.get(nodeId)
|
||||
return keys !== undefined && keys.size > 0
|
||||
}
|
||||
|
||||
function getSlotErrors(
|
||||
nodeId: NodeLocatorId,
|
||||
slotName: string
|
||||
): GraphError[] {
|
||||
return getErrorsForNode(nodeId).filter(
|
||||
(e) => e.target.kind === 'slot' && e.target.slotName === slotName
|
||||
)
|
||||
}
|
||||
|
||||
function hasSlotError(nodeId: NodeLocatorId, slotName: string): boolean {
|
||||
return getSlotErrors(nodeId, slotName).length > 0
|
||||
}
|
||||
|
||||
return {
|
||||
version,
|
||||
errorsByKey,
|
||||
keysByNode,
|
||||
execute,
|
||||
getErrorsForNode,
|
||||
hasErrorsForNode,
|
||||
getSlotErrors,
|
||||
hasSlotError
|
||||
}
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
@@ -30,7 +31,7 @@ const createMockOutputs = (
|
||||
|
||||
describe('imagePreviewStore getPreviewParam', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
vi.mocked(litegraphUtil.isVideoNode).mockReturnValue(false)
|
||||
})
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import { KeybindingImpl, useKeybindingStore } from '@/stores/keybindingStore'
|
||||
|
||||
describe('useKeybindingStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
it('should add and retrieve default keybindings', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { assetService } from '@/platform/assets/services/assetService'
|
||||
@@ -89,7 +90,7 @@ describe('useModelStore', () => {
|
||||
let store: ReturnType<typeof useModelStore>
|
||||
|
||||
beforeEach(async () => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.resetAllMocks()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { ComfyNodeDef as ComfyNodeDefV1 } from '@/schemas/nodeDefSchema'
|
||||
@@ -82,7 +83,7 @@ vi.mock('@/stores/nodeDefStore', async (importOriginal) => {
|
||||
|
||||
describe('useModelToNodeStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
@@ -330,7 +331,7 @@ describe('useModelToNodeStore', () => {
|
||||
|
||||
it('should not register when nodeDefStore is empty', () => {
|
||||
// Create fresh Pinia for this test to avoid state persistence
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
vi.mocked(useNodeDefStore, { partial: true }).mockReturnValue({
|
||||
nodeDefsByName: {}
|
||||
@@ -355,7 +356,7 @@ describe('useModelToNodeStore', () => {
|
||||
|
||||
it('should return empty Record when nodeDefStore is empty', () => {
|
||||
// Create fresh Pinia for this test to avoid state persistence
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
vi.mocked(useNodeDefStore, { partial: true }).mockReturnValue({
|
||||
nodeDefsByName: {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import type { ComfyNodeDef } from '@/schemas/nodeDefSchema'
|
||||
@@ -9,7 +10,7 @@ describe('useNodeDefStore', () => {
|
||||
let store: ReturnType<typeof useNodeDefStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useNodeDefStore()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type {
|
||||
@@ -71,7 +72,7 @@ describe('TaskItemImpl.loadWorkflow - workflow fetching', () => {
|
||||
let mockFetchApi: ReturnType<typeof vi.fn>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
|
||||
mockFetchApi = vi.fn()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { JobListItem } from '@/platform/remote/comfyui/jobs/jobTypes'
|
||||
@@ -240,7 +241,7 @@ describe('useQueueStore', () => {
|
||||
let store: ReturnType<typeof useQueueStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useQueueStore()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import type { ServerConfig } from '@/constants/serverConfig'
|
||||
@@ -14,7 +15,7 @@ describe('useServerConfigStore', () => {
|
||||
let store: ReturnType<typeof useServerConfigStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useServerConfigStore()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
@@ -47,7 +48,7 @@ vi.mock('@/utils/graphTraversalUtil', () => ({
|
||||
|
||||
describe('useSubgraphNavigationStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
it('should not clear navigation stack when workflow internal state changes', async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
@@ -46,7 +47,7 @@ const mockCanvas = app.canvas as any
|
||||
|
||||
describe('useSubgraphNavigationStore - Viewport Persistence', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
// Reset canvas state
|
||||
mockCanvas.ds.scale = 1
|
||||
mockCanvas.ds.offset = [0, 0]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { ComfyNodeDef as ComfyNodeDefV1 } from '@/schemas/nodeDefSchema'
|
||||
@@ -78,7 +79,7 @@ describe('useSubgraphStore', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useSubgraphStore()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { api } from '@/scripts/api'
|
||||
@@ -25,7 +26,7 @@ describe('useSystemStatsStore', () => {
|
||||
beforeEach(() => {
|
||||
// Mock API to prevent automatic fetch on store creation
|
||||
vi.mocked(api.getSystemStats).mockResolvedValue(null as any)
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useSystemStatsStore()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useTemplateRankingStore } from '@/stores/templateRankingStore'
|
||||
@@ -12,7 +13,7 @@ vi.mock('axios', () => ({
|
||||
|
||||
describe('templateRankingStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { api } from '@/scripts/api'
|
||||
@@ -19,7 +20,7 @@ describe('useUserFileStore', () => {
|
||||
let store: ReturnType<typeof useUserFileStore>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useUserFileStore()
|
||||
vi.resetAllMocks()
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
||||
@@ -53,7 +54,7 @@ vi.mock('@/utils/envUtil', () => ({
|
||||
|
||||
describe('useBottomPanelStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
it('should initialize with empty panels', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import { useNodeHelpStore } from '@/stores/workspace/nodeHelpStore'
|
||||
@@ -14,7 +15,7 @@ describe('nodeHelpStore', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
it('should initialize with empty state', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type NodeSearchBoxPopover from '@/components/searchbox/NodeSearchBoxPopover.vue'
|
||||
@@ -34,7 +35,7 @@ function createMockSettingStore(): ReturnType<typeof useSettingStore> {
|
||||
|
||||
describe('useSearchBoxStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
@@ -45,6 +45,8 @@ import UnloadWindowConfirmDialog from '@/components/dialog/UnloadWindowConfirmDi
|
||||
import GraphCanvas from '@/components/graph/GraphCanvas.vue'
|
||||
import GlobalToast from '@/components/toast/GlobalToast.vue'
|
||||
import RerouteMigrationToast from '@/components/toast/RerouteMigrationToast.vue'
|
||||
import { useGraphErrorState } from '@/composables/graph/useGraphErrorState'
|
||||
import { useRequiredConnectionValidator } from '@/composables/graph/useRequiredConnectionValidator'
|
||||
import { useBrowserTabTitle } from '@/composables/useBrowserTabTitle'
|
||||
import { useCoreCommands } from '@/composables/useCoreCommands'
|
||||
import { useErrorHandling } from '@/composables/useErrorHandling'
|
||||
@@ -85,6 +87,8 @@ import ManagerProgressToast from '@/workbench/extensions/manager/components/Mana
|
||||
setupAutoQueueHandler()
|
||||
useProgressFavicon()
|
||||
useBrowserTabTitle()
|
||||
useGraphErrorState()
|
||||
useRequiredConnectionValidator()
|
||||
|
||||
const { t } = useI18n()
|
||||
const toast = useToast()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { computed, ref } from 'vue'
|
||||
@@ -44,11 +45,11 @@ vi.mock(
|
||||
)
|
||||
|
||||
describe('NodeConflictDialogContent', () => {
|
||||
let pinia: ReturnType<typeof createPinia>
|
||||
let pinia: ReturnType<typeof createTestingPinia>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
pinia = createPinia()
|
||||
pinia = createTestingPinia({ stubActions: false })
|
||||
setActivePinia(pinia)
|
||||
// Reset mock data
|
||||
mockConflictData.value = []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { VueWrapper } from '@vue/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import Tooltip from 'primevue/tooltip'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
@@ -89,7 +89,7 @@ describe('PackVersionBadge', () => {
|
||||
...props
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue, createPinia(), i18n],
|
||||
plugins: [PrimeVue, createTestingPinia({ stubActions: false }), i18n],
|
||||
directives: {
|
||||
tooltip: Tooltip
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { VueWrapper } from '@vue/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import Listbox from 'primevue/listbox'
|
||||
@@ -115,7 +115,7 @@ describe('PackVersionSelectorPopover', () => {
|
||||
...props
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue, createPinia(), i18n],
|
||||
plugins: [PrimeVue, createTestingPinia({ stubActions: false }), i18n],
|
||||
components: {
|
||||
Listbox,
|
||||
VerifiedIcon,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { VueWrapper } from '@vue/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import ToggleSwitch from 'primevue/toggleswitch'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
@@ -81,7 +81,7 @@ describe('PackEnableToggle', () => {
|
||||
...props
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue, createPinia(), i18n]
|
||||
plugins: [PrimeVue, createTestingPinia({ stubActions: false }), i18n]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { VueWrapper } from '@vue/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
@@ -73,7 +73,7 @@ describe('PackCardFooter', () => {
|
||||
...props
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue, createPinia(), i18n],
|
||||
plugins: [PrimeVue, createTestingPinia({ stubActions: false }), i18n],
|
||||
provide: {
|
||||
[IsInstallingKey]: ref(false)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { VueWrapper } from '@vue/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
@@ -32,7 +32,7 @@ describe('GridSkeleton', () => {
|
||||
...props
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue, createPinia(), i18n],
|
||||
plugins: [PrimeVue, createTestingPinia({ stubActions: false }), i18n],
|
||||
stubs: {
|
||||
PackCardSkeleton: true
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -36,7 +37,7 @@ describe('usePacksSelection', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
const pinia = createPinia()
|
||||
const pinia = createTestingPinia({ stubActions: false })
|
||||
setActivePinia(pinia)
|
||||
|
||||
managerStore = useComfyManagerStore()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -48,7 +49,7 @@ describe('usePacksStatus', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
conflictDetectionStore = useConflictDetectionStore()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createSharedComposable } from '@vueuse/core'
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
@@ -9,7 +10,6 @@ import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { mapAllNodes } from '@/utils/graphTraversalUtil'
|
||||
import { useNodePacks } from '@/workbench/extensions/manager/composables/nodePack/useNodePacks'
|
||||
import type { UseNodePacksOptions } from '@/workbench/extensions/manager/types/comfyManagerTypes'
|
||||
|
||||
type WorkflowPack = {
|
||||
id:
|
||||
@@ -22,9 +22,10 @@ const CORE_NODES_PACK_NAME = 'comfy-core'
|
||||
|
||||
/**
|
||||
* Handles parsing node pack metadata from nodes on the graph and fetching the
|
||||
* associated node packs from the registry
|
||||
* associated node packs from the registry.
|
||||
* This is a shared singleton composable - all components use the same instance.
|
||||
*/
|
||||
export const useWorkflowPacks = (options: UseNodePacksOptions = {}) => {
|
||||
const _useWorkflowPacks = () => {
|
||||
const nodeDefStore = useNodeDefStore()
|
||||
const systemStatsStore = useSystemStatsStore()
|
||||
const { inferPackFromNodeName } = useComfyRegistryStore()
|
||||
@@ -129,7 +130,7 @@ export const useWorkflowPacks = (options: UseNodePacksOptions = {}) => {
|
||||
)
|
||||
|
||||
const { startFetch, cleanup, error, isLoading, nodePacks, isReady } =
|
||||
useNodePacks(workflowPacksIds, options)
|
||||
useNodePacks(workflowPacksIds)
|
||||
|
||||
const isIdInWorkflow = (packId: string) =>
|
||||
workflowPacksIds.value.includes(packId)
|
||||
@@ -153,3 +154,5 @@ export const useWorkflowPacks = (options: UseNodePacksOptions = {}) => {
|
||||
filterWorkflowPack
|
||||
}
|
||||
}
|
||||
|
||||
export const useWorkflowPacks = createSharedComposable(_useWorkflowPacks)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
describe('useConflictAcknowledgment', () => {
|
||||
beforeEach(() => {
|
||||
// Set up Pinia for each test
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
// Clear localStorage before each test
|
||||
localStorage.clear()
|
||||
// Reset modules to ensure fresh state
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
@@ -114,7 +115,7 @@ vi.mock('@/workbench/extensions/manager/composables/useManagerState', () => ({
|
||||
}))
|
||||
|
||||
describe('useConflictDetection', () => {
|
||||
let pinia: ReturnType<typeof createPinia>
|
||||
let pinia: ReturnType<typeof createTestingPinia>
|
||||
|
||||
const mockComfyManagerService = {
|
||||
getImportFailInfoBulk: vi.fn(),
|
||||
@@ -221,7 +222,7 @@ describe('useConflictDetection', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
pinia = createPinia()
|
||||
pinia = createTestingPinia({ stubActions: false })
|
||||
setActivePinia(pinia)
|
||||
|
||||
// Setup mocks
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
@@ -31,7 +32,7 @@ describe('useImportFailedDetection', () => {
|
||||
let mockDialogService: ReturnType<typeof dialogService.useDialogService>
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
mockComfyManagerStore = {
|
||||
isPackInstalled: vi.fn()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick, ref } from 'vue'
|
||||
|
||||
@@ -72,7 +73,7 @@ describe('useComfyManagerStore', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
mockManagerService = {
|
||||
isLoading: ref(false),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import { useConflictDetectionStore } from '@/workbench/extensions/manager/stores/conflictDetectionStore'
|
||||
@@ -6,7 +7,7 @@ import type { ConflictDetectionResult } from '@/workbench/extensions/manager/typ
|
||||
|
||||
describe('useConflictDetectionStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
const mockConflictedPackages: ConflictDetectionResult[] = [
|
||||
|
||||
Reference in New Issue
Block a user