snapshot of https://github.com/excalidraw/excalidraw.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Tests / test (push) Failing after 15s
Some checks failed
Tests / test (push) Failing after 15s
This commit is contained in:
182
packages/excalidraw/tests/actionStyles.test.tsx
Normal file
182
packages/excalidraw/tests/actionStyles.test.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
CODES,
|
||||
COLOR_PALETTE,
|
||||
ROUNDNESS,
|
||||
STROKE_WIDTH,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
||||
|
||||
import { copiedStyles } from "../actions/actionStyles";
|
||||
import { Excalidraw } from "../index";
|
||||
import { API } from "../tests/helpers/api";
|
||||
import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
|
||||
import {
|
||||
act,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
togglePopover,
|
||||
} from "../tests/test-utils";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
const mouse = new Pointer("mouse");
|
||||
|
||||
describe("actionStyles", () => {
|
||||
beforeEach(async () => {
|
||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// https://github.com/floating-ui/floating-ui/issues/1908#issuecomment-1301553793
|
||||
// affects node v16+
|
||||
await act(async () => {});
|
||||
});
|
||||
|
||||
it("should copy & paste styles via keyboard", async () => {
|
||||
UI.clickTool("rectangle");
|
||||
mouse.down(10, 10);
|
||||
mouse.up(20, 20);
|
||||
|
||||
UI.clickTool("rectangle");
|
||||
mouse.down(10, 10);
|
||||
mouse.up(20, 20);
|
||||
|
||||
// Change some styles of second rectangle
|
||||
togglePopover("Stroke");
|
||||
UI.clickOnTestId("color-red");
|
||||
togglePopover("Background");
|
||||
UI.clickOnTestId("color-blue");
|
||||
// Fill style
|
||||
fireEvent.click(screen.getByTitle("Cross-hatch"));
|
||||
// Stroke width
|
||||
fireEvent.click(screen.getByTitle("Bold"));
|
||||
// Stroke style
|
||||
fireEvent.click(screen.getByTitle("Dotted"));
|
||||
// Roughness
|
||||
fireEvent.click(screen.getByTitle("Cartoonist"));
|
||||
// Opacity
|
||||
fireEvent.change(screen.getByTestId("opacity"), {
|
||||
target: { value: "60" },
|
||||
});
|
||||
|
||||
mouse.reset();
|
||||
|
||||
API.setSelectedElements([h.elements[1]] as NonDeletedExcalidrawElement[]);
|
||||
|
||||
Keyboard.withModifierKeys({ ctrl: true, alt: true }, () => {
|
||||
Keyboard.codeDown(CODES.C);
|
||||
});
|
||||
const secondRect = JSON.parse(copiedStyles)[0];
|
||||
expect(secondRect.id).toBe(h.elements[1].id);
|
||||
|
||||
mouse.reset();
|
||||
// Paste styles to first rectangle
|
||||
API.setSelectedElements([h.elements[0]] as NonDeletedExcalidrawElement[]);
|
||||
Keyboard.withModifierKeys({ ctrl: true, alt: true }, () => {
|
||||
Keyboard.codeDown(CODES.V);
|
||||
});
|
||||
|
||||
const firstRect = API.getSelectedElement();
|
||||
expect(firstRect.id).toBe(h.elements[0].id);
|
||||
expect(firstRect.strokeColor).toBe("#e03131");
|
||||
expect(firstRect.backgroundColor).toBe("#a5d8ff");
|
||||
expect(firstRect.fillStyle).toBe("cross-hatch");
|
||||
expect(firstRect.strokeWidth).toBe(STROKE_WIDTH.bold);
|
||||
expect(firstRect.strokeStyle).toBe("dotted");
|
||||
expect(firstRect.roughness).toBe(2); // Cartoonist: 2
|
||||
expect(firstRect.opacity).toBe(60);
|
||||
});
|
||||
|
||||
it("should show and apply roughness for sticky notes", async () => {
|
||||
const stickyNote = API.createElement({
|
||||
type: "stickynote",
|
||||
roughness: 0,
|
||||
});
|
||||
|
||||
API.setElements([stickyNote]);
|
||||
API.setSelectedElements([stickyNote]);
|
||||
|
||||
fireEvent.click(screen.getByTitle("Cartoonist"));
|
||||
|
||||
expect(API.getSelectedElement().roughness).toBe(2);
|
||||
});
|
||||
|
||||
it("should show and apply roundness for sticky notes", async () => {
|
||||
const stickyNote = API.createElement({
|
||||
type: "stickynote",
|
||||
roundness: null,
|
||||
});
|
||||
|
||||
API.setElements([stickyNote]);
|
||||
API.setSelectedElements([stickyNote]);
|
||||
|
||||
fireEvent.click(screen.getByTitle("Round"));
|
||||
|
||||
expect(API.getSelectedElement().roundness).toEqual({
|
||||
type: ROUNDNESS.PROPORTIONAL_RADIUS,
|
||||
});
|
||||
});
|
||||
|
||||
it("should hide transparent stroke color for sticky notes", async () => {
|
||||
UI.clickTool("stickynote");
|
||||
|
||||
togglePopover("Text color");
|
||||
|
||||
// hidden via `excludedColors` (same mechanism as bucket fill): the swatch
|
||||
// is gone, but an invisible placeholder keeps the grid so the remaining
|
||||
// colors stay on their usual positions and hotkeys
|
||||
expect(screen.queryByTestId("color-transparent")).toBeNull();
|
||||
expect(
|
||||
document.querySelector(
|
||||
'.color-picker-content--default [aria-hidden="true"]',
|
||||
),
|
||||
).not.toBeNull();
|
||||
expect(screen.queryByTestId("color-black")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("keeps the transparent hotkey dead and the others intact for sticky notes", async () => {
|
||||
UI.clickTool("stickynote");
|
||||
|
||||
togglePopover("Text color");
|
||||
|
||||
const picker = document.querySelector(".color-picker-content")!;
|
||||
const before = h.state.currentItemStickynoteStrokeColor;
|
||||
|
||||
// `q` maps to the hidden transparent swatch (and to the global tool-lock
|
||||
// shortcut) — inside the popup it must be inert, not leaked
|
||||
fireEvent.keyDown(picker, { key: "q" });
|
||||
expect(h.state.currentItemStickynoteStrokeColor).toBe(before);
|
||||
expect(h.state.activeTool.locked).toBe(false);
|
||||
|
||||
// the remaining colors keep their usual keys (w = white)
|
||||
fireEvent.keyDown(picker, { key: "w" });
|
||||
expect(h.state.currentItemStickynoteStrokeColor).toBe(COLOR_PALETTE.white);
|
||||
});
|
||||
|
||||
it("should track sticky note stroke color separately", async () => {
|
||||
API.setAppState({
|
||||
currentItemStrokeColor: COLOR_PALETTE.red[4],
|
||||
currentItemStickynoteStrokeColor: COLOR_PALETTE.black,
|
||||
});
|
||||
const stickyNote = API.createElement({
|
||||
type: "stickynote",
|
||||
strokeColor: COLOR_PALETTE.black,
|
||||
});
|
||||
|
||||
API.setElements([stickyNote]);
|
||||
API.setSelectedElements([stickyNote]);
|
||||
|
||||
togglePopover("Text color");
|
||||
UI.clickOnTestId("color-blue");
|
||||
|
||||
expect(API.getSelectedElement().strokeColor).toBe(COLOR_PALETTE.blue[4]);
|
||||
expect(h.state.currentItemStickynoteStrokeColor).toBe(
|
||||
COLOR_PALETTE.blue[4],
|
||||
);
|
||||
expect(h.state.currentItemStrokeColor).toBe(COLOR_PALETTE.red[4]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user