chore: bump @testing-library/react 12.1.5 -> 16.0.0 (#8322)

This commit is contained in:
David Luzar 2024-08-06 15:17:42 +02:00 committed by GitHub
parent 3cf14c73a3
commit f19ce30dfe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 1035 additions and 978 deletions

View file

@ -2141,16 +2141,6 @@ class App extends React.Component<AppProps, AppState> {
let editingElement: AppState["editingElement"] | null = null;
if (actionResult.elements) {
actionResult.elements.forEach((element) => {
if (
this.state.editingElement?.id === element.id &&
this.state.editingElement !== element &&
isNonDeletedElement(element)
) {
editingElement = element;
}
});
this.scene.replaceAllElements(actionResult.elements);
didUpdate = true;
}
@ -2183,8 +2173,20 @@ class App extends React.Component<AppProps, AppState> {
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
}
editingElement =
editingElement || actionResult.appState?.editingElement || null;
editingElement = actionResult.appState?.editingElement || null;
// make sure editingElement points to latest element reference
if (actionResult.elements && editingElement) {
actionResult.elements.forEach((element) => {
if (
editingElement?.id === element.id &&
editingElement !== element &&
isNonDeletedElement(element)
) {
editingElement = element;
}
});
}
if (editingElement?.isDeleted) {
editingElement = null;
@ -4479,15 +4481,22 @@ class App extends React.Component<AppProps, AppState> {
const elementIdToSelect = element.containerId
? element.containerId
: element.id;
this.setState((prevState) => ({
selectedElementIds: makeNextSelectedElementIds(
{
...prevState.selectedElementIds,
[elementIdToSelect]: true,
},
prevState,
),
}));
// needed to ensure state is updated before "finalize" action
// that's invoked on keyboard-submit as well
// TODO either move this into finalize as well, or handle all state
// updates in one place, skipping finalize action
flushSync(() => {
this.setState((prevState) => ({
selectedElementIds: makeNextSelectedElementIds(
{
...prevState.selectedElementIds,
[elementIdToSelect]: true,
},
prevState,
),
}));
});
}
if (isDeleted) {
fixBindingsAfterDeletion(this.scene.getNonDeletedElements(), [

View file

@ -9,7 +9,7 @@ import {
import {
assertExcalidrawWithSidebar,
assertSidebarDockButton,
} from "./Sidebar/Sidebar.test";
} from "./Sidebar/siderbar.test.helpers";
const { h } = window;

View file

@ -2,8 +2,8 @@ import React from "react";
import { DEFAULT_SIDEBAR } from "../../constants";
import { Excalidraw, Sidebar } from "../../index";
import {
act,
fireEvent,
GlobalTestState,
queryAllByTestId,
queryByTestId,
render,
@ -11,39 +11,17 @@ import {
withExcalidrawDimensions,
} from "../../tests/test-utils";
import { vi } from "vitest";
import {
assertExcalidrawWithSidebar,
assertSidebarDockButton,
} from "./siderbar.test.helpers";
export const assertSidebarDockButton = async <T extends boolean>(
hasDockButton: T,
): Promise<
T extends false
? { dockButton: null; sidebar: HTMLElement }
: { dockButton: HTMLElement; sidebar: HTMLElement }
> => {
const sidebar =
GlobalTestState.renderResult.container.querySelector<HTMLElement>(
".sidebar",
);
expect(sidebar).not.toBe(null);
const dockButton = queryByTestId(sidebar!, "sidebar-dock");
if (hasDockButton) {
expect(dockButton).not.toBe(null);
return { dockButton: dockButton!, sidebar: sidebar! } as any;
}
expect(dockButton).toBe(null);
return { dockButton: null, sidebar: sidebar! } as any;
};
export const assertExcalidrawWithSidebar = async (
sidebar: React.ReactNode,
name: string,
test: () => void,
) => {
await render(
<Excalidraw initialData={{ appState: { openSidebar: { name } } }}>
{sidebar}
</Excalidraw>,
);
await withExcalidrawDimensions({ width: 1920, height: 1080 }, test);
const toggleSidebar = (
...args: Parameters<typeof window.h.app.toggleSidebar>
): Promise<boolean> => {
return act(() => {
return window.h.app.toggleSidebar(...args);
});
};
describe("Sidebar", () => {
@ -103,7 +81,7 @@ describe("Sidebar", () => {
// toggle sidebar on
// -------------------------------------------------------------------------
expect(window.h.app.toggleSidebar({ name: "customSidebar" })).toBe(true);
expect(await toggleSidebar({ name: "customSidebar" })).toBe(true);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
@ -112,7 +90,7 @@ describe("Sidebar", () => {
// toggle sidebar off
// -------------------------------------------------------------------------
expect(window.h.app.toggleSidebar({ name: "customSidebar" })).toBe(false);
expect(await toggleSidebar({ name: "customSidebar" })).toBe(false);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
@ -121,9 +99,9 @@ describe("Sidebar", () => {
// force-toggle sidebar off (=> still hidden)
// -------------------------------------------------------------------------
expect(
window.h.app.toggleSidebar({ name: "customSidebar", force: false }),
).toBe(false);
expect(await toggleSidebar({ name: "customSidebar", force: false })).toBe(
false,
);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
@ -132,12 +110,12 @@ describe("Sidebar", () => {
// force-toggle sidebar on
// -------------------------------------------------------------------------
expect(
window.h.app.toggleSidebar({ name: "customSidebar", force: true }),
).toBe(true);
expect(
window.h.app.toggleSidebar({ name: "customSidebar", force: true }),
).toBe(true);
expect(await toggleSidebar({ name: "customSidebar", force: true })).toBe(
true,
);
expect(await toggleSidebar({ name: "customSidebar", force: true })).toBe(
true,
);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
@ -146,9 +124,7 @@ describe("Sidebar", () => {
// toggle library (= hide custom sidebar)
// -------------------------------------------------------------------------
expect(window.h.app.toggleSidebar({ name: DEFAULT_SIDEBAR.name })).toBe(
true,
);
expect(await toggleSidebar({ name: DEFAULT_SIDEBAR.name })).toBe(true);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
@ -161,13 +137,13 @@ describe("Sidebar", () => {
// closing sidebar using `{ name: null }`
// -------------------------------------------------------------------------
expect(window.h.app.toggleSidebar({ name: "customSidebar" })).toBe(true);
expect(await toggleSidebar({ name: "customSidebar" })).toBe(true);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
expect(node).not.toBe(null);
});
expect(window.h.app.toggleSidebar({ name: null })).toBe(false);
expect(await toggleSidebar({ name: null })).toBe(false);
await waitFor(() => {
const node = container.querySelector("#test-sidebar-content");
expect(node).toBe(null);
@ -321,6 +297,9 @@ describe("Sidebar", () => {
});
it("shouldn't be user-dockable when only `onDock` supplied w/o `docked`", async () => {
// we expect warnings in this test and don't want to pollute stdout
const mock = jest.spyOn(console, "warn").mockImplementation(() => {});
await render(
<Excalidraw
initialData={{ appState: { openSidebar: { name: "customSidebar" } } }}
@ -341,6 +320,8 @@ describe("Sidebar", () => {
await assertSidebarDockButton(false);
},
);
mock.mockRestore();
});
});
@ -367,9 +348,9 @@ describe("Sidebar", () => {
).toBeNull();
// open library sidebar
expect(
window.h.app.toggleSidebar({ name: "custom", tab: "library" }),
).toBe(true);
expect(await toggleSidebar({ name: "custom", tab: "library" })).toBe(
true,
);
expect(
container.querySelector<HTMLElement>(
"[role=tabpanel][data-testid=library]",
@ -377,9 +358,9 @@ describe("Sidebar", () => {
).not.toBeNull();
// switch to comments tab
expect(
window.h.app.toggleSidebar({ name: "custom", tab: "comments" }),
).toBe(true);
expect(await toggleSidebar({ name: "custom", tab: "comments" })).toBe(
true,
);
expect(
container.querySelector<HTMLElement>(
"[role=tabpanel][data-testid=comments]",
@ -387,9 +368,9 @@ describe("Sidebar", () => {
).not.toBeNull();
// toggle sidebar closed
expect(
window.h.app.toggleSidebar({ name: "custom", tab: "comments" }),
).toBe(false);
expect(await toggleSidebar({ name: "custom", tab: "comments" })).toBe(
false,
);
expect(
container.querySelector<HTMLElement>(
"[role=tabpanel][data-testid=comments]",
@ -397,9 +378,9 @@ describe("Sidebar", () => {
).toBeNull();
// toggle sidebar open
expect(
window.h.app.toggleSidebar({ name: "custom", tab: "comments" }),
).toBe(true);
expect(await toggleSidebar({ name: "custom", tab: "comments" })).toBe(
true,
);
expect(
container.querySelector<HTMLElement>(
"[role=tabpanel][data-testid=comments]",

View file

@ -0,0 +1,42 @@
import React from "react";
import { Excalidraw } from "../..";
import {
GlobalTestState,
queryByTestId,
render,
withExcalidrawDimensions,
} from "../../tests/test-utils";
export const assertSidebarDockButton = async <T extends boolean>(
hasDockButton: T,
): Promise<
T extends false
? { dockButton: null; sidebar: HTMLElement }
: { dockButton: HTMLElement; sidebar: HTMLElement }
> => {
const sidebar =
GlobalTestState.renderResult.container.querySelector<HTMLElement>(
".sidebar",
);
expect(sidebar).not.toBe(null);
const dockButton = queryByTestId(sidebar!, "sidebar-dock");
if (hasDockButton) {
expect(dockButton).not.toBe(null);
return { dockButton: dockButton!, sidebar: sidebar! } as any;
}
expect(dockButton).toBe(null);
return { dockButton: null, sidebar: sidebar! } as any;
};
export const assertExcalidrawWithSidebar = async (
sidebar: React.ReactNode,
name: string,
test: () => void,
) => {
await render(
<Excalidraw initialData={{ appState: { openSidebar: { name } } }}>
{sidebar}
</Excalidraw>,
);
await withExcalidrawDimensions({ width: 1920, height: 1080 }, test);
};

View file

@ -1,4 +1,5 @@
import { fireEvent, queryByTestId } from "@testing-library/react";
import React from "react";
import { act, fireEvent, queryByTestId } from "@testing-library/react";
import { Keyboard, Pointer, UI } from "../../tests/helpers/ui";
import { getStepSizedValue } from "./utils";
import {
@ -24,7 +25,6 @@ import { getCommonBounds, isTextElement } from "../../element";
import { API } from "../../tests/helpers/api";
import { actionGroup } from "../../actions";
import { isInGroup } from "../../groups";
import React from "react";
const { h } = window;
const mouse = new Pointer("mouse");
@ -32,12 +32,6 @@ const renderStaticScene = vi.spyOn(StaticScene, "renderStaticScene");
let stats: HTMLElement | null = null;
let elementStats: HTMLElement | null | undefined = null;
const editInput = (input: HTMLInputElement, value: string) => {
input.focus();
fireEvent.change(input, { target: { value } });
input.blur();
};
const getStatsProperty = (label: string) => {
const elementStats = UI.queryStats()?.querySelector("#elementStats");
@ -65,7 +59,7 @@ const testInputProperty = (
) as HTMLInputElement;
expect(input).toBeDefined();
expect(input.value).toBe(initialValue.toString());
editInput(input, String(nextValue));
UI.updateInput(input, String(nextValue));
if (property === "angle") {
expect(element[property]).toBe(degreeToRadian(Number(nextValue)));
} else if (property === "fontSize" && isTextElement(element)) {
@ -110,7 +104,7 @@ describe("binding with linear elements", () => {
await render(<Excalidraw handleKeyboardGlobally={true} />);
h.elements = [];
API.setElements([]);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
@ -148,7 +142,7 @@ describe("binding with linear elements", () => {
expect(linear.startBinding).not.toBe(null);
expect(inputX).not.toBeNull();
editInput(inputX, String("204"));
UI.updateInput(inputX, String("204"));
expect(linear.startBinding).not.toBe(null);
});
@ -159,7 +153,7 @@ describe("binding with linear elements", () => {
) as HTMLInputElement;
expect(linear.startBinding).not.toBe(null);
editInput(inputAngle, String("1"));
UI.updateInput(inputAngle, String("1"));
expect(linear.startBinding).not.toBe(null);
});
@ -171,7 +165,7 @@ describe("binding with linear elements", () => {
expect(linear.startBinding).not.toBe(null);
expect(inputX).not.toBeNull();
editInput(inputX, String("254"));
UI.updateInput(inputX, String("254"));
expect(linear.startBinding).toBe(null);
});
@ -182,7 +176,7 @@ describe("binding with linear elements", () => {
) as HTMLInputElement;
expect(linear.startBinding).not.toBe(null);
editInput(inputAngle, String("45"));
UI.updateInput(inputAngle, String("45"));
expect(linear.startBinding).toBe(null);
});
});
@ -197,7 +191,7 @@ describe("stats for a generic element", () => {
await render(<Excalidraw handleKeyboardGlobally={true} />);
h.elements = [];
API.setElements([]);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
@ -268,13 +262,13 @@ describe("stats for a generic element", () => {
) as HTMLInputElement;
expect(input).toBeDefined();
expect(input.value).toBe(rectangle.width.toString());
editInput(input, "123.123");
UI.updateInput(input, "123.123");
expect(h.elements.length).toBe(1);
expect(rectangle.id).toBe(rectangleId);
expect(input.value).toBe("123.12");
expect(rectangle.width).toBe(123.12);
editInput(input, "88.98766");
UI.updateInput(input, "88.98766");
expect(input.value).toBe("88.99");
expect(rectangle.width).toBe(88.99);
});
@ -387,7 +381,7 @@ describe("stats for a non-generic element", () => {
await render(<Excalidraw handleKeyboardGlobally={true} />);
h.elements = [];
API.setElements([]);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
@ -412,9 +406,10 @@ describe("stats for a non-generic element", () => {
mouse.clickAt(20, 30);
const textEditorSelector = ".excalidraw-textEditorContainer > textarea";
const editor = await getTextEditor(textEditorSelector, true);
await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello!");
editor.blur();
act(() => {
editor.blur();
});
const text = h.elements[0] as ExcalidrawTextElement;
mouse.clickOn(text);
@ -427,7 +422,7 @@ describe("stats for a non-generic element", () => {
) as HTMLInputElement;
expect(input).toBeDefined();
expect(input.value).toBe(text.fontSize.toString());
editInput(input, "36");
UI.updateInput(input, "36");
expect(text.fontSize).toBe(36);
// cannot change width or height
@ -437,7 +432,7 @@ describe("stats for a non-generic element", () => {
expect(height).toBeUndefined();
// min font size is 4
editInput(input, "0");
UI.updateInput(input, "0");
expect(text.fontSize).not.toBe(0);
expect(text.fontSize).toBe(4);
});
@ -449,8 +444,8 @@ describe("stats for a non-generic element", () => {
x: 150,
width: 150,
});
h.elements = [frame];
h.setState({
API.setElements([frame]);
API.setAppState({
selectedElementIds: {
[frame.id]: true,
},
@ -471,9 +466,9 @@ describe("stats for a non-generic element", () => {
it("image element", () => {
const image = API.createElement({ type: "image", width: 200, height: 100 });
h.elements = [image];
API.setElements([image]);
mouse.clickOn(image);
h.setState({
API.setAppState({
selectedElementIds: {
[image.id]: true,
},
@ -508,7 +503,7 @@ describe("stats for a non-generic element", () => {
mutateElement(container, {
boundElements: [{ type: "text", id: text.id }],
});
h.elements = [container, text];
API.setElements([container, text]);
API.setSelectedElements([container]);
const fontSize = getStatsProperty("F")?.querySelector(
@ -516,7 +511,7 @@ describe("stats for a non-generic element", () => {
) as HTMLInputElement;
expect(fontSize).toBeDefined();
editInput(fontSize, "40");
UI.updateInput(fontSize, "40");
expect(text.fontSize).toBe(40);
});
@ -533,7 +528,7 @@ describe("stats for multiple elements", () => {
await render(<Excalidraw handleKeyboardGlobally={true} />);
h.elements = [];
API.setElements([]);
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
@ -566,7 +561,7 @@ describe("stats for multiple elements", () => {
mouse.down(-100, -100);
mouse.up(125, 145);
h.setState({
API.setAppState({
selectedElementIds: h.elements.reduce((acc, el) => {
acc[el.id] = true;
return acc;
@ -588,12 +583,12 @@ describe("stats for multiple elements", () => {
) as HTMLInputElement;
expect(angle.value).toBe("0");
editInput(width, "250");
UI.updateInput(width, "250");
h.elements.forEach((el) => {
expect(el.width).toBe(250);
});
editInput(height, "450");
UI.updateInput(height, "450");
h.elements.forEach((el) => {
expect(el.height).toBe(450);
});
@ -605,9 +600,10 @@ describe("stats for multiple elements", () => {
mouse.clickAt(20, 30);
const textEditorSelector = ".excalidraw-textEditorContainer > textarea";
const editor = await getTextEditor(textEditorSelector, true);
await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello!");
editor.blur();
act(() => {
editor.blur();
});
UI.clickTool("rectangle");
mouse.down();
@ -619,12 +615,12 @@ describe("stats for multiple elements", () => {
width: 150,
});
h.elements = [...h.elements, frame];
API.setElements([...h.elements, frame]);
const text = h.elements.find((el) => el.type === "text");
const rectangle = h.elements.find((el) => el.type === "rectangle");
h.setState({
API.setAppState({
selectedElementIds: h.elements.reduce((acc, el) => {
acc[el.id] = true;
return acc;
@ -657,13 +653,13 @@ describe("stats for multiple elements", () => {
expect(fontSize).toBeDefined();
// changing width does not affect text
editInput(width, "200");
UI.updateInput(width, "200");
expect(rectangle?.width).toBe(200);
expect(frame.width).toBe(200);
expect(text?.width).not.toBe(200);
editInput(angle, "40");
UI.updateInput(angle, "40");
const angleInRadian = degreeToRadian(40);
expect(rectangle?.angle).toBeCloseTo(angleInRadian, 4);
@ -686,7 +682,7 @@ describe("stats for multiple elements", () => {
mouse.click();
});
h.app.actionManager.executeAction(actionGroup);
API.executeAction(actionGroup);
};
createAndSelectGroup();
@ -703,7 +699,7 @@ describe("stats for multiple elements", () => {
expect(x).toBeDefined();
expect(Number(x.value)).toBe(x1);
editInput(x, "300");
UI.updateInput(x, "300");
expect(h.elements[0].x).toBe(300);
expect(h.elements[1].x).toBe(400);
@ -716,7 +712,7 @@ describe("stats for multiple elements", () => {
expect(y).toBeDefined();
expect(Number(y.value)).toBe(y1);
editInput(y, "200");
UI.updateInput(y, "200");
expect(h.elements[0].y).toBe(200);
expect(h.elements[1].y).toBe(300);
@ -734,20 +730,20 @@ describe("stats for multiple elements", () => {
expect(height).toBeDefined();
expect(Number(height.value)).toBe(200);
editInput(width, "400");
UI.updateInput(width, "400");
[x1, y1, x2, y2] = getCommonBounds(elementsInGroup);
let newGroupWidth = x2 - x1;
expect(newGroupWidth).toBeCloseTo(400, 4);
editInput(width, "300");
UI.updateInput(width, "300");
[x1, y1, x2, y2] = getCommonBounds(elementsInGroup);
newGroupWidth = x2 - x1;
expect(newGroupWidth).toBeCloseTo(300, 4);
editInput(height, "500");
UI.updateInput(height, "500");
[x1, y1, x2, y2] = getCommonBounds(elementsInGroup);
const newGroupHeight = y2 - y1;

View file

@ -1,7 +1,13 @@
import React from "react";
import { Excalidraw } from "../../index";
import { KEYS } from "../../keys";
import { Keyboard } from "../../tests/helpers/ui";
import { render, waitFor, getByTestId } from "../../tests/test-utils";
import {
render,
waitFor,
getByTestId,
fireEvent,
} from "../../tests/test-utils";
describe("Test <DropdownMenu/>", () => {
it("should", async () => {
@ -9,7 +15,7 @@ describe("Test <DropdownMenu/>", () => {
expect(window.h.state.openMenu).toBe(null);
getByTestId(container, "main-menu-trigger").click();
fireEvent.click(getByTestId(container, "main-menu-trigger"));
expect(window.h.state.openMenu).toBe("canvas");
await waitFor(() => {

View file

@ -1,3 +1,4 @@
import React from "react";
import { render, queryAllByTestId } from "../../tests/test-utils";
import { Excalidraw, MainMenu } from "../../index";