UNPKG

@shopware-ag/dive

Version:

Shopware Spatial Framework

1,025 lines (904 loc) 32.3 kB
import { DIVECommunication } from '../Communication'; import '../types'; import { type Actions } from '../actions'; import '../actions/camera/movecamera'; import '../actions/camera/resetcamera'; import '../actions/camera/setcameralayer'; import '../actions/camera/setcameratransform'; import '../actions/camera/zoomcamera'; import '../actions/media/generatemedia'; import '../actions/object/addobject'; import '../actions/object/deleteobject'; import '../actions/object/getallobjects'; import '../actions/object/getobjects'; import '../actions/object/selectobject'; import '../actions/object/updateobject'; import '../actions/object/model/modelloaded'; import '../actions/object/model/placeonfloor'; import '../actions/scene/getallscenedata'; import '../actions/scene/setbackground'; import '../actions/scene/updatescene'; import '../actions/toolbox/select/setgizmomode'; import '../actions/toolbox/transform/setgizmovisible'; import '../actions/camera/getcameratransform'; import { type DIVEScene } from '../../scene/Scene'; import type DIVEToolbox from '../../toolbox/Toolbox'; import type DIVEOrbitControls from '../../controls/OrbitControls'; import { type DIVERenderer } from '../../renderer/Renderer'; import { type COMGroup, type COMEntity, type COMEntityType, type COMLight, type COMModel, type COMPov, } from '../types'; import { type DIVESceneObject } from '../../types'; const mockModule: Record<string, any> = { get: jest.fn().mockReturnValue(Promise.resolve({})), }; jest.mock('../../module/Module', () => { return { DIVEModule: jest.fn().mockImplementation(() => { return mockModule; }), }; }); jest.mock('../../mediacreator/MediaCreator', () => { return { DIVEMediaCreator: jest.fn().mockImplementation(() => { return { GenerateMedia: jest.fn(), }; }), }; }); jest.mock('../../io/IO', () => { return { DIVEIO: jest.fn().mockImplementation(() => { return { Import: jest.fn(), Export: jest.fn(), }; }), }; }); jest.mock('../../ar/AR', () => { return { DIVEAR: jest.fn().mockImplementation(() => { return { Launch: jest.fn(), }; }), }; }); jest.mock('../../toolbox/select/SelectTool', () => { return { isSelectTool: jest.fn().mockReturnValue(true), DIVESelectTool: jest.fn().mockImplementation(() => { return { AttachGizmo: jest.fn(), DetachGizmo: jest.fn(), }; }), }; }); const mockRenderer = { render: jest.fn(), OnResize: jest.fn(), StartRenderer: jest.fn(), } as unknown as DIVERenderer; const mockScene = { SetBackground: jest.fn(), AddSceneObject: jest.fn(), UpdateSceneObject: jest.fn(), DeleteSceneObject: jest.fn(), PlaceOnFloor: jest.fn(), GetSceneObject: jest.fn().mockReturnValue({ attach: jest.fn(), DropIt: jest.fn(), }), background: { getHexString: jest.fn().mockReturnValue('ffffff'), }, Root: { attach: jest.fn(), }, Floor: { isFloor: true, visible: true, material: { color: { getHexString: jest.fn().mockReturnValue('ffffff'), }, }, SetVisibility: jest.fn(), SetColor: jest.fn(), }, Grid: { SetVisibility: jest.fn(), }, ComputeSceneBB: jest.fn(), } as unknown as DIVEScene; const mockController = { enableDamping: true, dampingFactor: 0.25, enableZoom: true, enablePan: true, minPolarAngle: 0, maxPolarAngle: Math.PI, minDistance: 0, maxDistance: Infinity, rotateSpeed: 0.5, panSpeed: 0.5, zoomSpeed: 0.5, keyPanSpeed: 0.5, screenSpacePanning: true, autoRotate: false, autoRotateSpeed: 2.0, enableKeys: true, keys: { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40, }, mouseButtons: { LEFT: 0, MIDDLE: 1, RIGHT: 2, }, target: { x: 4, y: 5, z: 6, set: jest.fn(), clone: jest.fn().mockReturnValue({ x: 4, y: 5, z: 6 }), copy: jest.fn(), }, update: jest.fn(), dispose: jest.fn(), ZoomIn: jest.fn(), ZoomOut: jest.fn(), object: { position: { x: 1, y: 2, z: 3, clone: jest.fn().mockReturnValue({ x: 1, y: 2, z: 3 }), copy: jest.fn(), }, quaternion: { x: 1, y: 2, z: 3, w: 4, clone: jest.fn().mockReturnValue({ x: 1, y: 2, z: 3, w: 4 }), copy: jest.fn(), }, SetCameraLayer: jest.fn(), OnResize: jest.fn(), layers: { mask: 1, }, }, MoveTo: jest.fn(), RevertLast: jest.fn(), ComputeEncompassingView: jest.fn().mockReturnValue({ position: { x: 1, y: 2, z: 3 }, target: { x: 4, y: 5, z: 6 }, }), } as unknown as DIVEOrbitControls; const mockToolBox = { UseTool: jest.fn(), GetActiveTool: jest.fn().mockReturnValue({ AttachGizmo: jest.fn(), DetachGizmo: jest.fn(), }), SetGizmoMode: jest.fn(), SetGizmoVisibility: jest.fn(), SetGizmoScaleLinked: jest.fn(), } as unknown as DIVEToolbox; let testCom: DIVECommunication; describe('dive/communication/DIVECommunication', () => { beforeEach(() => { jest.clearAllMocks(); testCom = new DIVECommunication( mockRenderer, mockScene, mockController, mockToolBox, ); }); afterEach(() => { testCom.DestroyInstance(); jest.clearAllMocks(); }); it('should instantiate', () => { expect(testCom).toBeDefined(); expect(DIVECommunication['__instances']).toHaveLength(1); }); it('should get instance', () => { expect(testCom).toBeDefined(); expect(DIVECommunication.get(testCom.id)).toBeDefined(); testCom.PerformAction('ADD_OBJECT', { id: 'someID', } as COMModel); expect(DIVECommunication.get('someID')).toBeDefined(); }); it('should destroy instance', () => { expect(testCom).toBeDefined(); testCom.DestroyInstance(); expect(DIVECommunication['__instances']).toBeDefined(); expect(DIVECommunication['__instances']).toHaveLength(0); }); it('should subscribe, listen and unsubscribe from action', () => { const listener = jest.fn(); const unsub = testCom.Subscribe('GET_ALL_OBJECTS', listener); expect(unsub).toBeDefined(); expect(unsub).toBeInstanceOf(Function); const objects0 = testCom.PerformAction('GET_ALL_OBJECTS', new Map()); expect(objects0).toBeDefined(); expect(objects0.size).toBeDefined(); expect(objects0.size).toBe(0); unsub(); testCom.PerformAction('GET_ALL_OBJECTS', new Map()); expect(listener).toHaveBeenCalledTimes(1); }); it('should not unsubscribe twice', () => { const unsub = testCom.Subscribe('GET_ALL_OBJECTS', () => {}); expect(unsub()).toBe(true); expect(unsub()).toBe(false); }); it('should not unsubscribe if listener does not exist anymore', () => { const unsub = testCom.Subscribe('GET_ALL_OBJECTS', () => {}); testCom['listeners'].clear(); expect(unsub()).toBe(false); }); it('should tigger onChange callback', () => { const payload = { name: 'name', entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight; expect(() => testCom.PerformAction('ADD_OBJECT', payload), ).not.toThrow(); }); it('should perform action START_RENDER', () => { const success = testCom.PerformAction('START_RENDER'); expect(mockRenderer.StartRenderer).toHaveBeenCalledTimes(1); expect(success).toBe(true); }); it('should perform action ADD_OBJECT', () => { const payload = { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight; const success = testCom.PerformAction('ADD_OBJECT', payload); expect(mockScene.AddSceneObject).toHaveBeenCalledTimes(1); expect(success).toBe(true); }); it('should not perform action ADD_OBJECT with same object', () => { const payload = { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight; expect(testCom.PerformAction('ADD_OBJECT', payload)).toBe(true); expect(testCom.PerformAction('ADD_OBJECT', payload)).toBe(false); expect(mockScene.AddSceneObject).toHaveBeenCalledTimes(1); }); it('should perform action UPDATE_OBJECT with existing oject', () => { const payload = { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight; testCom.PerformAction('ADD_OBJECT', payload); const successUpdate = testCom.PerformAction('UPDATE_OBJECT', payload); expect(mockScene.UpdateSceneObject).toHaveBeenCalledTimes(1); expect(successUpdate).toBe(true); }); it('should perform action UPDATE_OBJECT without existing oject', () => { const payload = { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight; const successUpdate = testCom.PerformAction('UPDATE_OBJECT', payload); expect(mockScene.UpdateSceneObject).toHaveBeenCalledTimes(0); expect(successUpdate).toBe(false); }); it('should perform action DELETE_OBJECT with existing object', () => { const payload = { entityType: 'group', id: 'group00', } as COMGroup; testCom.PerformAction('ADD_OBJECT', payload); // additionally add a child to the group testCom.PerformAction('ADD_OBJECT', { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', parentId: 'group00', } as COMLight); // and one child that has NO parent testCom.PerformAction('ADD_OBJECT', { entityType: 'light', id: 'ambient01', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight); // and one child that has A DIFFERENT parent testCom.PerformAction('ADD_OBJECT', { entityType: 'light', id: 'ambient02', type: 'ambient', intensity: 0.5, color: 'white', parentId: 'group01', } as COMLight); const successDelete = testCom.PerformAction('DELETE_OBJECT', payload); expect(mockScene.DeleteSceneObject).toHaveBeenCalledTimes(1); expect(successDelete).toBe(true); }); it('should perform action DELETE_OBJECT without existing object', () => { const payload = { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight; const successDelete = testCom.PerformAction('DELETE_OBJECT', payload); expect(mockScene.DeleteSceneObject).toHaveBeenCalledTimes(0); expect(successDelete).toBe(false); }); it('should perform action SET_BACKGROUND', () => { const payload = { color: 'white', }; const successSet = testCom.PerformAction('SET_BACKGROUND', payload); expect(mockScene.SetBackground).toHaveBeenCalledTimes(1); expect(successSet).toBe(true); }); it('should perform action DROP_IT with existing model', () => { const payload = { entityType: 'model', id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', } as COMModel; testCom.PerformAction('ADD_OBJECT', payload); const placeSpy = jest.spyOn(mockScene, 'GetSceneObject'); const successPlace = testCom.PerformAction('DROP_IT', payload); expect(successPlace).toBe(true); expect(placeSpy).toHaveBeenCalledTimes(1); }); it('should perform action DROP_IT without existing model', () => { const payload = { entityType: 'model', id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', }; const placeSpy = jest.spyOn(mockScene, 'GetSceneObject'); const successPlace = testCom.PerformAction('DROP_IT', payload); expect(successPlace).toBe(false); expect(placeSpy).toHaveBeenCalledTimes(0); }); it('should perform action PLACE_ON_FLOOR with existing model', () => { const payload = { entityType: 'model', id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', } as COMModel; testCom.PerformAction('ADD_OBJECT', payload); const placeSpy = jest.spyOn(mockScene, 'PlaceOnFloor'); const successPlace = testCom.PerformAction('PLACE_ON_FLOOR', payload); expect(successPlace).toBe(true); expect(placeSpy).toHaveBeenCalledTimes(1); }); it('should perform action PLACE_ON_FLOOR without existing model', () => { const payload = { entityType: 'model' as COMEntityType, id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', }; const placeSpy = jest.spyOn(mockScene, 'PlaceOnFloor'); const successPlace = testCom.PerformAction('PLACE_ON_FLOOR', payload); expect(successPlace).toBe(false); expect(placeSpy).toHaveBeenCalledTimes(0); }); it('should perform action GET_ALL_OBJECTS', () => { const payload = { entityType: 'model', id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', } as COMModel; const objects0 = testCom.PerformAction('GET_ALL_OBJECTS', new Map()); expect(objects0).toBeDefined(); expect(objects0.size).toBeDefined(); expect(objects0.size).toBe(0); testCom.PerformAction('ADD_OBJECT', payload); const objects1 = testCom.PerformAction('GET_ALL_OBJECTS', new Map()); expect(objects1).toBeDefined(); expect(objects1.size).toBeDefined(); expect(objects1.size).toBe(1); }); it('should perform action MOVE_CAMERA', () => { const payload = { position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, duration: 1000, locked: true, }; const successSet = testCom.PerformAction('MOVE_CAMERA', payload); const moveToSpy = jest.spyOn(mockController, 'MoveTo'); expect(moveToSpy).toHaveBeenCalledTimes(1); expect(successSet).toBe(true); moveToSpy.mockClear(); testCom.PerformAction('ADD_OBJECT', { entityType: 'pov', id: 'pov', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov); const payloadId = { id: 'pov', locked: true, duration: 1000, }; const successSet1 = testCom.PerformAction('MOVE_CAMERA', payloadId); expect(moveToSpy).toHaveBeenCalledTimes(1); expect(successSet1).toBe(true); }); it('should perform action RESET_CAMERA', () => { const payload = { duration: 1000, }; const successSet = testCom.PerformAction('RESET_CAMERA', payload); expect(mockController.RevertLast).toHaveBeenCalledTimes(1); expect(successSet).toBe(true); }); it('should perform action COMPUTE_ENCOMPASSING_VIEW', () => { const payload = {}; const transform = testCom.PerformAction( 'COMPUTE_ENCOMPASSING_VIEW', payload, ); expect(transform).toStrictEqual({ position: { x: 1, y: 2, z: 3 }, target: { x: 4, y: 5, z: 6 }, }); expect(payload).toStrictEqual({ position: { x: 1, y: 2, z: 3 }, target: { x: 4, y: 5, z: 6 }, }); }); it('should perform action GET_ALL_SCENE_DATA', () => { testCom.PerformAction('ADD_OBJECT', { entityType: 'pov', id: 'pov', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov); testCom.PerformAction('ADD_OBJECT', { entityType: 'model', id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', } as COMModel); testCom.PerformAction('ADD_OBJECT', { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', } as COMLight); testCom.PerformAction('ADD_OBJECT', { entityType: 'group', id: 'group1', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, parentId: null, } as COMGroup); const success = testCom.PerformAction('GET_ALL_SCENE_DATA', {}); expect(success).toStrictEqual({ backgroundColor: '#ffffff', cameras: [ { entityType: 'pov', id: 'pov', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, parentId: null, }, ], floorColor: '#ffffff', floorEnabled: true, lights: [ { entityType: 'light', id: 'ambient00', type: 'ambient', intensity: 0.5, color: 'white', parentId: null, }, ], mediaItem: null, name: undefined, objects: [ { entityType: 'model', id: 'model', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, parentId: null, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', }, ], primitives: [], spotmarks: [], userCamera: { position: { x: 1, y: 2, z: 3 }, target: { x: 4, y: 5, z: 6 }, }, groups: [ { entityType: 'group', id: 'group1', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, parentId: null, }, ], }); }); it('should perform action GET_OBJECTS', () => { const mock0 = { entityType: 'pov', id: 'test0', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov; testCom.PerformAction('ADD_OBJECT', mock0); const mock1 = { entityType: 'pov', id: 'test1', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov; testCom.PerformAction('ADD_OBJECT', mock1); const successWithoutIds = testCom.PerformAction('GET_OBJECTS', { ids: [], }); expect(Array.from(successWithoutIds.values())).toStrictEqual([]); const successWithIds = testCom.PerformAction('GET_OBJECTS', { ids: ['test1'], }); expect(Array.from(successWithIds.values())).toStrictEqual([ { entityType: 'pov', id: 'test1', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, parentId: null, }, ]); }); it('should perform action SELECT_OBJECT', () => { const success0 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0', }); expect(success0).toBe(false); const mock0 = { entityType: 'pov', id: 'test0', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov; testCom.PerformAction('ADD_OBJECT', mock0); jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce(undefined); const success1 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0', }); expect(success1).toBe(false); jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce( {} as unknown as DIVESceneObject, ); const success2 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0', }); expect(success2).toBe(false); jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true, } as unknown as DIVESceneObject); const success3 = testCom.PerformAction('SELECT_OBJECT', { id: 'test0', }); expect(success3).toBe(true); }); it('should perform action DESELECT_OBJECT', () => { const success0 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0', }); expect(success0).toBe(false); const mock0 = { entityType: 'pov', id: 'test0', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov; testCom.PerformAction('ADD_OBJECT', mock0); jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce(undefined); const success1 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0', }); expect(success1).toBe(false); jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce( {} as unknown as DIVESceneObject, ); const success2 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0', }); expect(success2).toBe(false); jest.spyOn(mockScene, 'GetSceneObject').mockReturnValueOnce({ isSelectable: true, } as unknown as DIVESceneObject); const success3 = testCom.PerformAction('DESELECT_OBJECT', { id: 'test0', }); expect(success3).toBe(true); }); it('should perform action SET_CAMERA_TRANSFORM', () => { const success = testCom.PerformAction('SET_CAMERA_TRANSFORM', { position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, }); expect(success).toBe(true); }); it('should perform action GET_CAMERA_TRANSFORM', () => { const success = testCom.PerformAction('GET_CAMERA_TRANSFORM', {}); expect(success).toStrictEqual({ position: { x: 1, y: 2, z: 3 }, target: { x: 4, y: 5, z: 6 }, }); }); it('should perform action SET_CAMERA_LAYER', () => { const success = testCom.PerformAction('SET_CAMERA_LAYER', { layer: 'EDITOR', }); expect(success).toBe(true); }); it('should perform action ZOOM_CAMERA', () => { const success0 = testCom.PerformAction('ZOOM_CAMERA', { direction: 'IN', by: 10, }); expect(success0).toBe(true); const success1 = testCom.PerformAction('ZOOM_CAMERA', { direction: 'OUT', by: 10, }); expect(success1).toBe(true); }); it('should perform action SET_GIZMO_MODE', () => { const success = testCom.PerformAction('SET_GIZMO_MODE', { mode: 'translate', }); expect(success).toBe(true); }); it('should perform action SET_GIZMO_VISIBILITY', () => { let visibility = testCom.PerformAction('SET_GIZMO_VISIBILITY', true); expect(visibility).toBe(true); visibility = testCom.PerformAction('SET_GIZMO_VISIBILITY', false); expect(visibility).toBe(false); }); it('should perform action SET_GIZMO_SCALE_LINKED', () => { const success = testCom.PerformAction('SET_GIZMO_SCALE_LINKED', true); expect(success).toBe(true); }); it('should perform action USE_TOOL', () => { let success = testCom.PerformAction('USE_TOOL', { tool: 'select' }); expect(success).toBe(true); success = testCom.PerformAction('USE_TOOL', { tool: 'none' }); expect(success).toBe(true); }); it('should perform action MODEL_LOADED', () => { const payload = { entityType: 'model', id: 'modelID', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, scale: { x: 0.01, y: 0.01, z: 0.01 }, uri: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb', } as COMModel; testCom.PerformAction('ADD_OBJECT', payload); const success = testCom.PerformAction('MODEL_LOADED', { id: 'modelID', }); expect(success).toBe(true); }); it('should perform action UPDATE_SCENE', () => { const success0 = testCom.PerformAction('UPDATE_SCENE', { name: 'scene name', backgroundColor: 'ffffff', floorEnabled: true, floorColor: 'ffffff', gridEnabled: true, }); expect(success0).toBe(true); const success1 = testCom.PerformAction('UPDATE_SCENE', { name: undefined, backgroundColor: undefined, floorEnabled: undefined, floorColor: undefined, gridEnabled: undefined, }); expect(success1).toBe(true); }); it('should perform action GENERATE_MEDIA', async () => { const blobUri = 'blob:http://localhost:3000/1234'; jest.spyOn(mockModule, 'get').mockResolvedValue({ GenerateMedia: jest.fn(), }); const mediaGeneratorModule = await testCom['_mediaGenerator'].get(); jest.spyOn(mediaGeneratorModule, 'GenerateMedia').mockReturnValue( blobUri, ); const mock1 = { entityType: 'pov', id: 'test1', position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, } as COMPov; testCom.PerformAction('ADD_OBJECT', mock1); const success0 = await testCom.PerformAction('GENERATE_MEDIA', { id: 'test1', width: 800, height: 600, }); expect(success0).toBe(blobUri); const success1 = await testCom.PerformAction('GENERATE_MEDIA', { position: { x: 0, y: 0, z: 0 }, target: { x: 0, y: 0, z: 0 }, width: 800, height: 600, }); expect(success1).toBe(blobUri); jest.restoreAllMocks(); }); it('should perform action SET_PARENT', () => { const object = { id: 'object', } as COMEntity; testCom.PerformAction('ADD_OBJECT', object); const objectNotRegistered = { id: 'objectNotRegistered', } as COMEntity; const parent0 = { id: 'parent0', } as COMEntity; testCom.PerformAction('ADD_OBJECT', parent0); const parent1 = { id: 'parent1', } as COMEntity; testCom.PerformAction('ADD_OBJECT', parent1); const parentNotRegistered = { id: 'parentNotRegistered', } as COMEntity; const attachNotRegisteredObject = testCom.PerformAction('SET_PARENT', { object: objectNotRegistered, parent: null, }); expect(attachNotRegisteredObject).toBe(false); jest.spyOn(mockScene, 'GetSceneObject').mockImplementationOnce(() => { return undefined; }); const attachNonSceneObject = testCom.PerformAction('SET_PARENT', { object: object, parent: null, }); expect(attachNonSceneObject).toBe(false); const attachToNull = testCom.PerformAction('SET_PARENT', { object: object, parent: null, }); expect(attachToNull).toBe(true); const attachToItself = testCom.PerformAction('SET_PARENT', { object: object, parent: object, }); expect(attachToItself).toBe(false); const attachToNotRegsiteredParent = testCom.PerformAction( 'SET_PARENT', { object: object, parent: parentNotRegistered, }, ); expect(attachToNotRegsiteredParent).toBe(true); jest.spyOn(mockScene, 'GetSceneObject') .mockImplementationOnce(() => { return { DropIt: jest.fn(), attach: jest.fn(), } as unknown as DIVESceneObject; }) .mockImplementationOnce(() => { return undefined; }); const attachtoNonSceneParent = testCom.PerformAction('SET_PARENT', { object: object, parent: parent1, }); expect(attachtoNonSceneParent).toBe(true); const attachToValidParent = testCom.PerformAction('SET_PARENT', { object: object, parent: parent1, }); expect(attachToValidParent).toBe(true); }); it('should perform action EXPORT_SCENE', async () => { const url = 'https://example.com'; jest.spyOn(mockModule, 'get').mockResolvedValue({ Export: jest.fn(), }); const ioModule = await testCom['_io'].get(); jest.spyOn(ioModule, 'Export').mockResolvedValueOnce(url); const result = await testCom.PerformAction('EXPORT_SCENE', { type: 'glb', }); expect(result).toBe(url); }); it('should perform action LAUNCH_AR', async () => { jest.spyOn(mockModule, 'get').mockResolvedValue({ Launch: jest.fn(), }); const arModule = await testCom['_ar'].get(); const arLaunchSpy = jest .spyOn(arModule, 'Launch') .mockResolvedValueOnce(); const result = await testCom.PerformAction('LAUNCH_AR', undefined); expect(arLaunchSpy).toHaveBeenCalledTimes(1); }); it('should warn of action is of invalid type ', () => { jest.spyOn(console, 'warn').mockImplementationOnce(() => {}); testCom.PerformAction('INVALID_ACTION' as keyof Actions, {}); expect(console.warn).toHaveBeenCalledTimes(1); }); });