@shopware-ag/dive 1.18.5-beta.2 → 1.18.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/build/dive.cjs +3856 -1
  3. package/build/dive.cjs.map +1 -1
  4. package/build/dive.js +24728 -6
  5. package/build/dive.js.map +1 -1
  6. package/build/src/ar/arquicklook/ARQuickLook.d.ts +2 -3
  7. package/build/src/com/Communication.d.ts +1 -4
  8. package/build/src/module/Module.d.ts +8 -0
  9. package/package.json +2 -2
  10. package/src/ar/arquicklook/ARQuickLook.ts +75 -48
  11. package/src/ar/arquicklook/__test__/ARQuickLook.test.ts +45 -80
  12. package/src/ar/sceneviewer/__test__/SceneViewer.test.ts +0 -12
  13. package/src/com/Communication.ts +17 -84
  14. package/src/com/__test__/Communication.test.ts +43 -16
  15. package/src/module/Module.ts +45 -0
  16. package/src/module/__test__/Module.test.ts +54 -0
  17. package/build/AR-B-g0updz.js +0 -1450
  18. package/build/AR-B-g0updz.js.map +0 -1
  19. package/build/AR-BWQebw6-.cjs +0 -153
  20. package/build/AR-BWQebw6-.cjs.map +0 -1
  21. package/build/IO-BgiJzKrU.js +0 -1257
  22. package/build/IO-BgiJzKrU.js.map +0 -1
  23. package/build/IO-CuYml7Y5.cjs +0 -2
  24. package/build/IO-CuYml7Y5.cjs.map +0 -1
  25. package/build/MediaCreator-4zmvmUWH.js +0 -22
  26. package/build/MediaCreator-4zmvmUWH.js.map +0 -1
  27. package/build/MediaCreator-BNxZVYyZ.cjs +0 -2
  28. package/build/MediaCreator-BNxZVYyZ.cjs.map +0 -1
  29. package/build/TextureUtils-CxpuVgwF.js +0 -38
  30. package/build/TextureUtils-CxpuVgwF.js.map +0 -1
  31. package/build/TextureUtils-DNG-yR77.cjs +0 -19
  32. package/build/TextureUtils-DNG-yR77.cjs.map +0 -1
  33. package/build/dive-Mi8g8Khn.js +0 -24852
  34. package/build/dive-Mi8g8Khn.js.map +0 -1
  35. package/build/dive-_-yiZbhn.cjs +0 -3857
  36. package/build/dive-_-yiZbhn.cjs.map +0 -1
@@ -1,8 +1,7 @@
1
1
  import { DIVEScene } from '../../scene/Scene';
2
2
  import { DIVEAROptions } from '../AR';
3
3
  export declare class DIVEARQuickLook {
4
- private static _usdzExporter;
5
4
  static Launch(scene: DIVEScene, options?: DIVEAROptions): Promise<void>;
6
- private static extractModels;
7
- private static launchARFromNode;
5
+ private static launchARQuickLook;
6
+ private static findARQuickLookSrc;
8
7
  }
