@shopware-ag/dive
Version:
Shopware Spatial Framework
628 lines (572 loc) • 19.3 kB
text/typescript
import { DIVEBaseTool } from '../BaseTool';
import type DIVEOrbitControls from '../../controls/OrbitControls';
import type { DIVEScene } from '../../scene/Scene';
import { Vector3, type Intersection, type Object3D } from 'three';
import { type DIVEHoverable } from '../../interface/Hoverable';
import { type DIVEDraggable } from '../../interface/Draggable';
import { RaycasterIntersectObjectMock } from '../../../__mocks__/three';
/**
* @jest-environment jsdom
*/
const mock_Canvas = {
width: 0,
height: 0,
getContext: jest.fn(),
clientWidth: 1000,
clientHeight: 1000,
offsetLeft: 0,
offsetTop: 0,
};
const mockController = {
domElement: mock_Canvas,
object: {
isPerspectiveCamera: true,
type: 'cameraP',
},
} as unknown as DIVEOrbitControls;
const mockScene = {
children: [],
} as unknown as DIVEScene;
const abstractWrapper = class Wrapper extends DIVEBaseTool {
constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
super(scene, controller);
this.name = 'DIVEBaseTool';
}
};
describe('dive/toolbox/DIVEBaseTool', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('should instantiate', () => {
const baseTool = new abstractWrapper(mockScene, mockController);
expect(baseTool).toBeDefined();
});
it('should Activate', () => {
const baseTool = new abstractWrapper(mockScene, mockController);
expect(() => baseTool.Activate()).not.toThrow();
});
it('should Deactivate', () => {
const baseTool = new abstractWrapper(mockScene, mockController);
expect(() => baseTool.Deactivate()).not.toThrow();
});
it('should raycast', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
RaycasterIntersectObjectMock.mockImplementationOnce(() => {
return [
{
object: {
visible: true,
},
} as unknown as Intersection,
];
});
expect(() => toolBox['raycast']()).not.toThrow();
expect(RaycasterIntersectObjectMock).toHaveBeenCalled();
});
it('should raycast with selection of objects', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
const spy = jest
.spyOn(toolBox['_raycaster'], 'intersectObjects')
.mockImplementationOnce(() => {
return [
{
object: {
visible: true,
},
} as unknown as Intersection,
];
});
expect(() => toolBox['raycast']([])).not.toThrow();
expect(spy).toHaveBeenCalled();
});
it('should return correct pointerAnyDown', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(toolBox).toBeDefined();
expect(toolBox['_pointerAnyDown']).toBeDefined();
expect(toolBox['_pointerAnyDown']).toBe(false);
toolBox['_pointerPrimaryDown'] = false;
toolBox['_pointerMiddleDown'] = false;
toolBox['_pointerSecondaryDown'] = false;
expect(toolBox['_pointerAnyDown']).toBe(false);
toolBox['_pointerPrimaryDown'] = true;
toolBox['_pointerMiddleDown'] = false;
toolBox['_pointerSecondaryDown'] = false;
expect(toolBox['_pointerAnyDown']).toBe(true);
toolBox['_pointerPrimaryDown'] = false;
toolBox['_pointerMiddleDown'] = true;
toolBox['_pointerSecondaryDown'] = false;
expect(toolBox['_pointerAnyDown']).toBe(true);
toolBox['_pointerPrimaryDown'] = false;
toolBox['_pointerMiddleDown'] = false;
toolBox['_pointerSecondaryDown'] = true;
expect(toolBox['_pointerAnyDown']).toBe(true);
});
it('should execute onPointerDown correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() =>
toolBox.onPointerDown({ button: 0 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerDown({ button: 1 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerDown({ button: 2 } as PointerEvent),
).not.toThrow();
const spy = jest.spyOn(console, 'warn').mockImplementation();
expect(() =>
toolBox.onPointerDown({ button: 666 } as PointerEvent),
).not.toThrow();
expect(spy).toHaveBeenCalled();
toolBox['_intersects'] = [
{
distance: 1,
point: {
clone() {
return {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3;
},
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid2',
isHoverable: true,
onPointerEnter() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
];
expect(() =>
toolBox.onPointerDown({ button: 0 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerDown({ button: 1 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerDown({ button: 2 } as PointerEvent),
).not.toThrow();
});
it('should execute onPointerMove correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
jest.spyOn(toolBox['_raycaster'], 'setFromCamera').mockImplementation();
const spy = jest.spyOn(toolBox['_raycaster'], 'intersectObjects');
// test with no hit with hovered object before
spy.mockReturnValue([]);
toolBox['_hovered'] = {
uuid: 'uuid',
onPointerLeave() {
return;
},
} as Object3D & DIVEHoverable;
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
// test with no hovered object
spy.mockReturnValue([
{
distance: 1,
point: {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid',
isHoverable: true,
visible: true,
} as Object3D & DIVEHoverable,
},
]);
toolBox['_hovered'] = null;
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
// test with no hovered object with onPointerEnter
spy.mockReturnValue([
{
distance: 1,
point: {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid',
isHoverable: true,
visible: true,
onPointerEnter() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
]);
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
// test with same hovered object
spy.mockReturnValue([
{
distance: 1,
point: {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid',
isHoverable: true,
visible: true,
onPointerOver() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
]);
toolBox['_hovered'] = {
uuid: 'uuid',
visible: true,
onPointerLeave() {
return;
},
} as Object3D & DIVEHoverable;
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
// test with different hovered object
spy.mockReturnValue([
{
distance: 1,
point: new Vector3(1, 1, 1),
object: {
uuid: 'uuid2',
isHoverable: true,
visible: true,
onPointerEnter() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
]);
toolBox['_hovered'] = {
uuid: 'uuid',
visible: true,
onPointerLeave() {
return;
},
} as Object3D & DIVEHoverable;
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
// test with pointer down
toolBox['_pointerPrimaryDown'] = true;
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
// test with pointer down while already dragging
toolBox['_pointerPrimaryDown'] = true;
toolBox['_dragging'] = true;
expect(() =>
toolBox.onPointerMove({
button: 0,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 1,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerMove({
button: 2,
offsetX: 100,
offsetY: 100,
} as PointerEvent),
).not.toThrow();
spy.mockRestore();
});
it('should execute onPointerUp correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() =>
toolBox.onPointerUp({ button: 0 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerUp({ button: 1 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerUp({ button: 2 } as PointerEvent),
).not.toThrow();
toolBox['pointerWasDragged'] = () => {
return true;
};
toolBox['_dragging'] = true;
toolBox['_intersects'] = [
{
distance: 1,
point: {
clone() {
return {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3;
},
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid2',
isHoverable: true,
onPointerEnter() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
];
toolBox['_draggable'] = {
onDragEnd() {
return;
},
} as unknown as Object3D & DIVEDraggable;
expect(() =>
toolBox.onPointerUp({ button: 0 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerUp({ button: 1 } as PointerEvent),
).not.toThrow();
expect(() =>
toolBox.onPointerUp({ button: 2 } as PointerEvent),
).not.toThrow();
});
it('should execute onDragStart correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
toolBox['_draggable'] = {
onDragStart() {
return;
},
} as unknown as Object3D & DIVEDraggable;
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
toolBox['_dragRaycastOnObjects'] = [];
jest.spyOn(
toolBox['_raycaster'],
'intersectObjects',
).mockReturnValueOnce([]);
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
jest.spyOn(
toolBox['_raycaster'],
'intersectObjects',
).mockReturnValueOnce([]);
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
jest.spyOn(
toolBox['_raycaster'],
'intersectObjects',
).mockReturnValueOnce([
{
distance: 1,
point: {
clone() {
return {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3;
},
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid2',
isHoverable: true,
onPointerEnter() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
]);
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
toolBox['_draggable'] = {
onDragStart() {
return;
},
} as unknown as Object3D & DIVEDraggable;
jest.spyOn(
toolBox['_raycaster'],
'intersectObjects',
).mockReturnValueOnce([]);
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
});
it('should execute onDrag correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
toolBox['_dragRaycastOnObjects'] = [];
jest.spyOn(
toolBox['_raycaster'],
'intersectObjects',
).mockReturnValueOnce([]);
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
toolBox['_draggable'] = {
onDrag() {
return;
},
} as unknown as Object3D & DIVEDraggable;
jest.spyOn(
toolBox['_raycaster'],
'intersectObjects',
).mockReturnValueOnce([
{
distance: 1,
point: {
clone() {
return {
x: 1,
y: 1,
z: 1,
} as unknown as Vector3;
},
x: 1,
y: 1,
z: 1,
} as unknown as Vector3,
object: {
uuid: 'uuid2',
isHoverable: true,
onPointerEnter() {
return;
},
} as unknown as Object3D & DIVEHoverable,
},
]);
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
});
it('should execute onCLick correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() => toolBox.onClick({} as PointerEvent)).not.toThrow();
});
it('should execute onDragEnd correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() => toolBox.onDragEnd({} as PointerEvent)).not.toThrow();
});
it('should execute onWheel correctly', () => {
const toolBox = new abstractWrapper(mockScene, mockController);
expect(() => toolBox.onWheel({} as WheelEvent)).not.toThrow();
});
});