@shopware-ag/dive 1.14.0 → 1.15.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "description": "Shopware Spatial Framework",
5
5
  "type": "module",
6
6
  "main": "./build/dive.cjs",
@@ -1,15 +1,11 @@
1
- import { Box3, BoxGeometry, Mesh, MeshBasicMaterial, Object3D, Vector3, type Vector3Like } from "three";
2
- import { type DIVEMoveable } from "../interface/Moveable";
3
- import { type DIVESelectable } from "../interface/Selectable";
4
- import { type DIVESceneObject } from "../types";
1
+ import { BoxGeometry, Mesh, MeshBasicMaterial, Vector3 } from "three";
2
+ import { DIVENode } from "../node/Node";
5
3
  import { DIVECommunication } from "../com/Communication";
4
+ import { type DIVESceneObject } from "../types";
6
5
 
7
- export class DIVEGroup extends Object3D implements DIVESelectable, DIVEMoveable {
6
+ export class DIVEGroup extends DIVENode {
8
7
  readonly isDIVEGroup: true = true;
9
- readonly isSelectable: true = true;
10
- readonly isMoveable: true = true;
11
8
 
12
- private _bb: Box3;
13
9
  private _boxMesh: Mesh;
14
10
 
15
11
  constructor() {
@@ -17,32 +13,11 @@ export class DIVEGroup extends Object3D implements DIVESelectable, DIVEMoveable
17
13
 
18
14
  this.name = 'DIVEGroup';
19
15
 
20
- this._bb = new Box3();
21
-
22
16
  this._boxMesh = new Mesh(new BoxGeometry(0, 0, 0), new MeshBasicMaterial({ color: 0xff0000, wireframe: true }));
23
17
  this._boxMesh.visible = false;
24
18
  this.add(this._boxMesh);
25
19
  }
26
20
 
27
- public SetPosition(position: Vector3Like): void {
28
- this.position.set(position.x, position.y, position.z);
29
- }
30
-
31
- public SetRotation(rotation: Vector3Like): void {
32
- this.rotation.setFromVector3(new Vector3(rotation.x, rotation.y, rotation.z));
33
- }
34
-
35
- public SetScale(scale: Vector3Like): void {
36
- this.scale.set(scale.x, scale.y, scale.z);
37
- }
38
-
39
- public SetVisibility(visible: boolean): void {
40
- this.traverse((child) => {
41
- if (child.uuid === this._boxMesh.uuid) return;
42
- child.visible = visible;
43
- });
44
- }
45
-
46
21
  public SetBoundingBoxVisibility(visible: boolean): void {
47
22
  this._boxMesh.visible = visible;
48
23
  }
@@ -99,28 +74,24 @@ export class DIVEGroup extends Object3D implements DIVESelectable, DIVEMoveable
99
74
  * @returns {Vector3} The new center of the bounding box.
100
75
  */
101
76
  private updateBB(): Vector3 {
102
- this._bb.makeEmpty();
77
+ this._boundingBox.makeEmpty();
103
78
  this.children.forEach((child) => {
104
79
  if (child.uuid === this._boxMesh.uuid) return;
105
- this._bb.expandByObject(child);
80
+ this._boundingBox.expandByObject(child);
106
81
  });
107
82
 
108
- return this._bb.getCenter(new Vector3());
83
+ return this._boundingBox.getCenter(new Vector3());
109
84
  }
110
85
 
111
86
  private updateBoxMesh(): void {
112
- this._boxMesh.geometry = new BoxGeometry(this._bb.max.x - this._bb.min.x, this._bb.max.y - this._bb.min.y, this._bb.max.z - this._bb.min.z);
87
+ this._boxMesh.quaternion.copy(this.quaternion.clone().invert());
88
+ this._boxMesh.scale.set(1 / this.scale.x, 1 / this.scale.y, 1 / this.scale.z);
89
+ this._boxMesh.geometry = new BoxGeometry(this._boundingBox.max.x - this._boundingBox.min.x, this._boundingBox.max.y - this._boundingBox.min.y, this._boundingBox.max.z - this._boundingBox.min.z);
113
90
  }
114
91
 
115
92
  public onMove(): void {
116
- DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
117
- }
118
-
119
- public onSelect(): void {
120
- DIVECommunication.get(this.userData.id)?.PerformAction('SELECT_OBJECT', { id: this.userData.id });
121
- }
122
-
123
- public onDeselect(): void {
124
- DIVECommunication.get(this.userData.id)?.PerformAction('DESELECT_OBJECT', { id: this.userData.id });
93
+ super.onMove();
94
+ this.updateBB();
95
+ this.updateBoxMesh();
125
96
  }
126
97
  }
@@ -1,4 +1,3 @@
1
- import { type GLTF } from "three/examples/jsm/loaders/GLTFLoader";
2
1
  import { DIVECommunication } from "../../com/Communication";
3
2
  import { DIVEGroup } from "../Group";
4
3
 
@@ -31,22 +30,6 @@ describe('dive/group/DIVEGroup', () => {
31
30
  expect(group).toBeDefined();
32
31
  });
33
32
 
34
- it('should set position', () => {
35
- expect(() => group.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
36
- });
37
-
38
- it('should set rotation', () => {
39
- expect(() => group.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
40
- });
41
-
42
- it('should set scale', () => {
43
- expect(() => group.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
44
- });
45
-
46
- it('should set visibility', () => {
47
- expect(() => group.SetVisibility(true)).not.toThrow();
48
- });
49
-
50
33
  it('should set bounding box visibility', () => {
51
34
  expect(() => group.SetBoundingBoxVisibility(true)).not.toThrow();
52
35
  });
@@ -97,4 +80,13 @@ describe('dive/group/DIVEGroup', () => {
97
80
  jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
98
81
  expect(() => group.onDeselect()).not.toThrow();
99
82
  });
83
+
84
+ it('should onMove', () => {
85
+ group.userData.id = 'something';
86
+
87
+ expect(() => group.onMove()).not.toThrow();
88
+
89
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
90
+ expect(() => group.onMove()).not.toThrow();
91
+ });
100
92
  });
@@ -1,11 +1,10 @@
1
- import { Box3, Mesh, MeshStandardMaterial, Object3D, Raycaster, Vector3, Vector3Like } from 'three';
2
- import { DIVESelectable } from '../interface/Selectable';
1
+ import { Mesh, MeshStandardMaterial, Raycaster, Vector3 } from 'three';
3
2
  import { PRODUCT_LAYER_MASK } from '../constant/VisibilityLayerMask';
4
- import { DIVEMoveable } from '../interface/Moveable';
5
3
  import { DIVECommunication } from '../com/Communication';
6
- import type { GLTF, TransformControls } from 'three/examples/jsm/Addons.js';
4
+ import type { GLTF } from 'three/examples/jsm/Addons.js';
7
5
  import { findSceneRecursive } from '../helper/findSceneRecursive/findSceneRecursive';
8
6
  import { type COMMaterial } from '../com/types';
7
+ import { DIVENode } from '../node/Node';
9
8
 
10
9
  /**
11
10
  * A basic model class.
@@ -17,26 +16,12 @@ import { type COMMaterial } from '../com/types';
17
16
  * @module
18
17
  */
19
18
 
20
- export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable {
19
+ export class DIVEModel extends DIVENode {
21
20
  readonly isDIVEModel: true = true;
22
- readonly isSelectable: true = true;
23
- readonly isMoveable: true = true;
24
-
25
- public gizmo: TransformControls | null = null;
26
-
27
- private boundingBox: Box3;
28
21
 
29
22
  private _mesh: Mesh | null = null;
30
23
  private _material: MeshStandardMaterial | null = null;
31
24
 
32
- constructor() {
33
- super();
34
-
35
- this.layers.mask = PRODUCT_LAYER_MASK;
36
-
37
- this.boundingBox = new Box3();
38
- }
39
-
40
25
  public SetModel(gltf: GLTF): void {
41
26
  this.clear();
42
27
 
@@ -45,7 +30,7 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
45
30
  child.receiveShadow = true;
46
31
 
47
32
  child.layers.mask = this.layers.mask;
48
- this.boundingBox.expandByObject(child);
33
+ this._boundingBox.expandByObject(child);
49
34
 
50
35
  // only search for first mesh for now
51
36
  if (!this._mesh && 'isMesh' in child) {
@@ -63,24 +48,6 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
63
48
  this.add(gltf.scene);
64
49
  }
65
50
 
66
- public SetPosition(position: Vector3Like): void {
67
- this.position.set(position.x, position.y, position.z);
68
- }
69
-
70
- public SetRotation(rotation: Vector3Like): void {
71
- this.rotation.setFromVector3(new Vector3(rotation.x, rotation.y, rotation.z));
72
- }
73
-
74
- public SetScale(scale: Vector3Like): void {
75
- this.scale.set(scale.x, scale.y, scale.z);
76
- }
77
-
78
- public SetVisibility(visible: boolean): void {
79
- this.traverse((child) => {
80
- child.visible = visible;
81
- });
82
- }
83
-
84
51
  public SetMaterial(material: Partial<COMMaterial>): void {
85
52
  // if there is no material, create a new one
86
53
  if (!this._material) {
@@ -142,13 +109,8 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
142
109
  }
143
110
  }
144
111
 
145
- public SetToWorldOrigin(): void {
146
- this.position.set(0, 0, 0);
147
- DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
148
- }
149
-
150
112
  public PlaceOnFloor(): void {
151
- this.position.y = -this.boundingBox.min.y * this.scale.y;
113
+ this.position.y = -this._boundingBox.min.y * this.scale.y;
152
114
  DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
153
115
  }
154
116
 
@@ -159,8 +121,8 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
159
121
  }
160
122
 
161
123
  // calculate the bottom center of the bounding box
162
- const bottomY = this.boundingBox.min.y * this.scale.y;
163
- const bbBottomCenter = this.localToWorld(this.boundingBox.getCenter(new Vector3()).multiply(this.scale));
124
+ const bottomY = this._boundingBox.min.y * this.scale.y;
125
+ const bbBottomCenter = this.localToWorld(this._boundingBox.getCenter(new Vector3()).multiply(this.scale));
164
126
  bbBottomCenter.y = bottomY + this.position.y;
165
127
 
166
128
  // set up raycaster and raycast all scene objects (product layer)
@@ -184,16 +146,4 @@ export class DIVEModel extends Object3D implements DIVESelectable, DIVEMoveable
184
146
  DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
185
147
  }
186
148
  }
187
-
188
- public onMove(): void {
189
- DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
190
- }
191
-
192
- public onSelect(): void {
193
- DIVECommunication.get(this.userData.id)?.PerformAction('SELECT_OBJECT', { id: this.userData.id });
194
- }
195
-
196
- public onDeselect(): void {
197
- DIVECommunication.get(this.userData.id)?.PerformAction('DESELECT_OBJECT', { id: this.userData.id });
198
- }
199
149
  }
@@ -214,34 +214,6 @@ describe('dive/model/DIVEModel', () => {
214
214
  expect(() => model.SetModel(gltf)).not.toThrow();
215
215
  });
216
216
 
217
- it('should set position', () => {
218
- expect(() => model.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
219
- });
220
-
221
- it('should set rotation', () => {
222
- expect(() => model.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
223
- });
224
-
225
- it('should set scale', () => {
226
- expect(() => model.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
227
- });
228
-
229
- it('should set visibility', () => {
230
- expect(() => model.SetVisibility(true)).not.toThrow();
231
- });
232
-
233
- it('should set to world origin', () => {
234
- model.userData.id = 'something';
235
-
236
- expect(() => model.SetToWorldOrigin()).not.toThrow();
237
- expect(model.position.x).toBe(0);
238
- expect(model.position.y).toBe(0);
239
- expect(model.position.z).toBe(0);
240
-
241
- jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
242
- expect(() => model.SetToWorldOrigin()).not.toThrow();
243
- });
244
-
245
217
  it('should place on floor', () => {
246
218
  model.userData.id = 'something';
247
219
 
@@ -265,7 +237,7 @@ describe('dive/model/DIVEModel', () => {
265
237
 
266
238
  model.userData.id = 'something';
267
239
  model.position.set(0, 4, 0);
268
- model['boundingBox'] = {
240
+ model['_boundingBox'] = {
269
241
  min: new Vector3(-size.x / 2, -size.y / 2, -size.z / 2),
270
242
  max: new Vector3(size.x / 2, size.y / 2, size.z / 2),
271
243
  getCenter: jest.fn(() => {
@@ -315,33 +287,6 @@ describe('dive/model/DIVEModel', () => {
315
287
 
316
288
  });
317
289
 
318
- it('should onMove', () => {
319
- model.userData.id = 'something';
320
-
321
- expect(() => model.onMove()).not.toThrow();
322
-
323
- jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
324
- expect(() => model.onMove()).not.toThrow();
325
- });
326
-
327
- it('should onSelect', () => {
328
- model.userData.id = 'something';
329
-
330
- expect(() => model.onSelect()).not.toThrow();
331
-
332
- jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
333
- expect(() => model.onSelect()).not.toThrow();
334
- });
335
-
336
- it('should onDeselect', () => {
337
- model.userData.id = 'something';
338
-
339
- expect(() => model.onDeselect()).not.toThrow();
340
-
341
- jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
342
- expect(() => model.onDeselect()).not.toThrow();
343
- });
344
-
345
290
  it('should set material', () => {
346
291
  // apply invalid material should not crash
347
292
  expect(() => model.SetMaterial({} as COMMaterial)).not.toThrow();
@@ -0,0 +1,58 @@
1
+ import { Box3, Object3D, type Vector3Like } from "three";
2
+ import { PRODUCT_LAYER_MASK } from "../constant/VisibilityLayerMask";
3
+ import { DIVECommunication } from "../com/Communication";
4
+
5
+ import { type DIVEMoveable } from "../interface/Moveable";
6
+ import { type DIVESelectable } from "../interface/Selectable";
7
+ import { type TransformControls } from "three/examples/jsm/controls/TransformControls";
8
+
9
+ export class DIVENode extends Object3D implements DIVESelectable, DIVEMoveable {
10
+ readonly isDIVENode: true = true;
11
+ readonly isSelectable: true = true;
12
+ readonly isMoveable: true = true;
13
+
14
+ public gizmo: TransformControls | null = null;
15
+
16
+ protected _boundingBox: Box3;
17
+
18
+ constructor() {
19
+ super();
20
+
21
+ this.layers.mask = PRODUCT_LAYER_MASK;
22
+
23
+ this._boundingBox = new Box3();
24
+ }
25
+
26
+ public SetPosition(position: Vector3Like): void {
27
+ this.position.set(position.x, position.y, position.z);
28
+ }
29
+
30
+ public SetRotation(rotation: Vector3Like): void {
31
+ this.rotation.set(rotation.x, rotation.y, rotation.z);
32
+ }
33
+
34
+ public SetScale(scale: Vector3Like): void {
35
+ this.scale.set(scale.x, scale.y, scale.z);
36
+ }
37
+
38
+ public SetVisibility(visible: boolean): void {
39
+ this.visible = visible;
40
+ }
41
+
42
+ public SetToWorldOrigin(): void {
43
+ this.position.set(0, 0, 0);
44
+ DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
45
+ }
46
+
47
+ public onMove(): void {
48
+ DIVECommunication.get(this.userData.id)?.PerformAction('UPDATE_OBJECT', { id: this.userData.id, position: this.position, rotation: this.rotation, scale: this.scale });
49
+ }
50
+
51
+ public onSelect(): void {
52
+ DIVECommunication.get(this.userData.id)?.PerformAction('SELECT_OBJECT', { id: this.userData.id });
53
+ }
54
+
55
+ public onDeselect(): void {
56
+ DIVECommunication.get(this.userData.id)?.PerformAction('DESELECT_OBJECT', { id: this.userData.id });
57
+ }
58
+ }
@@ -0,0 +1,229 @@
1
+ import { DIVENode } from '../Node';
2
+ import { DIVECommunication } from '../../com/Communication';
3
+ import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
4
+ import { Vector3, Box3, Mesh, Color, Euler } from 'three';
5
+
6
+ const intersectObjectsMock = jest.fn();
7
+
8
+ jest.mock('three', () => {
9
+ return {
10
+ Vector3: jest.fn(function (x: number, y: number, z: number) {
11
+ this.x = x;
12
+ this.y = y;
13
+ this.z = z;
14
+ this.copy = (vec3: Vector3) => {
15
+ this.x = vec3.x;
16
+ this.y = vec3.y;
17
+ this.z = vec3.z;
18
+ return this;
19
+ };
20
+ this.set = (x: number, y: number, z: number) => {
21
+ this.x = x;
22
+ this.y = y;
23
+ this.z = z;
24
+ return this;
25
+ };
26
+ this.multiply = (vec3: Vector3) => {
27
+ this.x *= vec3.x;
28
+ this.y *= vec3.y;
29
+ this.z *= vec3.z;
30
+ return this;
31
+ };
32
+ this.clone = () => {
33
+ return new Vector3(this.x, this.y, this.z);
34
+ };
35
+ this.setY = (y: number) => {
36
+ this.y = y;
37
+ return this;
38
+ }
39
+ this.add = (vec3: Vector3) => {
40
+ this.x += vec3.x;
41
+ this.y += vec3.y;
42
+ this.z += vec3.z;
43
+ return this;
44
+ };
45
+ this.sub = (vec3: Vector3) => {
46
+ this.x -= vec3.x;
47
+ this.y -= vec3.y;
48
+ this.z -= vec3.z;
49
+ return this;
50
+ };
51
+ return this;
52
+ }),
53
+ Euler: jest.fn(function () {
54
+ this.set = jest.fn();
55
+ return this;
56
+ }),
57
+ Object3D: jest.fn(function () {
58
+ this.clear = jest.fn();
59
+ this.color = {};
60
+ this.intensity = 0;
61
+ this.layers = {
62
+ mask: 0,
63
+ };
64
+ this.shadow = {
65
+ radius: 0,
66
+ mapSize: { width: 0, height: 0 },
67
+ bias: 0,
68
+ camera: {
69
+ near: 0,
70
+ far: 0,
71
+ fov: 0,
72
+ },
73
+ }
74
+ this.add = jest.fn();
75
+ this.sub = jest.fn();
76
+ this.children = [{
77
+ visible: true,
78
+ material: {
79
+ color: {},
80
+ },
81
+ }];
82
+ this.userData = {};
83
+ this.position = new Vector3();
84
+ this.rotation = new Euler();
85
+ this.scale = new Vector3(1, 1, 1);
86
+ this.localToWorld = (vec3: Vector3) => {
87
+ return vec3;
88
+ };
89
+ this.mesh = new Mesh();
90
+ this.traverse = jest.fn((callback) => {
91
+ callback(this.children[0])
92
+ });
93
+ return this;
94
+ }),
95
+ Box3: jest.fn(function () {
96
+ this.min = new Vector3(Infinity, Infinity, Infinity);
97
+ this.max = new Vector3(-Infinity, -Infinity, -Infinity);
98
+ this.getCenter = jest.fn(() => {
99
+ return new Vector3(0, 0, 0);
100
+ });
101
+ this.expandByObject = jest.fn();
102
+
103
+ return this;
104
+ }),
105
+ Raycaster: jest.fn(function () {
106
+ this.intersectObjects = intersectObjectsMock;
107
+ this.layers = {
108
+ mask: 0,
109
+ };
110
+ return this;
111
+ }),
112
+ Mesh: jest.fn(function () {
113
+ this.geometry = {
114
+ computeBoundingBox: jest.fn(),
115
+ boundingBox: new Box3(),
116
+ };
117
+ this.material = {};
118
+ this.castShadow = true;
119
+ this.receiveShadow = true;
120
+ this.layers = {
121
+ mask: 0,
122
+ };
123
+ this.updateWorldMatrix = jest.fn();
124
+ this.traverse = jest.fn();
125
+ this.removeFromParent = jest.fn();
126
+ this.localToWorld = (vec3: Vector3) => {
127
+ return vec3;
128
+ };
129
+ return this;
130
+ }),
131
+ MeshStandardMaterial: jest.fn(function () {
132
+ this.color = new Color();
133
+ this.roughness = 1;
134
+ this.roughnessMap = undefined;
135
+ this.metalness = 0;
136
+ this.metalnessMap = undefined;
137
+ return this;
138
+ }),
139
+ Color: jest.fn(function () {
140
+ this.set = jest.fn();
141
+ return this;
142
+ }),
143
+ }
144
+ });
145
+
146
+ jest.mock('../../com/Communication.ts', () => {
147
+ return {
148
+ DIVECommunication: {
149
+ get: jest.fn(() => {
150
+ return {
151
+ PerformAction: jest.fn(),
152
+ }
153
+ }),
154
+ },
155
+ }
156
+ });
157
+
158
+ jest.spyOn(DIVECommunication, 'get').mockReturnValue({ PerformAction: jest.fn() } as unknown as DIVECommunication);
159
+
160
+ let node: DIVENode;
161
+
162
+ describe('dive/node/DIVENode', () => {
163
+ beforeEach(() => {
164
+ node = new DIVENode();
165
+ });
166
+
167
+ afterEach(() => {
168
+ jest.clearAllMocks();
169
+ });
170
+
171
+ it('should instantiate', () => {
172
+ expect(node).toBeDefined();
173
+ });
174
+
175
+ it('should set position', () => {
176
+ expect(() => node.SetPosition({ x: 0, y: 0, z: 0 })).not.toThrow();
177
+ });
178
+
179
+ it('should set rotation', () => {
180
+ expect(() => node.SetRotation({ x: 0, y: 0, z: 0 })).not.toThrow();
181
+ });
182
+
183
+ it('should set scale', () => {
184
+ expect(() => node.SetScale({ x: 1, y: 1, z: 1 })).not.toThrow();
185
+ });
186
+
187
+ it('should set visibility', () => {
188
+ expect(() => node.SetVisibility(true)).not.toThrow();
189
+ });
190
+
191
+ it('should set to world origin', () => {
192
+ node.userData.id = 'something';
193
+
194
+ expect(() => node.SetToWorldOrigin()).not.toThrow();
195
+ expect(node.position.x).toBe(0);
196
+ expect(node.position.y).toBe(0);
197
+ expect(node.position.z).toBe(0);
198
+
199
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
200
+ expect(() => node.SetToWorldOrigin()).not.toThrow();
201
+ });
202
+
203
+ it('should onMove', () => {
204
+ node.userData.id = 'something';
205
+
206
+ expect(() => node.onMove()).not.toThrow();
207
+
208
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
209
+ expect(() => node.onMove()).not.toThrow();
210
+ });
211
+
212
+ it('should onSelect', () => {
213
+ node.userData.id = 'something';
214
+
215
+ expect(() => node.onSelect()).not.toThrow();
216
+
217
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
218
+ expect(() => node.onSelect()).not.toThrow();
219
+ });
220
+
221
+ it('should onDeselect', () => {
222
+ node.userData.id = 'something';
223
+
224
+ expect(() => node.onDeselect()).not.toThrow();
225
+
226
+ jest.spyOn(DIVECommunication, 'get').mockReturnValueOnce(undefined);
227
+ expect(() => node.onDeselect()).not.toThrow();
228
+ });
229
+ });