Add unit tests for pause navigation controller
This commit is contained in:
149
tests/unit/pause-navigation-controller.test.ts
Normal file
149
tests/unit/pause-navigation-controller.test.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { PerspectiveCamera } from "three";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { Vec3 } from "../../src/core/vector";
|
||||
import { createEmptySceneDocument } from "../../src/document/scene-document";
|
||||
import { createPlayerStartEntity } from "../../src/entities/entity-instances";
|
||||
import type {
|
||||
FirstPersonPlayerShape,
|
||||
PlayerGroundProbeResult,
|
||||
ResolvedPlayerMotion
|
||||
} from "../../src/runtime-three/player-collision";
|
||||
import { FirstPersonNavigationController } from "../../src/runtime-three/first-person-navigation-controller";
|
||||
import { buildRuntimeSceneFromDocument } from "../../src/runtime-three/runtime-scene-build";
|
||||
import { ThirdPersonNavigationController } from "../../src/runtime-three/third-person-navigation-controller";
|
||||
|
||||
function createSuspendedContext(navigationMode: "firstPerson" | "thirdPerson") {
|
||||
const playerStart = createPlayerStartEntity({
|
||||
id: `entity-player-start-${navigationMode}`
|
||||
});
|
||||
const runtimeScene = buildRuntimeSceneFromDocument(
|
||||
{
|
||||
...createEmptySceneDocument({ name: `Paused ${navigationMode} Scene` }),
|
||||
entities: {
|
||||
[playerStart.id]: playerStart
|
||||
}
|
||||
},
|
||||
{
|
||||
navigationMode
|
||||
}
|
||||
);
|
||||
const domElement = document.createElement("canvas");
|
||||
|
||||
return {
|
||||
domElement,
|
||||
context: {
|
||||
camera: new PerspectiveCamera(70, 1, 0.05, 1000),
|
||||
domElement,
|
||||
getRuntimeScene: () => runtimeScene,
|
||||
resolveFirstPersonMotion: (
|
||||
feetPosition: Vec3,
|
||||
motion: Vec3,
|
||||
_shape: FirstPersonPlayerShape
|
||||
): ResolvedPlayerMotion => ({
|
||||
feetPosition: {
|
||||
x: feetPosition.x + motion.x,
|
||||
y: feetPosition.y + motion.y,
|
||||
z: feetPosition.z + motion.z
|
||||
},
|
||||
grounded: false,
|
||||
collisionCount: 0,
|
||||
groundCollisionNormal: null,
|
||||
collidedAxes: {
|
||||
x: false,
|
||||
y: false,
|
||||
z: false
|
||||
}
|
||||
}),
|
||||
probePlayerGround: (): PlayerGroundProbeResult => ({
|
||||
grounded: false,
|
||||
distance: null,
|
||||
normal: null,
|
||||
slopeDegrees: null
|
||||
}),
|
||||
canOccupyPlayerShape: () => true,
|
||||
resolvePlayerVolumeState: () => ({
|
||||
inWater: false,
|
||||
inFog: false,
|
||||
waterSurfaceHeight: null
|
||||
}),
|
||||
resolveThirdPersonCameraCollision: (
|
||||
_pivot: Vec3,
|
||||
desiredCameraPosition: Vec3
|
||||
) => ({ ...desiredCameraPosition }),
|
||||
isInputSuspended: () => true,
|
||||
setRuntimeMessage: vi.fn(),
|
||||
setPlayerControllerTelemetry: vi.fn()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("paused navigation input", () => {
|
||||
it("ignores first-person mouse look while input is suspended", () => {
|
||||
const { context, domElement } = createSuspendedContext("firstPerson");
|
||||
const controller = new FirstPersonNavigationController();
|
||||
|
||||
Object.defineProperty(document, "pointerLockElement", {
|
||||
configurable: true,
|
||||
get: () => domElement
|
||||
});
|
||||
|
||||
controller.activate(context);
|
||||
const initialQuaternion = context.camera.quaternion.clone();
|
||||
|
||||
(controller as unknown as {
|
||||
handleMouseMove(event: { movementX: number; movementY: number }): void;
|
||||
}).handleMouseMove({
|
||||
movementX: 48,
|
||||
movementY: 24
|
||||
});
|
||||
controller.update(0);
|
||||
|
||||
expect(context.camera.quaternion.equals(initialQuaternion)).toBe(true);
|
||||
|
||||
controller.deactivate(context, {
|
||||
releasePointerLock: false
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores third-person orbit and zoom while input is suspended", () => {
|
||||
const { context } = createSuspendedContext("thirdPerson");
|
||||
const controller = new ThirdPersonNavigationController();
|
||||
|
||||
controller.activate(context);
|
||||
const initialPosition = context.camera.position.clone();
|
||||
|
||||
(
|
||||
controller as unknown as {
|
||||
handlePointerDown(event: { button: number; clientX: number; clientY: number }): void;
|
||||
handlePointerMove(event: { clientX: number; clientY: number }): void;
|
||||
handleWheel(event: { preventDefault(): void; deltaY: number }): void;
|
||||
}
|
||||
).handlePointerDown({
|
||||
button: 0,
|
||||
clientX: 100,
|
||||
clientY: 100
|
||||
});
|
||||
(
|
||||
controller as unknown as {
|
||||
handlePointerMove(event: { clientX: number; clientY: number }): void;
|
||||
}
|
||||
).handlePointerMove({
|
||||
clientX: 180,
|
||||
clientY: 150
|
||||
});
|
||||
(
|
||||
controller as unknown as {
|
||||
handleWheel(event: { preventDefault(): void; deltaY: number }): void;
|
||||
}
|
||||
).handleWheel({
|
||||
preventDefault() {},
|
||||
deltaY: -240
|
||||
});
|
||||
controller.update(0);
|
||||
|
||||
expect(context.camera.position.equals(initialPosition)).toBe(true);
|
||||
|
||||
controller.deactivate(context);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user