11import { mount } from '@vue/test-utils'
2- import { createPinia , setActivePinia } from 'pinia'
2+ import { setActivePinia } from 'pinia'
33import PrimeVue from 'primevue/config'
44import { beforeEach , describe , expect , it , vi } from 'vitest'
55import { createI18n } from 'vue-i18n'
66
77import SelectionToolbox from '@/components/graph/SelectionToolbox.vue'
8- import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
98import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
109import { useExtensionService } from '@/services/extensionService'
10+ import type { Positionable } from '@/lib/litegraph/src/interfaces'
11+ import { ref } from 'vue'
12+ import { createTestingPinia } from '@pinia/testing'
13+
14+ const mockData = vi . hoisted ( ( ) => {
15+ return { canvas : undefined , selectedItems : [ ] as Positionable [ ] }
16+ } )
17+
18+ vi . mock ( '@/renderer/core/canvas/canvasStore' , ( ) => ( {
19+ useCanvasStore : vi . fn ( ( ) => ( {
20+ canvas : {
21+ setDirty : vi . fn ( ) ,
22+ state : {
23+ selectionChanged : false
24+ }
25+ } ,
26+ selectedItems : ref ( mockData . selectedItems )
27+ } ) )
28+ } ) )
1129
12- // Mock the composables and services
1330vi . mock ( '@/renderer/core/canvas/useCanvasInteractions' , ( ) => ( {
1431 useCanvasInteractions : vi . fn ( ( ) => ( {
1532 handleWheel : vi . fn ( )
@@ -84,8 +101,6 @@ vi.mock('@/stores/nodeDefStore', () => ({
84101} ) )
85102
86103describe ( 'SelectionToolbox' , ( ) => {
87- let canvasStore : ReturnType < typeof useCanvasStore >
88-
89104 const i18n = createI18n ( {
90105 legacy : false ,
91106 locale : 'en' ,
@@ -108,16 +123,7 @@ describe('SelectionToolbox', () => {
108123 }
109124
110125 beforeEach ( ( ) => {
111- setActivePinia ( createPinia ( ) )
112- canvasStore = useCanvasStore ( )
113-
114- // Mock the canvas to avoid "getCanvas: canvas is null" errors
115- canvasStore . canvas = {
116- setDirty : vi . fn ( ) ,
117- state : {
118- selectionChanged : false
119- }
120- } as any
126+ setActivePinia ( createTestingPinia ( { createSpy : vi . fn } ) )
121127
122128 vi . resetAllMocks ( )
123129 } )
@@ -191,12 +197,12 @@ describe('SelectionToolbox', () => {
191197
192198 it ( 'should show info button only for single selections' , ( ) => {
193199 // Single node selection
194- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
200+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
195201 const wrapper = mountComponent ( )
196202 expect ( wrapper . find ( '.info-button' ) . exists ( ) ) . toBe ( true )
197203
198204 // Multiple node selection
199- canvasStore . selectedItems = [
205+ mockData . selectedItems = [
200206 { type : 'TestNode1' } ,
201207 { type : 'TestNode2' }
202208 ] as any
@@ -206,7 +212,7 @@ describe('SelectionToolbox', () => {
206212 } )
207213
208214 it ( 'should not show info button when node definition is not found' , ( ) => {
209- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
215+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
210216 // mock nodedef and return null
211217 nodeDefMock = null
212218 // remount component
@@ -216,14 +222,14 @@ describe('SelectionToolbox', () => {
216222
217223 it ( 'should show color picker for all selections' , ( ) => {
218224 // Single node selection
219- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
225+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
220226 const wrapper = mountComponent ( )
221227 expect ( wrapper . find ( '[data-testid="color-picker-button"]' ) . exists ( ) ) . toBe (
222228 true
223229 )
224230
225231 // Multiple node selection
226- canvasStore . selectedItems = [
232+ mockData . selectedItems = [
227233 { type : 'TestNode1' } ,
228234 { type : 'TestNode2' }
229235 ] as any
@@ -236,12 +242,12 @@ describe('SelectionToolbox', () => {
236242
237243 it ( 'should show frame nodes only for multiple selections' , ( ) => {
238244 // Single node selection
239- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
245+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
240246 const wrapper = mountComponent ( )
241247 expect ( wrapper . find ( '.frame-nodes' ) . exists ( ) ) . toBe ( false )
242248
243249 // Multiple node selection
244- canvasStore . selectedItems = [
250+ mockData . selectedItems = [
245251 { type : 'TestNode1' } ,
246252 { type : 'TestNode2' }
247253 ] as any
@@ -252,12 +258,12 @@ describe('SelectionToolbox', () => {
252258
253259 it ( 'should show bypass button for appropriate selections' , ( ) => {
254260 // Single node selection
255- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
261+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
256262 const wrapper = mountComponent ( )
257263 expect ( wrapper . find ( '[data-testid="bypass-button"]' ) . exists ( ) ) . toBe ( true )
258264
259265 // Multiple node selection
260- canvasStore . selectedItems = [
266+ mockData . selectedItems = [
261267 { type : 'TestNode1' } ,
262268 { type : 'TestNode2' }
263269 ] as any
@@ -267,7 +273,7 @@ describe('SelectionToolbox', () => {
267273 } )
268274
269275 it ( 'should show common buttons for all selections' , ( ) => {
270- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
276+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
271277 const wrapper = mountComponent ( )
272278
273279 expect ( wrapper . find ( '[data-testid="delete-button"]' ) . exists ( ) ) . toBe ( true )
@@ -285,13 +291,13 @@ describe('SelectionToolbox', () => {
285291
286292 // Single image node
287293 isImageNodeSpy . mockReturnValue ( true )
288- canvasStore . selectedItems = [ { type : 'ImageNode' } ] as any
294+ mockData . selectedItems = [ { type : 'ImageNode' } ] as any
289295 const wrapper = mountComponent ( )
290296 expect ( wrapper . find ( '.mask-editor-button' ) . exists ( ) ) . toBe ( true )
291297
292298 // Single non-image node
293299 isImageNodeSpy . mockReturnValue ( false )
294- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
300+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
295301 wrapper . unmount ( )
296302 const wrapper2 = mountComponent ( )
297303 expect ( wrapper2 . find ( '.mask-editor-button' ) . exists ( ) ) . toBe ( false )
@@ -303,13 +309,13 @@ describe('SelectionToolbox', () => {
303309
304310 // Single Load3D node
305311 isLoad3dNodeSpy . mockReturnValue ( true )
306- canvasStore . selectedItems = [ { type : 'Load3DNode' } ] as any
312+ mockData . selectedItems = [ { type : 'Load3DNode' } ] as any
307313 const wrapper = mountComponent ( )
308314 expect ( wrapper . find ( '.load-3d-viewer-button' ) . exists ( ) ) . toBe ( true )
309315
310316 // Single non-Load3D node
311317 isLoad3dNodeSpy . mockReturnValue ( false )
312- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
318+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
313319 wrapper . unmount ( )
314320 const wrapper2 = mountComponent ( )
315321 expect ( wrapper2 . find ( '.load-3d-viewer-button' ) . exists ( ) ) . toBe ( false )
@@ -326,7 +332,7 @@ describe('SelectionToolbox', () => {
326332 // With output node selected
327333 isOutputNodeSpy . mockReturnValue ( true )
328334 filterOutputNodesSpy . mockReturnValue ( [ { type : 'SaveImage' } ] as any )
329- canvasStore . selectedItems = [
335+ mockData . selectedItems = [
330336 { type : 'SaveImage' , constructor : { nodeData : { output_node : true } } }
331337 ] as any
332338 const wrapper = mountComponent ( )
@@ -335,13 +341,13 @@ describe('SelectionToolbox', () => {
335341 // Without output node selected
336342 isOutputNodeSpy . mockReturnValue ( false )
337343 filterOutputNodesSpy . mockReturnValue ( [ ] )
338- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
344+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
339345 wrapper . unmount ( )
340346 const wrapper2 = mountComponent ( )
341347 expect ( wrapper2 . find ( '.execute-button' ) . exists ( ) ) . toBe ( false )
342348
343349 // No selection at all
344- canvasStore . selectedItems = [ ]
350+ mockData . selectedItems = [ ]
345351 wrapper2 . unmount ( )
346352 const wrapper3 = mountComponent ( )
347353 expect ( wrapper3 . find ( '.execute-button' ) . exists ( ) ) . toBe ( false )
@@ -351,7 +357,7 @@ describe('SelectionToolbox', () => {
351357 describe ( 'Divider Visibility Logic' , ( ) => {
352358 it ( 'should show dividers between button groups when both groups have buttons' , ( ) => {
353359 // Setup single node to show info + other buttons
354- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
360+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
355361 const wrapper = mountComponent ( )
356362
357363 const dividers = wrapper . findAll ( '.vertical-divider' )
@@ -360,7 +366,7 @@ describe('SelectionToolbox', () => {
360366
361367 it ( 'should not show dividers when adjacent groups are empty' , ( ) => {
362368 // No selection should show minimal buttons and dividers
363- canvasStore . selectedItems = [ ]
369+ mockData . selectedItems = [ ]
364370 const wrapper = mountComponent ( )
365371
366372 const buttons = wrapper . find ( '.panel' ) . element . children
@@ -380,7 +386,7 @@ describe('SelectionToolbox', () => {
380386 invokeExtensions : vi . fn ( ( ) => [ 'test-command' ] )
381387 } as any )
382388
383- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
389+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
384390 const wrapper = mountComponent ( )
385391
386392 expect ( wrapper . find ( '.extension-command-button' ) . exists ( ) ) . toBe ( true )
@@ -393,7 +399,7 @@ describe('SelectionToolbox', () => {
393399 invokeExtensions : vi . fn ( ( ) => [ ] )
394400 } as any )
395401
396- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
402+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
397403 const wrapper = mountComponent ( )
398404
399405 expect ( wrapper . find ( '.extension-command-button' ) . exists ( ) ) . toBe ( false )
@@ -408,7 +414,7 @@ describe('SelectionToolbox', () => {
408414 invokeExtensions : vi . fn ( ( ) => [ ] )
409415 } as any )
410416
411- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
417+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
412418 const wrapper = mountComponent ( )
413419
414420 const panel = wrapper . find ( '.panel' )
@@ -422,7 +428,7 @@ describe('SelectionToolbox', () => {
422428 invokeExtensions : vi . fn ( ( ) => [ ] )
423429 } as any )
424430
425- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
431+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
426432 const wrapper = mountComponent ( )
427433
428434 const panel = wrapper . find ( '.panel' )
@@ -439,7 +445,7 @@ describe('SelectionToolbox', () => {
439445 invokeExtensions : vi . fn ( ( ) => [ ] )
440446 } as any )
441447
442- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
448+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
443449 const wrapper = mountComponent ( )
444450
445451 const panel = wrapper . find ( '.panel' )
@@ -461,7 +467,7 @@ describe('SelectionToolbox', () => {
461467 invokeExtensions : vi . fn ( ( ) => [ ] )
462468 } as any )
463469
464- canvasStore . selectedItems = [ { type : 'TestNode' } ] as any
470+ mockData . selectedItems = [ { type : 'TestNode' } ] as any
465471 const wrapper = mountComponent ( )
466472
467473 const panel = wrapper . find ( '.panel' )
@@ -481,7 +487,7 @@ describe('SelectionToolbox', () => {
481487 } )
482488
483489 it ( 'should hide most buttons when no items selected' , ( ) => {
484- canvasStore . selectedItems = [ ]
490+ mockData . selectedItems = [ ]
485491 const wrapper = mountComponent ( )
486492
487493 expect ( wrapper . find ( '.info-button' ) . exists ( ) ) . toBe ( false )
0 commit comments