Add test for multi-selection synchronization between outliner and viewport

This commit is contained in:
2026-04-15 15:13:06 +02:00
parent 492f7aacab
commit 41bb2d9e24

View File

@@ -225,6 +225,63 @@ async function renderQuadTransformFixtureApp() {
return fixture;
}
async function renderMultiSelectionFixtureApp() {
const brushA = createBoxBrush({
id: "brush-multi-select-a",
name: "Brush Multi A",
center: {
x: -2,
y: 1,
z: 0
}
});
const brushB = createBoxBrush({
id: "brush-multi-select-b",
name: "Brush Multi B",
center: {
x: 4,
y: 1,
z: 0
}
});
const playerStart = createPlayerStartEntity({
id: "entity-multi-select-player",
name: "Player Multi Fixture",
position: {
x: 0,
y: 0,
z: -4
}
});
const store = createEditorStore({
initialDocument: {
...createEmptySceneDocument({ name: "Multi Selection Fixture" }),
brushes: {
[brushA.id]: brushA,
[brushB.id]: brushB
},
entities: {
[playerStart.id]: playerStart
}
}
});
render(<App store={store} />);
await waitFor(() => {
expect(viewportHostInstances.length).toBeGreaterThan(0);
expect(getTopLeftViewportHost().setBrushSelectionChangeHandler).toHaveBeenCalled();
});
return {
store,
brushA,
brushB,
playerStart,
viewportHost: getTopLeftViewportHost()
};
}
function getLatestTransformSession(
store: ReturnType<typeof createEditorStore>
): ActiveTransformSession {
@@ -576,6 +633,46 @@ describe("transform foundation integration", () => {
expect(screen.getByText(/selection mode set to object/i)).toBeInTheDocument();
});
it("keeps outliner and viewport selection state synchronized for same-kind multi-selection", async () => {
const { store, brushA, brushB, playerStart, viewportHost } =
await renderMultiSelectionFixtureApp();
await act(async () => {
fireEvent.click(screen.getByTestId(`outliner-brush-${brushA.id}`));
});
await act(async () => {
fireEvent.click(screen.getByTestId(`outliner-brush-${brushB.id}`), {
shiftKey: true
});
});
expect(store.getState().selection).toEqual({
kind: "brushes",
ids: [brushA.id, brushB.id]
});
expect(store.getState().activeSelectionId).toBe(brushB.id);
expect(screen.getByText("Whitebox Solids")).toBeInTheDocument();
expect(screen.getByText("2 selected")).toBeInTheDocument();
expect(screen.getByText("Brush Multi B")).toBeInTheDocument();
const selectionHandler = viewportHost.setBrushSelectionChangeHandler.mock.calls.at(
-1
)?.[0] as ((selection: { kind: "entities"; ids: string[] }) => void);
act(() => {
selectionHandler({
kind: "entities",
ids: [playerStart.id]
});
});
expect(store.getState().selection).toEqual({
kind: "entities",
ids: [playerStart.id]
});
expect(store.getState().activeSelectionId).toBe(playerStart.id);
});
it("moves an entity through the shared transform controller", async () => {
const { store, playerStart, viewportHost } =
await renderTransformFixtureApp();