Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(react-components): added test for few hooks #4767

Merged
merged 4 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions react-components/tests/unit-tests/fixtures/cadModel.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { type CogniteCadModel } from '@cognite/reveal';
import { Mock } from 'moq.ts';
import { Matrix4 } from 'three';
import { It, Mock } from 'moq.ts';
import { Box3, Matrix4, Vector3 } from 'three';

export const cadModelOptions = {
modelId: 123,
revisionId: 456
};

export const nodeBoundingBox = new Box3(new Vector3(1, 1, 1), new Vector3(2, 2, 2));

export const cadMock = new Mock<CogniteCadModel>()
.setup((p) => p.modelId)
.returns(cadModelOptions.modelId)
.setup((p) => p.revisionId)
.returns(cadModelOptions.revisionId)
.setup((p) => p.getModelTransformation())
.returns(new Matrix4())
.setup(async (p) => await p.getBoundingBoxesByNodeIds(It.IsAny()))
.returns(Promise.resolve([nodeBoundingBox]))
.object();
23 changes: 12 additions & 11 deletions react-components/tests/unit-tests/fixtures/cameraManager.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { CameraManager, CameraManagerEventType, CameraState } from '@cognite/reveal';
import { type CameraManager, type CameraManagerEventType, type CameraState } from '@cognite/reveal';
import { remove } from 'lodash';
import { Mock } from 'moq.ts';
import { Vector3 } from 'three';
import { type Box3, type Vector3 } from 'three';

import { vi, Mock as viMock } from 'vitest';
import { vi, type Mock as viMock } from 'vitest';

export const cameraManagerGlobalCameraEvents: Record<
CameraManagerEventType,
viMock<[Vector3, Vector3], void>[]
Array<viMock<[Vector3, Vector3], void>>
> = {
cameraChange: [],
cameraStop: []
};

const cameraManagerGlobalCurrentCameraState: CameraState = {};
export const fitCameraToBoundingBoxMock = vi.fn<[Box3], void>();

export const cameraManagerMock = new Mock<CameraManager>()
.setup((p) => p.on)
Expand All @@ -31,14 +32,14 @@ export const cameraManagerMock = new Mock<CameraManager>()
.returns(({ position, target }) => {
cameraManagerGlobalCurrentCameraState.position = position;
cameraManagerGlobalCurrentCameraState.target = target;
setTimeout(
() =>
cameraManagerGlobalCameraEvents.cameraStop.forEach((callback) =>
callback(position!, target!)
),
50
);
setTimeout(() => {
cameraManagerGlobalCameraEvents.cameraStop.forEach((callback) => {
callback(position!, target!);
});
}, 50);
})
.setup((p) => p.getCameraState())
.returns(cameraManagerGlobalCurrentCameraState as Required<CameraState>)
.setup((p) => p.fitCameraToBoundingBox)
.returns(fitCameraToBoundingBoxMock)
.object();
68 changes: 68 additions & 0 deletions react-components/tests/unit-tests/fixtures/fdmNodeCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Mock } from 'moq.ts';
import { type FdmNodeCache } from '../../../src/components/CacheProvider/FdmNodeCache';
import { type FdmNodeCacheContent } from '../../../src/components/CacheProvider/NodeCacheProvider';
import { type DmsUniqueIdentifier } from '../../../src/data-providers/FdmSDK';
import { type TypedReveal3DModel } from '../../../src/components/Reveal3DResources/types';
import { type Node3D } from '@cognite/sdk';
import {
type FdmCadConnection,
type FdmConnectionWithNode
} from '../../../src/components/CacheProvider/types';

const fdmNodeCacheMock = new Mock<FdmNodeCache>()
.setup((instance) => instance.getAllMappingExternalIds)
.returns(
async (
modelRevisionIds: Array<{ modelId: number; revisionId: number }>,
_fetchViews: boolean
) => {
return new Map(
modelRevisionIds.map(({ modelId, revisionId }) => [
`${modelId}/${revisionId}`,
[
{
connection: {
instance: { space: 'space', externalId: 'id' },
modelId,
revisionId,
treeIndex: 1
} satisfies FdmCadConnection,
cadNode: {
id: 1,
treeIndex: 1,
parentId: 0,
depth: 0,
name: 'node-name',
subtreeSize: 1
} satisfies Node3D
} satisfies FdmConnectionWithNode
]
])
);
}
)
.setup((instance) => instance.getClosestParentDataPromises)
.returns((modelId: number, revisionId: number, treeIndex: number) => {
return {
modelId,
revisionId,
treeIndex,
data: `data-for-${modelId}-${revisionId}-${treeIndex}`,
cadAndFdmNodesPromise: Promise.resolve(undefined),
viewsPromise: Promise.resolve([])
};
})
.setup((instance) => instance.getMappingsForFdmInstances)
.returns(async (fdmAssetExternalIds: DmsUniqueIdentifier[], models: TypedReveal3DModel[]) => {
return models.map((model) => ({
modelId: model.modelId,
revisionId: model.revisionId,
mappings: new Map(fdmAssetExternalIds.map((id) => [JSON.stringify(id), [] as Node3D[]]))
}));
});

