-
Notifications
You must be signed in to change notification settings - Fork 22
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) Unit test for UndoManager #5028
Changes from all commits
937bde5
a5e27b0
01ba643
12360da
418d101
15f9758
590c73f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/*! | ||
* Copyright 2024 Cognite AS | ||
*/ | ||
|
||
import { beforeEach, describe, expect, test } from 'vitest'; | ||
import { Changes } from '../domainObjectsHelpers/Changes'; | ||
import { UndoManager } from './UndoManager'; | ||
import { MeasureBoxDomainObject } from '../../concrete/measurements/MeasureBoxDomainObject'; | ||
import { PrimitiveType } from '../utilities/primitives/PrimitiveType'; | ||
import { expectEqualVector3 } from '../../../../tests/tests-utilities/primitives/primitiveTestUtil'; | ||
import { type BoxDomainObject } from '../../concrete/primitives/box/BoxDomainObject'; | ||
import { RevealRenderTarget } from '../renderTarget/RevealRenderTarget'; | ||
import { type RootDomainObject } from '../domainObjects/RootDomainObject'; | ||
import { Box } from '../utilities/primitives/Box'; | ||
import { viewerMock } from '../../../../tests/tests-utilities/fixtures/viewer'; | ||
import { sdkMock } from '../../../../tests/tests-utilities/fixtures/sdk'; | ||
|
||
describe('UndoManager', () => { | ||
let renderTarget: RevealRenderTarget; | ||
let root: RootDomainObject; | ||
let manager: UndoManager; | ||
beforeEach(() => { | ||
renderTarget = createRenderTargetMock(); | ||
root = renderTarget.rootDomainObject; | ||
manager = new UndoManager(); | ||
}); | ||
|
||
test('Should updated the state of the UndoManager', () => { | ||
const domainObject = createBoxDomainObject(); | ||
root.addChildInteractive(domainObject); | ||
|
||
// Change name | ||
const transaction = domainObject.createTransaction(Changes.active); // Just fake a change | ||
expect(manager.canUndo).toBe(false); | ||
expect(manager.addTransaction(transaction)).toBe(true); | ||
|
||
// Undo | ||
expect(manager.hasUniqueId(domainObject.uniqueId)).toBe(true); | ||
expect(manager.canUndo).toBe(true); | ||
manager.undo(renderTarget); | ||
expect(manager.hasUniqueId(domainObject.uniqueId)).toBe(false); | ||
expect(manager.canUndo).toBe(false); | ||
}); | ||
|
||
test('Should undo geometry and name change', () => { | ||
const domainObject = createBoxDomainObject(); | ||
root.addChildInteractive(domainObject); | ||
const oldBox = new Box().copy(domainObject.box); | ||
const oldName = domainObject.name; | ||
|
||
{ | ||
// Change some geometry | ||
const transaction = domainObject.createTransaction(Changes.geometry); | ||
manager.addTransaction(transaction); | ||
domainObject.box.size.multiplyScalar(3); | ||
domainObject.box.center.addScalar(3); | ||
domainObject.notify(Changes.geometry); | ||
expect(domainObject.box.size).not.toStrictEqual(oldBox.size); | ||
expect(domainObject.box.center).not.toStrictEqual(oldBox.center); | ||
} | ||
{ | ||
// Change name | ||
const transaction = domainObject.createTransaction(Changes.naming); | ||
expect(manager.addTransaction(transaction)).toBe(false); | ||
domainObject.name = 'new name'; | ||
domainObject.notify(Changes.naming); | ||
expect(domainObject.name).not.toBe(oldName); | ||
} | ||
// Undo | ||
manager.undo(renderTarget); | ||
expectEqualVector3(domainObject.box.size, oldBox.size); | ||
expectEqualVector3(domainObject.box.center, oldBox.center); | ||
expect(domainObject.name).toBe(oldName); | ||
expect(manager.canUndo).toBe(false); | ||
}); | ||
|
||
test('Should undo add', () => { | ||
// Add the new domainObject | ||
const domainObject = createBoxDomainObject(); | ||
const transaction = domainObject.createTransaction(Changes.added); | ||
expect(manager.addTransaction(transaction)).toBe(true); | ||
root.addChildInteractive(domainObject); | ||
expect(root.getThisOrDescendantByUniqueId(domainObject.uniqueId)).toBeDefined(); | ||
expect(domainObject.hasParent).toBe(true); | ||
|
||
// Undo | ||
manager.undo(renderTarget); | ||
expect(root.getThisOrDescendantByUniqueId(domainObject.uniqueId)).toBeUndefined(); | ||
expect(domainObject.hasParent).toBe(false); | ||
expect(manager.canUndo).toBe(false); | ||
}); | ||
|
||
test('Should undo deleted', () => { | ||
const domainObject = createBoxDomainObject(); | ||
root.addChildInteractive(domainObject); | ||
const uniqueId = domainObject.uniqueId; | ||
|
||
// Delete the domain object | ||
const transaction = domainObject.createTransaction(Changes.deleted); | ||
expect(manager.addTransaction(transaction)).toBe(true); | ||
domainObject.removeInteractive(); | ||
expect(root.getThisOrDescendantByUniqueId(uniqueId)).toBeUndefined(); | ||
|
||
manager.undo(renderTarget); | ||
const restoredDomainObject = root.getThisOrDescendantByUniqueId(uniqueId); | ||
expect(restoredDomainObject).toBeDefined(); | ||
expect(restoredDomainObject).not.toBe(domainObject); | ||
expect(manager.canUndo).toBe(false); | ||
}); | ||
}); | ||
|
||
function createBoxDomainObject(): BoxDomainObject { | ||
const domainObject = new MeasureBoxDomainObject(PrimitiveType.Box); | ||
const { box } = domainObject; | ||
box.size.set(1, 2, 3); | ||
box.center.set(4, 5, 6); | ||
return domainObject; | ||
} | ||
|
||
function createRenderTargetMock(): RevealRenderTarget { | ||
const renderTarget = new RevealRenderTarget(viewerMock, sdkMock); | ||
return renderTarget; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,11 +10,9 @@ import { type PrimitivePickInfo } from '../common/PrimitivePickInfo'; | |
import { type BaseDragger } from '../../../base/domainObjectsHelpers/BaseDragger'; | ||
import { BoxDragger } from './BoxDragger'; | ||
import { type CreateDraggerProps } from '../../../base/domainObjects/VisualDomainObject'; | ||
import { getIconByPrimitiveType } from '../../../base/utilities/primitives/getIconByPrimitiveType'; | ||
import { type TranslationInput } from '../../../base/utilities/TranslateInput'; | ||
import { Quantity } from '../../../base/domainObjectsHelpers/Quantity'; | ||
import { PanelInfo } from '../../../base/domainObjectsHelpers/PanelInfo'; | ||
import { type IconName } from '../../../base/utilities/IconName'; | ||
import { SolidDomainObject } from '../common/SolidDomainObject'; | ||
import { SolidPrimitiveRenderStyle } from '../common/SolidPrimitiveRenderStyle'; | ||
import { Box } from '../../../base/utilities/primitives/Box'; | ||
|
@@ -42,10 +40,6 @@ export abstract class BoxDomainObject extends SolidDomainObject { | |
// OVERRIDES of DomainObject | ||
// ================================================== | ||
|
||
public override get icon(): IconName { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed, implementation is already in the base class |
||
return getIconByPrimitiveType(this.primitiveType); | ||
} | ||
|
||
public override get typeName(): TranslationInput { | ||
switch (this.primitiveType) { | ||
case PrimitiveType.HorizontalArea: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,6 @@ import { type PrimitivePickInfo } from '../common/PrimitivePickInfo'; | |
import { type BaseDragger } from '../../../base/domainObjectsHelpers/BaseDragger'; | ||
import { CylinderDragger } from './CylinderDragger'; | ||
import { type CreateDraggerProps } from '../../../base/domainObjects/VisualDomainObject'; | ||
import { getIconByPrimitiveType } from '../../../base/utilities/primitives/getIconByPrimitiveType'; | ||
import { type TranslationInput } from '../../../base/utilities/TranslateInput'; | ||
import { Quantity } from '../../../base/domainObjectsHelpers/Quantity'; | ||
import { PanelInfo } from '../../../base/domainObjectsHelpers/PanelInfo'; | ||
|
@@ -19,7 +18,6 @@ import { SolidPrimitiveRenderStyle } from '../common/SolidPrimitiveRenderStyle'; | |
import { Cylinder } from '../../../base/utilities/primitives/Cylinder'; | ||
import { Line3, Vector3 } from 'three'; | ||
import { type RevealRenderTarget } from '../../../base/renderTarget/RevealRenderTarget'; | ||
import { type IconName } from '../../../base/utilities/IconName'; | ||
|
||
export abstract class CylinderDomainObject extends SolidDomainObject { | ||
// ================================================== | ||
|
@@ -32,10 +30,6 @@ export abstract class CylinderDomainObject extends SolidDomainObject { | |
// OVERRIDES of DomainObject | ||
// ================================================== | ||
|
||
public override get icon(): IconName { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed, implementation is already in the base class |
||
return getIconByPrimitiveType(this.primitiveType); | ||
} | ||
|
||
public override get typeName(): TranslationInput { | ||
return { key: 'CYLINDER' }; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import { type CameraManager, type CameraManagerEventType, type CameraState } from '@cognite/reveal'; | ||
import { remove } from 'lodash'; | ||
import { Mock } from 'moq.ts'; | ||
import { PerspectiveCamera } from 'three'; | ||
|
||
import { vi, type Mock as viMock } from 'vitest'; | ||
|
||
|
@@ -36,6 +37,8 @@ export const cameraManagerMock = new Mock<CameraManager>() | |
}) | ||
.setup((p) => p.getCameraState()) | ||
.returns(cameraManagerGlobalCurrentCameraState as Required<CameraState>) | ||
.setup((p) => p.getCamera) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added this to the ,mock. It is needed. |
||
.returns(() => new PerspectiveCamera()) | ||
.setup((p) => p.fitCameraToBoundingBox) | ||
.returns(fitCameraToBoundingBoxMock) | ||
.object(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,4 +43,16 @@ export const viewerMock = new Mock<Cognite3DViewer<DataSourceType>>() | |
.returns(fitCameraToModelsMock) | ||
.setup((p) => p.requestRedraw) | ||
.returns(vi.fn()) | ||
.setup((p) => p.on) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also needed in the unit tests |
||
.returns(vi.fn()) | ||
.setup((p) => p.off) | ||
.returns(vi.fn()) | ||
.setup((p) => p.addObject3D) | ||
.returns(vi.fn()) | ||
.setup((p) => p.removeObject3D) | ||
.returns(vi.fn()) | ||
.setup((p) => p.addCustomObject) | ||
.returns(vi.fn()) | ||
.setup((p) => p.removeCustomObject) | ||
.returns(vi.fn()) | ||
.object(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed and will give problems in the unit test