From b4870c13f99425a739b176b13cfdc324e15f9090 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 20 Jan 2026 02:01:41 +0100 Subject: [PATCH] test: remove explicit any types from useLoad3dViewer.test.ts Removed all 5 any types and replaced with proper TypeScript types. Changes: - Replaced any with Partial for mock objects - Used ReturnType for service mocks - Used ReturnType for store mocks - Used Load3d['sceneManager'] etc. for nested manager types - Minimized type assertions to 2 necessary as unknown casts Remaining type assertions: - mockNode: Partial LGraphNode mock (constructor incompatible) - sceneManager: Simplified gridHelper mock (vs 82+ Three.js properties) Both mocks accurately reflect implementation usage patterns. All tests passing (33/33), 0 typecheck errors. Part of #8092 --- src/composables/useLoad3dViewer.test.ts | 172 ++++++++++++++---------- 1 file changed, 103 insertions(+), 69 deletions(-) diff --git a/src/composables/useLoad3dViewer.test.ts b/src/composables/useLoad3dViewer.test.ts index 77a8e50a0f..4abb0a03da 100644 --- a/src/composables/useLoad3dViewer.test.ts +++ b/src/composables/useLoad3dViewer.test.ts @@ -4,6 +4,8 @@ import { nextTick } from 'vue' import { useLoad3dViewer } from '@/composables/useLoad3dViewer' import Load3d from '@/extensions/core/load3d/Load3d' import Load3dUtils from '@/extensions/core/load3d/Load3dUtils' +import type { LGraph } from '@/lib/litegraph/src/LGraph' +import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' import { useToastStore } from '@/platform/updates/common/toastStore' import { useLoad3dService } from '@/services/load3dService' @@ -30,11 +32,11 @@ vi.mock('@/extensions/core/load3d/Load3d', () => ({ })) describe('useLoad3dViewer', () => { - let mockLoad3d: any - let mockSourceLoad3d: any - let mockLoad3dService: any - let mockToastStore: any - let mockNode: any + let mockLoad3d: Partial + let mockSourceLoad3d: Partial + let mockLoad3dService: ReturnType + let mockToastStore: ReturnType + let mockNode: LGraphNode beforeEach(() => { vi.clearAllMocks() @@ -62,9 +64,9 @@ describe('useLoad3dViewer', () => { }, graph: { setDirtyCanvas: vi.fn() - }, + } as Partial as LGraph, widgets: [] - } as any + } as unknown as LGraphNode mockLoad3d = { setBackgroundColor: vi.fn(), @@ -104,17 +106,17 @@ describe('useLoad3dViewer', () => { type: 'color', value: '#282828' }) - }, + } as unknown as Load3d['sceneManager'], lightingManager: { lights: [null, { intensity: 1 }] - }, + } as Partial as Load3d['lightingManager'], cameraManager: { perspectiveCamera: { fov: 75 } - }, + } as Partial as Load3d['cameraManager'], modelManager: { currentUpDirection: 'original', materialMode: 'original' - }, + } as Partial as Load3d['modelManager'], setBackgroundImage: vi.fn().mockResolvedValue(undefined), setBackgroundRenderMode: vi.fn(), forceRender: vi.fn() @@ -128,12 +130,16 @@ describe('useLoad3dViewer', () => { copyLoad3dState: vi.fn().mockResolvedValue(undefined), handleViewportRefresh: vi.fn(), getLoad3d: vi.fn().mockReturnValue(mockSourceLoad3d) - } + } as Partial> as ReturnType< + typeof useLoad3dService + > vi.mocked(useLoad3dService).mockReturnValue(mockLoad3dService) mockToastStore = { addAlert: vi.fn() - } + } as Partial> as ReturnType< + typeof useToastStore + > vi.mocked(useToastStore).mockReturnValue(mockToastStore) }) @@ -160,7 +166,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) expect(Load3d).toHaveBeenCalledWith(containerRef, { width: undefined, @@ -184,16 +190,20 @@ describe('useLoad3dViewer', () => { }) it('should handle background image during initialization', async () => { - mockSourceLoad3d.sceneManager.getCurrentBackgroundInfo.mockReturnValue({ + vi.mocked( + mockSourceLoad3d.sceneManager!.getCurrentBackgroundInfo + ).mockReturnValue({ type: 'image', value: '' }) - mockNode.properties['Scene Config'].backgroundImage = 'test-image.jpg' + ;( + mockNode.properties!['Scene Config'] as Record + ).backgroundImage = 'test-image.jpg' const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) expect(viewer.backgroundImage.value).toBe('test-image.jpg') expect(viewer.hasBackgroundImage.value).toBe(true) @@ -207,7 +217,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) expect(mockToastStore.addAlert).toHaveBeenCalledWith( 'toastMessages.failedToInitializeLoad3dViewer' @@ -220,7 +230,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.backgroundColor.value = '#ff0000' await nextTick() @@ -232,7 +242,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.showGrid.value = false await nextTick() @@ -244,7 +254,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.cameraType.value = 'orthographic' await nextTick() @@ -256,7 +266,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.fov.value = 90 await nextTick() @@ -268,7 +278,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.lightIntensity.value = 2 await nextTick() @@ -280,7 +290,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.backgroundImage.value = 'new-bg.jpg' await nextTick() @@ -293,7 +303,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.upDirection.value = '+y' await nextTick() @@ -305,7 +315,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.materialMode.value = 'wireframe' await nextTick() @@ -314,14 +324,16 @@ describe('useLoad3dViewer', () => { }) it('should handle watcher errors gracefully', async () => { - mockLoad3d.setBackgroundColor.mockImplementationOnce(function () { - throw new Error('Color update failed') - }) + vi.mocked(mockLoad3d.setBackgroundColor!).mockImplementationOnce( + function () { + throw new Error('Color update failed') + } + ) const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.backgroundColor.value = '#ff0000' await nextTick() @@ -337,7 +349,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) await viewer.exportModel('glb') @@ -345,12 +357,14 @@ describe('useLoad3dViewer', () => { }) it('should handle export errors', async () => { - mockLoad3d.exportModel.mockRejectedValueOnce(new Error('Export failed')) + vi.mocked(mockLoad3d.exportModel!).mockRejectedValueOnce( + new Error('Export failed') + ) const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) await viewer.exportModel('glb') @@ -373,7 +387,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.handleResize() @@ -384,7 +398,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.handleMouseEnter() @@ -395,7 +409,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.handleMouseLeave() @@ -408,22 +422,35 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) - - mockNode.properties['Scene Config'].backgroundColor = '#ff0000' - mockNode.properties['Scene Config'].showGrid = false + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) + ;( + mockNode.properties!['Scene Config'] as Record + ).backgroundColor = '#ff0000' + ;( + mockNode.properties!['Scene Config'] as Record + ).showGrid = false viewer.restoreInitialState() - expect(mockNode.properties['Scene Config'].backgroundColor).toBe( - '#282828' - ) - expect(mockNode.properties['Scene Config'].showGrid).toBe(true) - expect(mockNode.properties['Camera Config'].cameraType).toBe( - 'perspective' - ) - expect(mockNode.properties['Camera Config'].fov).toBe(75) - expect(mockNode.properties['Light Config'].intensity).toBe(1) + expect( + (mockNode.properties!['Scene Config'] as Record) + .backgroundColor + ).toBe('#282828') + expect( + (mockNode.properties!['Scene Config'] as Record) + .showGrid + ).toBe(true) + expect( + (mockNode.properties!['Camera Config'] as Record) + .cameraType + ).toBe('perspective') + expect( + (mockNode.properties!['Camera Config'] as Record).fov + ).toBe(75) + expect( + (mockNode.properties!['Light Config'] as Record) + .intensity + ).toBe(1) }) }) @@ -432,7 +459,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.backgroundColor.value = '#ff0000' viewer.showGrid.value = false @@ -440,23 +467,27 @@ describe('useLoad3dViewer', () => { const result = await viewer.applyChanges() expect(result).toBe(true) - expect(mockNode.properties['Scene Config'].backgroundColor).toBe( - '#ff0000' - ) - expect(mockNode.properties['Scene Config'].showGrid).toBe(false) + expect( + (mockNode.properties!['Scene Config'] as Record) + .backgroundColor + ).toBe('#ff0000') + expect( + (mockNode.properties!['Scene Config'] as Record) + .showGrid + ).toBe(false) expect(mockLoad3dService.copyLoad3dState).toHaveBeenCalledWith( mockLoad3d, mockSourceLoad3d ) expect(mockSourceLoad3d.forceRender).toHaveBeenCalled() - expect(mockNode.graph.setDirtyCanvas).toHaveBeenCalledWith(true, true) + expect(mockNode.graph!.setDirtyCanvas).toHaveBeenCalledWith(true, true) }) it('should handle background image during apply', async () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.backgroundImage.value = 'new-bg.jpg' @@ -481,7 +512,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.refreshViewport() @@ -498,7 +529,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) const file = new File([''], 'test.jpg', { type: 'image/jpeg' }) await viewer.handleBackgroundImageUpdate(file) @@ -515,7 +546,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) const file = new File([''], 'test.jpg', { type: 'image/jpeg' }) await viewer.handleBackgroundImageUpdate(file) @@ -527,7 +558,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.backgroundImage.value = 'existing.jpg' viewer.hasBackgroundImage.value = true @@ -546,7 +577,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) const file = new File([''], 'test.jpg', { type: 'image/jpeg' }) await viewer.handleBackgroundImageUpdate(file) @@ -562,7 +593,7 @@ describe('useLoad3dViewer', () => { const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) viewer.cleanup() @@ -580,33 +611,36 @@ describe('useLoad3dViewer', () => { it('should handle missing container ref', async () => { const viewer = useLoad3dViewer(mockNode) - await viewer.initializeViewer(null as any, mockSourceLoad3d) + await viewer.initializeViewer(null!, mockSourceLoad3d as Load3d) expect(Load3d).not.toHaveBeenCalled() }) it('should handle orthographic camera', async () => { - mockSourceLoad3d.getCurrentCameraType.mockReturnValue('orthographic') + vi.mocked(mockSourceLoad3d.getCurrentCameraType!).mockReturnValue( + 'orthographic' + ) mockSourceLoad3d.cameraManager = { perspectiveCamera: { fov: 75 } - } - delete mockNode.properties['Camera Config'].cameraType + } as Partial as Load3d['cameraManager'] + delete (mockNode.properties!['Camera Config'] as Record) + .cameraType const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) expect(viewer.cameraType.value).toBe('orthographic') }) it('should handle missing lights', async () => { - mockSourceLoad3d.lightingManager.lights = [] + mockSourceLoad3d.lightingManager!.lights = [] const viewer = useLoad3dViewer(mockNode) const containerRef = document.createElement('div') - await viewer.initializeViewer(containerRef, mockSourceLoad3d) + await viewer.initializeViewer(containerRef, mockSourceLoad3d as Load3d) expect(viewer.lightIntensity.value).toBe(1) // Default value })