@@ -34,16 +34,13 @@ export declare class DIVECommunication {
34
34
  private controller;
35
35
  private toolbox;
36
36
  private _mediaGenerator;
37
- private get mediaGenerator();
38
37
  private _io;
39
- private get io();
40
38
  private _ar;
41
- private get ar();
42
39
  private registered;
43
40
  private listeners;
44
41
  constructor(renderer: DIVERenderer, scene: DIVEScene, controls: DIVEOrbitControls, toolbox: DIVEToolbox);
45
42
  DestroyInstance(): boolean;
46
- PerformAction<Action extends keyof Actions>(action: Action, payload: Actions[Action]['PAYLOAD']): Actions[Action]['RETURN'];
43
+ PerformAction<Action extends keyof Actions>(action: Action, payload?: Actions[Action]['PAYLOAD']): Actions[Action]['RETURN'];
47
44
  Subscribe<Action extends keyof Actions>(type: Action, listener: EventListener<Action>): Unsubscribe;
48
45
  private dispatch;
49
46
  private getAllSceneData;
@@ -0,0 +1,8 @@
1
+ export declare class DIVEModule<T> {
2
+ private _path;
3
+ private _ctor;
4
+ constructor(_path: string, _ctor: string);
5
+ private _promise;
6
+ private _instance;
7
+ get(): Promise<T>;
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.18.5-beta.2",
3
+ "version": "1.18.5",
4
4
  "description": "Shopware Spatial Framework",
5
5
  "type": "module",
6
6
  "main": "build/dive.cjs",
@@ -51,7 +51,7 @@
51
51
  "ts-jest": "^29.1.2",
52
52
  "ts-node": "^10.9.2",
53
53
  "tsc": "^2.0.4",
54
- "typescript": "^5.4.5",
54
+ "typescript": "^5.8.2",
55
55
  "typescript-eslint": "^7.7.1",
56
56
  "vite": "^6.2.1",
57
57
  "vite-plugin-dts": "^4.5.3"
@@ -1,66 +1,93 @@
1
- import { Object3D } from 'three';
2
- import { DIVEUSDZExporter } from '../../exporters/usdz/USDZExporter';
3
1
  import { type DIVEScene } from '../../scene/Scene';
4
2
  import { type DIVEAROptions } from '../AR';
5
3
 
6
4
  export class DIVEARQuickLook {
7
- private static _usdzExporter: DIVEUSDZExporter = new DIVEUSDZExporter();
8
-
9
5
  public static Launch(
10
6
  scene: DIVEScene,
11
7
  options?: DIVEAROptions,
12
8
  ): Promise<void> {
13
- // create node to build usdz from
14
- const quickLookScene = new Object3D();
15
-
16
- // extract models from scene
17
- const rootCopy = scene.Root.clone(true);
18
-
19
- quickLookScene.add(...rootCopy.children);
9
+ const url = this.findARQuickLookSrc(scene);
20
10
 
21
11
  // launch ARQuickLook
22
- return this.launchARFromNode(quickLookScene, options);
12
+ return this.launchARQuickLook(url, options);
23
13
  }
24
14
 
25
- private static extractModels(scene: DIVEScene): Object3D[] {
26
- // extract models
27
- return scene.Root.children;
28
- }
29
-
30
- private static launchARFromNode(
31
- node: Object3D,
15
+ private static launchARQuickLook(
16
+ uri: string,
32
17
  options?: DIVEAROptions,
33
18
  ): Promise<void> {
34
- // bundle USDZ
35
- return this._usdzExporter
36
- .parse(node, {
37
- quickLookCompatible: true,
38
- ar: {
39
- anchoring: { type: 'plane' },
40
- planeAnchoring: {
41
- alignment:
42
- options?.arPlacement === 'vertical'
43
- ? 'vertical'
44
- : 'horizontal',
45
- },
46
- },
47
- })
48
- .then((usdz: Uint8Array) => {
49
- // create blob
50
- const blob = new Blob([usdz], { type: 'model/vnd.usdz+zip' });
51
- let url = URL.createObjectURL(blob);
19
+ return new Promise((resolve) => {
20
+ if (options?.arScale === 'fixed') {
21
+ uri = uri.concat('#allowsContentScaling=0');
22
+ }
23
+
24
+ // launch ARQuickLook
25
+ const a = document.createElement('a');
26
+ a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
27
+ a.rel = 'ar';
28
+ a.href = uri;
29
+ a.download = 'scene.usdz';
30
+ resolve();
31
+ a.click();
32
+ });
33
+ }
52
34
 
53
- if (options?.arScale === 'fixed') {
54
- url = url.concat('#allowsContentScaling=0');
55
- }
35
+ private static findARQuickLookSrc(scene: DIVEScene): string {
36
+ let uri: string | null = null;
56
37
 
57
- // launch ARQuickLook
58
- const a = document.createElement('a');
59
- a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
60
- a.rel = 'ar';
61
- a.href = url;
62
- a.download = 'scene.usdz';
63
- a.click();
64
- });
38
+ scene.traverse((object) => {
39
+ if (uri) return;
40
+ if (object.userData.uri) {
41
+ uri = object.userData.uri;
42
+ }
43
+ });
44
+
45
+ if (!uri) {
46
+ throw new Error('No model found in scene');
47
+ }
48
+
49
+ return uri;
65
50
  }
51
+
52
+ // private static extractModels(scene: DIVEScene): Object3D[] {
53
+ // // extract models
54
+ // return scene.Root.children;
55
+ // }
56
+
57
+ // private static launchARFromNode(
58
+ // node: Object3D,
59
+ // options?: DIVEAROptions,
60
+ // ): Promise<void> {
61
+ // // bundle USDZ
62
+ // return this._usdzExporter
63
+ // .parse(node, {
64
+ // quickLookCompatible: true,
65
+ // ar: {
66
+ // anchoring: { type: 'plane' },
67
+ // planeAnchoring: {
68
+ // alignment:
69
+ // options?.arPlacement === 'vertical'
70
+ // ? 'vertical'
71
+ // : 'horizontal',
72
+ // },
73
+ // },
74
+ // })
75
+ // .then((usdz: Uint8Array) => {
76
+ // // create blob
77
+ // const blob = new Blob([usdz], { type: 'model/vnd.usdz+zip' });
78
+ // let url = URL.createObjectURL(blob);
79
+
80
+ // if (options?.arScale === 'fixed') {
81
+ // url = url.concat('#allowsContentScaling=0');
82
+ // }
83
+
84
+ // // launch ARQuickLook
85
+ // const a = document.createElement('a');
86
+ // a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
87
+ // a.rel = 'ar';
88
+ // a.href = url;
89
+ // a.download = 'scene.usdz';
90
+ // a.click();
91
+ // });
92
+ // }
66
93
  }
@@ -1,16 +1,22 @@
1
- import { Object3D } from 'three';
1
+ import { Box3, Color, Euler, Mesh, Object3D, Vector3 } from 'three';
2
2
  import { DIVEScene } from '../../../scene/Scene';
3
3
  import { DIVEAROptions } from '../../AR';
4
4
  import { DIVEARQuickLook } from '../ARQuickLook';
5
5
 
6
- jest.mock('../../../exporters/usdz/USDZExporter', () => {
6
+ jest.mock('../../../scene/Scene', () => {
7
7
  return {
8
- DIVEUSDZExporter: jest.fn().mockImplementation(() => {
9
- return {
10
- parse: jest.fn(() => {
11
- return Promise.resolve(new Uint8Array());
12
- }),
8
+ DIVEScene: jest.fn(function () {
9
+ this.add = jest.fn();
10
+ this.children = [];
11
+ this.Root = {
12
+ children: [],
13
13
  };
14
+ this.traverse = jest.fn((callback) => {
15
+ this.Root.children.forEach((child: Object3D) => {
16
+ callback(child);
17
+ });
18
+ });
19
+ return this;
14
20
  }),
15
21
  };
16
22
  });
@@ -26,10 +32,12 @@ describe('DIVEARQuickLook', () => {
26
32
  mockModels = [
27
33
  new Object3D(),
28
34
  new Object3D(),
35
+ new Object3D(),
29
36
  ];
30
- mockScene = {
31
- Root: new Object3D(),
32
- } as DIVEScene;
37
+ mockModels[1].userData = {
38
+ uri: 'https://example.com',
39
+ };
40
+ mockScene = new DIVEScene();
33
41
  mockOptions = {
34
42
  arPlacement: 'horizontal',
35
43
  arScale: 'auto',
@@ -41,88 +49,45 @@ describe('DIVEARQuickLook', () => {
41
49
  expect(DIVEARQuickLook.Launch).toBeInstanceOf(Function);
42
50
  });
43
51
 
44
- it('should return a promise', () => {
45
- expect(
46
- DIVEARQuickLook.Launch(mockScene, mockOptions),
47
- ).toBeInstanceOf(Promise);
48
- });
49
-
50
- it('should not throw when called without options', () => {
51
- const usdzParseSpy = jest.spyOn(
52
- DIVEARQuickLook['_usdzExporter'],
53
- 'parse',
54
- );
55
-
56
- expect(
57
- async () => await DIVEARQuickLook.Launch(mockScene),
58
- ).not.toThrow();
59
-
60
- expect(usdzParseSpy).toHaveBeenCalled();
61
- });
62
-
63
- it('should not throw when called with empty scene', () => {
64
- const usdzParseSpy = jest.spyOn(
65
- DIVEARQuickLook['_usdzExporter'],
66
- 'parse',
67
- );
68
-
69
- expect(
70
- async () =>
71
- await DIVEARQuickLook.Launch(mockScene, mockOptions),
72
- ).not.toThrow();
52
+ it('should not throw without options', () => {
53
+ mockScene.Root.children = mockModels;
73
54
 
74
- expect(usdzParseSpy).toHaveBeenCalled();
55
+ expect(() => {
56
+ DIVEARQuickLook.Launch(mockScene);
57
+ }).not.toThrow();
75
58
  });
76
59
 
77
- it('should not throw when called with filled scene', () => {
78
- const usdzParseSpy = jest.spyOn(
79
- DIVEARQuickLook['_usdzExporter'],
80
- 'parse',
81
- );
82
-
60
+ it('should not throw with options', () => {
83
61
  mockScene.Root.children = mockModels;
84
62
 
85
- expect(
86
- async () =>
87
- await DIVEARQuickLook.Launch(mockScene, mockOptions),
88
- ).not.toThrow();
89
-
90
- expect(usdzParseSpy).toHaveBeenCalled();
63
+ expect(() => {
64
+ DIVEARQuickLook.Launch(mockScene, mockOptions);
65
+ }).not.toThrow();
91
66
  });
92
67
 
93
- it('should pass options to exporter', async () => {
94
- const usdzParseSpy = jest.spyOn(
95
- DIVEARQuickLook['_usdzExporter'],
96
- 'parse',
97
- );
98
-
99
- mockOptions.arPlacement = 'vertical';
100
- mockOptions.arScale = 'fixed';
68
+ it('should not throw with alternated options', () => {
69
+ mockScene.Root.children = mockModels;
101
70
 
102
- await DIVEARQuickLook.Launch(mockScene, mockOptions);
71
+ mockOptions = {
72
+ arPlacement: 'vertical',
73
+ arScale: 'fixed',
74
+ } as DIVEAROptions;
103
75
 
104
- expect(usdzParseSpy).toHaveBeenCalledWith(expect.any(Object3D), {
105
- quickLookCompatible: true,
106
- ar: {
107
- anchoring: { type: 'plane' },
108
- planeAnchoring: {
109
- alignment: 'vertical',
110
- },
111
- },
112
- });
76
+ expect(() => {
77
+ DIVEARQuickLook.Launch(mockScene, mockOptions);
78
+ }).not.toThrow();
113
79
  });
114
80
 
115
- it('should reject when USDZExporter fails', async () => {
116
- const usdzParseSpy = jest.spyOn(
117
- DIVEARQuickLook['_usdzExporter'],
118
- 'parse',
119
- );
120
-
121
- usdzParseSpy.mockReturnValueOnce(Promise.reject());
81
+ it('should throw if no url is found', () => {
82
+ mockScene.Root.children = [
83
+ new Object3D(),
84
+ new Object3D(),
85
+ new Object3D(),
86
+ ];
122
87
 
123
- await expect(
124
- DIVEARQuickLook.Launch(mockScene, mockOptions),
125
- ).rejects.toBeUndefined();
88
+ expect(() => {
89
+ DIVEARQuickLook.Launch(mockScene, mockOptions);
90
+ }).toThrow();
126
91
  });
127
92
  });
128
93
  });
@@ -21,18 +21,6 @@ jest.mock('../../../scene/Scene', () => {
21
21
  };
22
22
  });
23
23
 
24
- jest.mock('../../../exporters/usdz/USDZExporter', () => {
25
- return {
26
- DIVEUSDZExporter: jest.fn().mockImplementation(() => {
27
- return {
28
- parse: jest.fn(() => {
29
- return Promise.resolve(new Uint8Array());
30
- }),
31
- };
32
- }),
33
- };
34
- });
35
-
36
24
  URL.createObjectURL = jest.fn(() => 'blob:http://localhost:8080/');
37
25
 
38
26
  describe('DIVESceneViewer', () => {
@@ -2,6 +2,7 @@ import { Actions } from './actions/index.ts';
2
2
  import { generateUUID } from 'three/src/math/MathUtils';
3
3
  import { isSelectTool } from '../toolbox/select/SelectTool.ts';
4
4
  import { merge } from 'lodash';
5
+ import { DIVEModule } from '../module/Module.ts';
5
6
 
6
7
  // type imports
7
8
  import { type Color, type MeshStandardMaterial } from 'three';
@@ -74,80 +75,13 @@ export class DIVECommunication {
74
75
  private controller: DIVEOrbitControls;
75
76
  private toolbox: DIVEToolbox;
76
77
 
77
- private _mediaGenerator: DIVEMediaCreator | null;
78
- private get mediaGenerator(): Promise<DIVEMediaCreator> {
79
- if (!this._mediaGenerator) {
80
- return new Promise((resolve, reject) => {
81
- import('../mediacreator/MediaCreator.ts')
82
- .then((module) => {
83
- const DIVEMediaCreator = module.DIVEMediaCreator;
84
- this._mediaGenerator = new DIVEMediaCreator(
85
- this.renderer,
86
- this.scene,
87
- this.controller,
88
- );
89
- resolve(this._mediaGenerator);
90
- })
91
- .catch((error) => {
92
- console.error(
93
- 'DIVE: Error while lazy-loading IO module:',
94
- error,
95
- );
96
- reject(error);
97
- });
98
- });
99
- }
100
- return Promise.resolve(this._mediaGenerator);
101
- }
102
-
103
- private _io: DIVEIO | null;
104
- private get io(): Promise<DIVEIO> {
105
- if (!this._io) {
106
- return new Promise((resolve, reject) => {
107
- import('../io/IO.ts')
108
- .then((module) => {
109
- const DIVEIO = module.DIVEIO;
110
- this._io = new DIVEIO(this.scene);
111
- resolve(this._io);
112
- })
113
- .catch((error) => {
114
- console.error(
115
- 'DIVE: Error while lazy-loading IO module:',
116
- error,
117
- );
118
- reject(error);
119
- });
120
- });
121
- }
122
- return Promise.resolve(this._io);
123
- }
124
-
125
- private _ar: DIVEAR | null;
126
- private get ar(): Promise<DIVEAR> {
127
- if (!this._ar) {
128
- return new Promise((resolve, reject) => {
129
- import('../ar/AR.ts')
130
- .then((module) => {
131
- const DIVEAR = module.DIVEAR;
132
- this._ar = new DIVEAR(
133
- this.renderer,
134
- this.scene,
135
- this.controller,
136
- );
137
- resolve(this._ar);
138
- })
139
- .catch((error) => {
140
- console.error(
141
- 'DIVE: Error while lazy-loading AR module:',
142
- error,
143
- );
144
- reject(error);
145
- });
146
- });
147
- }
78
+ private _mediaGenerator: DIVEModule<DIVEMediaCreator> = new DIVEModule(
79
+ '../mediacreator/MediaCreator.ts',
80
+ 'DIVEMediaCreator',
81
+ );
82
+ private _io: DIVEModule<DIVEIO> = new DIVEModule('../io/IO.ts', 'DIVEIO');
148
83
 
149
- return Promise.resolve(this._ar);
150
- }
84
+ private _ar: DIVEModule<DIVEAR> = new DIVEModule('../ar/AR.ts', 'DIVEAR');
151
85
 
152
86
  private registered: Map<string, COMEntity> = new Map();
153
87
 
@@ -166,9 +100,6 @@ export class DIVECommunication {
166
100
  this.scene = scene;
167
101
  this.controller = controls;
168
102
  this.toolbox = toolbox;
169
- this._mediaGenerator = null;
170
- this._io = null;
171
- this._ar = null;
172
103
 
173
104
  DIVECommunication.__instances.push(this);
174
105
  }
@@ -184,7 +115,7 @@ export class DIVECommunication {
184
115
 
185
116
  public PerformAction<Action extends keyof Actions>(
186
117
  action: Action,
187
- payload: Actions[Action]['PAYLOAD'],
118
+ payload?: Actions[Action]['PAYLOAD'],
188
119
  ): Actions[Action]['RETURN'] {
189
120
  let returnValue: Actions[Action]['RETURN'] = false;
190
121
 
@@ -353,10 +284,11 @@ export class DIVECommunication {
353
284
  }
354
285
  case 'LAUNCH_AR': {
355
286
  returnValue = new Promise<void>((resolve, reject) => {
356
- this.ar
357
- .then((arModule) => {
287
+ this._ar
288
+ .get()
289
+ .then((ar) => {
358
290
  resolve(
359
- arModule.Launch(
291
+ ar.Launch(
360
292
  payload as Actions['LAUNCH_AR']['PAYLOAD'],
361
293
  ),
362
294
  );
@@ -784,7 +716,7 @@ export class DIVECommunication {
784
716
  target = payload.target;
785
717
  }
786
718
 
787
- return this.mediaGenerator.then((module) => {
719
+ return this._mediaGenerator.get().then((module) => {
788
720
  return module.GenerateMedia(
789
721
  position,
790
722
  target,
@@ -858,9 +790,10 @@ export class DIVECommunication {
858
790
  payload: Actions['EXPORT_SCENE']['PAYLOAD'],
859
791
  ): Actions['EXPORT_SCENE']['RETURN'] {
860
792
  return new Promise<string | null>((resolve, reject) => {
861
- this.io
862
- .then((ioModule) => {
863
- resolve(ioModule.Export(payload.type));
793
+ this._io
794
+ .get()
795
+ .then((io) => {
796
+ resolve(io.Export(payload.type));
864
797
  })
865
798
  .catch(reject);
866
799
  });
@@ -32,36 +32,47 @@ import {
32
32
  type COMLight,
33
33
  type COMModel,
34
34
  type COMPov,
35
- type COMPrimitive,
36
35
  } from '../types';
37
36
  import { type DIVESceneObject } from '../../types';
38
37
 
39
- jest.mock('../../mediacreator/MediaCreator', () => {
38
+ const mockModule: Record<string, any> = {
39
+ get: jest.fn().mockReturnValue(Promise.resolve({})),
40
+ };
41
+ jest.mock('../../module/Module', () => {
40
42
  return {
41
- DIVEMediaCreator: jest.fn(function () {
42
- this.GenerateMedia = jest.fn();
43
+ DIVEModule: jest.fn().mockImplementation(() => {
44
+ return mockModule;
45
+ }),
46
+ };
47
+ });
43
48
 
44
- return this;
49
+ jest.mock('../../mediacreator/MediaCreator', () => {
50
+ return {
51
+ DIVEMediaCreator: jest.fn().mockImplementation(() => {
52
+ return {
53
+ GenerateMedia: jest.fn(),
54
+ };
45
55
  }),
46
56
  };
47
57
  });
48
58
 
49
59
  jest.mock('../../io/IO', () => {
50
60
  return {
51
- DIVEIO: jest.fn(function () {
52
- this.Import = jest.fn();
53
- this.Export = jest.fn();
54
- return this;
61
+ DIVEIO: jest.fn().mockImplementation(() => {
62
+ return {
63
+ Import: jest.fn(),
64
+ Export: jest.fn(),
65
+ };
55
66
  }),
56
67
  };
57
68
  });
58
69
 
59
70
  jest.mock('../../ar/AR', () => {
60
71
  return {
61
- DIVEAR: jest.fn(function () {
62
- this.Launch = jest.fn();
63
-
64
- return this;
72
+ DIVEAR: jest.fn().mockImplementation(() => {
73
+ return {
74
+ Launch: jest.fn(),
75
+ };
65
76
  }),
66
77
  };
67
78
  });
@@ -194,12 +205,14 @@ const mockToolBox = {
194
205
  }),
195
206
  SetGizmoMode: jest.fn(),
196
207
  SetGizmoVisibility: jest.fn(),
208
+ SetGizmoScaleLinked: jest.fn(),
197
209
  } as unknown as DIVEToolbox;
198
210
 
199
211
  let testCom: DIVECommunication;
200
212
 
201
213
  describe('dive/communication/DIVECommunication', () => {
202
214
  beforeEach(() => {
215
+ jest.clearAllMocks();
203
216
  testCom = new DIVECommunication(
204
217
  mockRenderer,
205
218
  mockScene,
@@ -797,6 +810,11 @@ describe('dive/communication/DIVECommunication', () => {
797
810
  expect(visibility).toBe(false);
798
811
  });
799
812
 
813
+ it('should perform action SET_GIZMO_SCALE_LINKED', () => {
814
+ const success = testCom.PerformAction('SET_GIZMO_SCALE_LINKED', true);
815
+ expect(success).toBe(true);
816
+ });
817
+
800
818
  it('should perform action USE_TOOL', () => {
801
819
  let success = testCom.PerformAction('USE_TOOL', { tool: 'select' });
802
820
  expect(success).toBe(true);
@@ -844,7 +862,10 @@ describe('dive/communication/DIVECommunication', () => {
844
862
 
845
863
  it('should perform action GENERATE_MEDIA', async () => {
846
864
  const blobUri = 'blob:http://localhost:3000/1234';
847
- const mediaGeneratorModule = await testCom['mediaGenerator'];
865
+ jest.spyOn(mockModule, 'get').mockResolvedValue({
866
+ GenerateMedia: jest.fn(),
867
+ });
868
+ const mediaGeneratorModule = await testCom['_mediaGenerator'].get();
848
869
 
849
870
  jest.spyOn(mediaGeneratorModule, 'GenerateMedia').mockReturnValue(
850
871
  blobUri,
@@ -962,7 +983,10 @@ describe('dive/communication/DIVECommunication', () => {
962
983
 
963
984
  it('should perform action EXPORT_SCENE', async () => {
964
985
  const url = 'https://example.com';
965
- const ioModule = await testCom['io'];
986
+ jest.spyOn(mockModule, 'get').mockResolvedValue({
987
+ Export: jest.fn(),
988
+ });
989
+ const ioModule = await testCom['_io'].get();
966
990
 
967
991
  jest.spyOn(ioModule, 'Export').mockResolvedValueOnce(url);
968
992
 
@@ -973,7 +997,10 @@ describe('dive/communication/DIVECommunication', () => {
973
997
  });
974
998
 
975
999
  it('should perform action LAUNCH_AR', async () => {
976
- const arModule = await testCom['ar'];
1000
+ jest.spyOn(mockModule, 'get').mockResolvedValue({
1001
+ Launch: jest.fn(),
1002
+ });
1003
+ const arModule = await testCom['_ar'].get();
977
1004
  const arLaunchSpy = jest
978
1005
  .spyOn(arModule, 'Launch')
979
1006
  .mockResolvedValueOnce();