Enhance ViewportCanvas unit tests for time transport controls and pointer events
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { act, render, screen, waitFor } from "@testing-library/react";
|
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -120,6 +120,7 @@ describe("ViewportCanvas", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
vi.useRealTimers();
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -805,6 +806,260 @@ describe("ViewportCanvas", () => {
|
|||||||
).toHaveTextContent("terrain · paint · layer 3");
|
).toHaveTextContent("terrain · paint · layer 3");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("shows the viewport time transport only on the active viewport panel", () => {
|
||||||
|
const sceneDocument = createEmptySceneDocument();
|
||||||
|
const commonProps = {
|
||||||
|
world: sceneDocument.world,
|
||||||
|
sceneDocument,
|
||||||
|
editorSimulationController: new EditorSimulationController(),
|
||||||
|
projectAssets: sceneDocument.assets,
|
||||||
|
loadedModelAssets: {},
|
||||||
|
loadedImageAssets: {},
|
||||||
|
whiteboxSelectionMode: "object" as const,
|
||||||
|
whiteboxSnapEnabled: true,
|
||||||
|
whiteboxSnapStep: 1,
|
||||||
|
viewportGridVisible: true,
|
||||||
|
selection: { kind: "none" } as EditorSelection,
|
||||||
|
activeSelectionId: null,
|
||||||
|
terrainBrushState: null,
|
||||||
|
toolMode: "select" as const,
|
||||||
|
toolPreview: { kind: "none" } as ViewportToolPreview,
|
||||||
|
transformSession: createInactiveTransformSession(),
|
||||||
|
cameraState: createDefaultViewportPanelCameraState(),
|
||||||
|
viewMode: "perspective" as const,
|
||||||
|
displayMode: "normal" as const,
|
||||||
|
layoutMode: "quad" as const,
|
||||||
|
focusRequestId: 0,
|
||||||
|
focusSelection: { kind: "none" } as EditorSelection,
|
||||||
|
onSelectionChange: vi.fn(),
|
||||||
|
onTerrainBrushCommit: vi.fn(() => true),
|
||||||
|
onCommitCreation: vi.fn(() => true),
|
||||||
|
onCameraStateChange: vi.fn(),
|
||||||
|
onToolPreviewChange: vi.fn(),
|
||||||
|
onTransformSessionChange: vi.fn(),
|
||||||
|
onTransformCommit: vi.fn(),
|
||||||
|
onTransformCancel: vi.fn(),
|
||||||
|
onPlayEditorSimulation: vi.fn(),
|
||||||
|
onPauseEditorSimulation: vi.fn(),
|
||||||
|
onStepEditorSimulation: vi.fn()
|
||||||
|
};
|
||||||
|
|
||||||
|
const { rerender } = render(
|
||||||
|
<ViewportCanvas panelId="topLeft" isActivePanel {...commonProps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByTestId("viewport-time-transport-topLeft")).toBeVisible();
|
||||||
|
|
||||||
|
rerender(
|
||||||
|
<ViewportCanvas
|
||||||
|
panelId="topRight"
|
||||||
|
isActivePanel={false}
|
||||||
|
{...commonProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByTestId("viewport-time-transport-topRight")
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes viewport time transport play and pause to editor simulation handlers", () => {
|
||||||
|
const sceneDocument = createEmptySceneDocument();
|
||||||
|
const onPlayEditorSimulation = vi.fn();
|
||||||
|
const onPauseEditorSimulation = vi.fn();
|
||||||
|
|
||||||
|
const renderCanvas = (editorSimulationPlaying: boolean) => (
|
||||||
|
<ViewportCanvas
|
||||||
|
panelId="topLeft"
|
||||||
|
world={sceneDocument.world}
|
||||||
|
sceneDocument={sceneDocument}
|
||||||
|
editorSimulationController={new EditorSimulationController()}
|
||||||
|
editorSimulationPlaying={editorSimulationPlaying}
|
||||||
|
projectAssets={sceneDocument.assets}
|
||||||
|
loadedModelAssets={{}}
|
||||||
|
loadedImageAssets={{}}
|
||||||
|
whiteboxSelectionMode="object"
|
||||||
|
whiteboxSnapEnabled
|
||||||
|
whiteboxSnapStep={1}
|
||||||
|
viewportGridVisible={true}
|
||||||
|
selection={{ kind: "none" }}
|
||||||
|
activeSelectionId={null}
|
||||||
|
terrainBrushState={null}
|
||||||
|
toolMode="select"
|
||||||
|
toolPreview={{ kind: "none" }}
|
||||||
|
transformSession={createInactiveTransformSession()}
|
||||||
|
cameraState={createDefaultViewportPanelCameraState()}
|
||||||
|
viewMode="perspective"
|
||||||
|
displayMode="normal"
|
||||||
|
layoutMode="single"
|
||||||
|
isActivePanel
|
||||||
|
focusRequestId={0}
|
||||||
|
focusSelection={{ kind: "none" }}
|
||||||
|
onSelectionChange={vi.fn()}
|
||||||
|
onTerrainBrushCommit={vi.fn(() => true)}
|
||||||
|
onCommitCreation={vi.fn(() => true)}
|
||||||
|
onCameraStateChange={vi.fn()}
|
||||||
|
onToolPreviewChange={vi.fn()}
|
||||||
|
onTransformSessionChange={vi.fn()}
|
||||||
|
onTransformCommit={vi.fn()}
|
||||||
|
onTransformCancel={vi.fn()}
|
||||||
|
onPlayEditorSimulation={onPlayEditorSimulation}
|
||||||
|
onPauseEditorSimulation={onPauseEditorSimulation}
|
||||||
|
onStepEditorSimulation={vi.fn()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const { rerender } = render(renderCanvas(false));
|
||||||
|
const playToggle = screen.getByTestId("viewport-time-play-toggle-topLeft");
|
||||||
|
|
||||||
|
expect(playToggle).toHaveTextContent(">");
|
||||||
|
fireEvent.click(playToggle);
|
||||||
|
expect(onPlayEditorSimulation).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onPauseEditorSimulation).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
rerender(renderCanvas(true));
|
||||||
|
const pauseToggle = screen.getByTestId("viewport-time-play-toggle-topLeft");
|
||||||
|
|
||||||
|
expect(pauseToggle).toHaveTextContent("II");
|
||||||
|
fireEvent.click(pauseToggle);
|
||||||
|
expect(onPauseEditorSimulation).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("steps viewport time once on click and repeatedly while held", () => {
|
||||||
|
vi.useFakeTimers();
|
||||||
|
|
||||||
|
const sceneDocument = createEmptySceneDocument();
|
||||||
|
const onStepEditorSimulation = vi.fn();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<ViewportCanvas
|
||||||
|
panelId="topLeft"
|
||||||
|
world={sceneDocument.world}
|
||||||
|
sceneDocument={sceneDocument}
|
||||||
|
editorSimulationController={new EditorSimulationController()}
|
||||||
|
projectAssets={sceneDocument.assets}
|
||||||
|
loadedModelAssets={{}}
|
||||||
|
loadedImageAssets={{}}
|
||||||
|
whiteboxSelectionMode="object"
|
||||||
|
whiteboxSnapEnabled
|
||||||
|
whiteboxSnapStep={1}
|
||||||
|
viewportGridVisible={true}
|
||||||
|
selection={{ kind: "none" }}
|
||||||
|
activeSelectionId={null}
|
||||||
|
terrainBrushState={null}
|
||||||
|
toolMode="select"
|
||||||
|
toolPreview={{ kind: "none" }}
|
||||||
|
transformSession={createInactiveTransformSession()}
|
||||||
|
cameraState={createDefaultViewportPanelCameraState()}
|
||||||
|
viewMode="perspective"
|
||||||
|
displayMode="normal"
|
||||||
|
layoutMode="single"
|
||||||
|
isActivePanel
|
||||||
|
focusRequestId={0}
|
||||||
|
focusSelection={{ kind: "none" }}
|
||||||
|
onSelectionChange={vi.fn()}
|
||||||
|
onTerrainBrushCommit={vi.fn(() => true)}
|
||||||
|
onCommitCreation={vi.fn(() => true)}
|
||||||
|
onCameraStateChange={vi.fn()}
|
||||||
|
onToolPreviewChange={vi.fn()}
|
||||||
|
onTransformSessionChange={vi.fn()}
|
||||||
|
onTransformCommit={vi.fn()}
|
||||||
|
onTransformCancel={vi.fn()}
|
||||||
|
onPlayEditorSimulation={vi.fn()}
|
||||||
|
onPauseEditorSimulation={vi.fn()}
|
||||||
|
onStepEditorSimulation={onStepEditorSimulation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByTestId("viewport-time-rewind-topLeft"));
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenLastCalledWith(-0.25);
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
const fastForward = screen.getByTestId("viewport-time-forward-topLeft");
|
||||||
|
fireEvent.pointerDown(fastForward, { button: 0, pointerId: 1 });
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenLastCalledWith(0.25);
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(124);
|
||||||
|
});
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(1);
|
||||||
|
});
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(3);
|
||||||
|
|
||||||
|
fireEvent.pointerUp(fastForward, { pointerId: 1 });
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(250);
|
||||||
|
});
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("stops viewport time repeat stepping on pointer cancel and blur", () => {
|
||||||
|
vi.useFakeTimers();
|
||||||
|
|
||||||
|
const sceneDocument = createEmptySceneDocument();
|
||||||
|
const onStepEditorSimulation = vi.fn();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<ViewportCanvas
|
||||||
|
panelId="topLeft"
|
||||||
|
world={sceneDocument.world}
|
||||||
|
sceneDocument={sceneDocument}
|
||||||
|
editorSimulationController={new EditorSimulationController()}
|
||||||
|
projectAssets={sceneDocument.assets}
|
||||||
|
loadedModelAssets={{}}
|
||||||
|
loadedImageAssets={{}}
|
||||||
|
whiteboxSelectionMode="object"
|
||||||
|
whiteboxSnapEnabled
|
||||||
|
whiteboxSnapStep={1}
|
||||||
|
viewportGridVisible={true}
|
||||||
|
selection={{ kind: "none" }}
|
||||||
|
activeSelectionId={null}
|
||||||
|
terrainBrushState={null}
|
||||||
|
toolMode="select"
|
||||||
|
toolPreview={{ kind: "none" }}
|
||||||
|
transformSession={createInactiveTransformSession()}
|
||||||
|
cameraState={createDefaultViewportPanelCameraState()}
|
||||||
|
viewMode="perspective"
|
||||||
|
displayMode="normal"
|
||||||
|
layoutMode="single"
|
||||||
|
isActivePanel
|
||||||
|
focusRequestId={0}
|
||||||
|
focusSelection={{ kind: "none" }}
|
||||||
|
onSelectionChange={vi.fn()}
|
||||||
|
onTerrainBrushCommit={vi.fn(() => true)}
|
||||||
|
onCommitCreation={vi.fn(() => true)}
|
||||||
|
onCameraStateChange={vi.fn()}
|
||||||
|
onToolPreviewChange={vi.fn()}
|
||||||
|
onTransformSessionChange={vi.fn()}
|
||||||
|
onTransformCommit={vi.fn()}
|
||||||
|
onTransformCancel={vi.fn()}
|
||||||
|
onPlayEditorSimulation={vi.fn()}
|
||||||
|
onPauseEditorSimulation={vi.fn()}
|
||||||
|
onStepEditorSimulation={onStepEditorSimulation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const rewind = screen.getByTestId("viewport-time-rewind-topLeft");
|
||||||
|
fireEvent.pointerDown(rewind, { button: 0, pointerId: 2 });
|
||||||
|
fireEvent.pointerCancel(rewind, { pointerId: 2 });
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(250);
|
||||||
|
});
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
const fastForward = screen.getByTestId("viewport-time-forward-topLeft");
|
||||||
|
fireEvent.pointerDown(fastForward, { button: 0, pointerId: 3 });
|
||||||
|
fireEvent.blur(fastForward);
|
||||||
|
act(() => {
|
||||||
|
vi.advanceTimersByTime(250);
|
||||||
|
});
|
||||||
|
expect(onStepEditorSimulation).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
it("does not refocus the viewport when the scene document changes without a new focus request", async () => {
|
it("does not refocus the viewport when the scene document changes without a new focus request", async () => {
|
||||||
const baseSceneDocument = createEmptySceneDocument();
|
const baseSceneDocument = createEmptySceneDocument();
|
||||||
const focusedTerrain = createTerrain({
|
const focusedTerrain = createTerrain({
|
||||||
|
|||||||
Reference in New Issue
Block a user