const fdmNodeCacheContentMock: FdmNodeCacheContent = {
cache: fdmNodeCacheMock.object()
};

export { fdmNodeCacheContentMock };
2 changes: 1 addition & 1 deletion react-components/tests/unit-tests/fixtures/image360.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Image360Collection } from '@cognite/reveal';
import { type Image360Collection } from '@cognite/reveal';
import { Mock } from 'moq.ts';

export const image360Options = {
Expand Down
2 changes: 1 addition & 1 deletion react-components/tests/unit-tests/fixtures/pointCloud.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CognitePointCloudModel } from '@cognite/reveal';
import { type CognitePointCloudModel } from '@cognite/reveal';
import { Mock } from 'moq.ts';
import { Matrix4 } from 'three';

Expand Down
6 changes: 6 additions & 0 deletions react-components/tests/unit-tests/fixtures/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const domElement = document.createElement('div').appendChild(document.createElem
export const viewerModelsMock = vi.fn<[], CogniteModel[]>();
export const viewerRemoveModelsMock = vi.fn<[CogniteModel], void>();
export const viewerImage360CollectionsMock = vi.fn<[], Image360Collection[]>();
export const fitCameraToVisualSceneBoundingBoxMock = vi.fn<[number?], void>();
export const fitCameraToModelsMock = vi.fn<[CogniteModel[], number?, boolean?], void>();

export const viewerMock = new Mock<Cognite3DViewer>()
.setup((viewer) => {
Expand All @@ -25,4 +27,8 @@ export const viewerMock = new Mock<Cognite3DViewer>()
.returns(viewerRemoveModelsMock)
.setup((p) => p.cameraManager)
.returns(cameraManagerMock)
.setup((p) => p.fitCameraToVisualSceneBoundingBox)
.returns(fitCameraToVisualSceneBoundingBoxMock)
.setup((p) => p.fitCameraToModels)
.returns(fitCameraToModelsMock)
.object();
75 changes: 75 additions & 0 deletions react-components/tests/unit-tests/hooks/use3dModels.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { describe, expect, test, vi, beforeEach, beforeAll, afterAll } from 'vitest';
import { use3dModels } from '../../../src/hooks/use3dModels';
import { CogniteCadModel, type CogniteModel } from '@cognite/reveal';
import { renderHook } from '@testing-library/react';

import { viewerMock, viewerModelsMock } from '../fixtures/viewer';
import { cadMock, cadModelOptions } from '../fixtures/cadModel';
import { Mock } from 'moq.ts';
import { Matrix4 } from 'three';

const mockResourceCount = { reveal3DResourcesCount: 2 };

vi.mock('../../../src/components/RevealCanvas/ViewerContext', () => ({
useReveal: () => viewerMock
}));

vi.mock('../../../src/components/Reveal3DResources/Reveal3DResourcesInfoContext', () => ({
useReveal3DResourcesCount: () => mockResourceCount
}));

describe('use3dModels', () => {
beforeEach(() => {
vi.resetAllMocks();
});

beforeAll(() => {
vi.useFakeTimers();
});

afterAll(() => {
vi.useRealTimers();
});

test('returns models from viewer', () => {
const mockModels: CogniteModel[] = [cadMock, cadMock];
viewerModelsMock.mockReturnValue(mockModels);

const { result } = renderHook(() => use3dModels());

expect(result.current).toEqual(mockModels);
});

test('updates models when viewer or resourceCount changes', () => {
const mockModels: CogniteModel[] = [cadMock, cadMock];
viewerModelsMock.mockReturnValue(mockModels);

const { result, rerender } = renderHook(() => use3dModels());

expect(result.current).toEqual(mockModels);

const newCadModelOptions = {
modelId: 987,
revisionId: 654
};

const newCadMock = new Mock<CogniteCadModel>()
.setup((p) => p.modelId)
.returns(newCadModelOptions.modelId)
.setup((p) => p.revisionId)
.returns(newCadModelOptions.revisionId)
.setup((p) => p.getModelTransformation())
.returns(new Matrix4())
.object();

const newMockModels: CogniteModel[] = [newCadMock, newCadMock];
const newMockResourceCount = { reveal3DResourcesCount: 3 };

viewerModelsMock.mockReturnValue(newMockModels);
mockResourceCount.reveal3DResourcesCount = newMockResourceCount.reveal3DResourcesCount;

rerender();

expect(result.current).toEqual(newMockModels);
});
});
141 changes: 141 additions & 0 deletions react-components/tests/unit-tests/hooks/useCameraNavigation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { describe, expect, test, vi, beforeEach, beforeAll, afterAll } from 'vitest';
import { useCameraNavigation } from '../../../src/hooks/useCameraNavigation';
import { viewerMock, viewerModelsMock } from '../fixtures/viewer';
import { cadMock, nodeBoundingBox } from '../fixtures/cadModel';
import { act, renderHook } from '@testing-library/react';
import { fdmNodeCacheContentMock } from '../fixtures/fdmNodeCache';
import { Vector3 } from 'three';

vi.mock('../../../src/components/RevealCanvas/ViewerContext', () => ({
useReveal: () => viewerMock
}));

vi.mock('../../../src/components/CacheProvider/NodeCacheProvider', () => ({
useFdmNodeCache: () => fdmNodeCacheContentMock
}));

describe('useCameraNavigation', () => {
beforeEach(() => {
vi.resetAllMocks();
viewerMock.cameraManager.setCameraState = vi.fn();
viewerMock.cameraManager.fitCameraToBoundingBox = vi.fn();
});

beforeAll(() => {
vi.useFakeTimers();
});

afterAll(() => {
vi.useRealTimers();
});

test('fitCameraToVisualSceneBoundingBox calls viewer method', () => {
const { result } = renderHook(() => useCameraNavigation());

act(() => {
result.current.fitCameraToVisualSceneBoundingBox(1000);
});

expect(viewerMock.fitCameraToVisualSceneBoundingBox).toHaveBeenCalledWith(1000);
});

test('fitCameraToAllModels calls viewer method with models', () => {
const mockModels = [cadMock, cadMock];
viewerModelsMock.mockReturnValue(mockModels);

const { result } = renderHook(() => useCameraNavigation());

act(() => {
result.current.fitCameraToAllModels(1000);
});

expect(viewerMock.fitCameraToModels).toHaveBeenCalledWith(mockModels, 1000, true);
});

test('fitCameraToModelNodes calls viewer method with bounding box', async () => {
const mockModels = [cadMock, cadMock];
viewerModelsMock.mockReturnValue(mockModels);

const { result } = renderHook(() => useCameraNavigation());
const fitCameraToModelNodesSpy = vi.spyOn(result.current, 'fitCameraToModelNodes');

await act(async () => {
await result.current.fitCameraToModelNodes(456, [1, 2]);
});

expect(fitCameraToModelNodesSpy).toHaveBeenCalledWith(456, [1, 2]);

expect(viewerMock.cameraManager.fitCameraToBoundingBox).toHaveBeenCalledWith(nodeBoundingBox);
});

test('fitCameraToModelNode calls fitCameraToModelNodes with single node', async () => {
const mockModels = [cadMock, cadMock];
viewerModelsMock.mockReturnValue(mockModels);

const { result } = renderHook(() => useCameraNavigation());
const fitCameraToModelNodeSpy = vi.spyOn(result.current, 'fitCameraToModelNode');

await act(async () => {
await result.current.fitCameraToModelNode(456, 1);
});

expect(fitCameraToModelNodeSpy).toHaveBeenCalledWith(456, 1);
});

test('fitCameraToInstances calls fitCameraToModelNodes with node ids', async () => {
const mockModels = [cadMock, cadMock];
viewerModelsMock.mockReturnValue(mockModels);
const mockMappings = {
revisionId: 456,
mappings: new Map([['model1', [{ id: 1 }, { id: 2 }]]])
};

fdmNodeCacheContentMock.cache.getMappingsForFdmInstances = vi
.fn()
.mockResolvedValue([mockMappings]);

const { result } = renderHook(() => useCameraNavigation());

await act(async () => {
await result.current.fitCameraToInstances([{ externalId: 'ext1', space: 'space1' }]);
});

expect(viewerMock.cameraManager.fitCameraToBoundingBox).toHaveBeenCalled();
});

test('fitCameraToInstance calls fitCameraToInstances with single instance', async () => {
const mockModels = [cadMock, cadMock];
const mockMappings = {
revisionId: 456,
mappings: new Map([['model1', [{ id: 1 }]]])
};
viewerModelsMock.mockReturnValue(mockModels);

fdmNodeCacheContentMock.cache.getMappingsForFdmInstances = vi
.fn()
.mockResolvedValue([mockMappings]);

const { result } = renderHook(() => useCameraNavigation());

await act(async () => {
await result.current.fitCameraToInstance('ext1', 'space1');
});

expect(viewerMock.cameraManager.fitCameraToBoundingBox).toHaveBeenCalled();
});

test('fitCameraToState calls viewer method with camera state', () => {
const mockCameraState = {
position: new Vector3(0, 0, 0),
target: new Vector3(1, 1, 1)
};

const { result } = renderHook(() => useCameraNavigation());

act(() => {
result.current.fitCameraToState(mockCameraState);
});

expect(viewerMock.cameraManager.setCameraState).toHaveBeenCalledWith(mockCameraState);
});
});
Loading