mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 06:20:32 +00:00
* 🐛 Show the size badge on paths and straight lines The badge was hidden when the shape was smaller than the badge in either side. Flat paths have a zero width or height, so they never showed it, and straight two-point paths hid it on purpose. Paths now only compare their longest side with the badge width. A straight line compares its length, and the badge runs along the line, rotated with it and kept upright. Near the bottom of the viewport the badge moves to the other side of the line. The badge now reads the size from the shape :selrect, like the measures inputs, so a rotated path shows the same values in both places. The three badge branches share a single render block. AI-assisted-by: claude-opus-5-5 * ♻️ Extract the size badge layout and add tests for it Move the badge geometry out of selection-size-badge* into the pure size-badge-layout function, so it can be tested without rendering. The component now only picks the color and draws the result. Add unit tests for rects, flat paths and straight lines: when the badge hides, where it sits, how it rotates and how it moves when it reaches the bottom of the viewport. Keep the line rotation between -90 and 90 degrees instead of returning 360 for lines drawn leftward. The e2e test still expected straight lines to hide the badge. It now checks that the badge shows and follows the line angle. AI-assisted-by: claude-opus-5-5 * ✨ Show the length of straight lines in the size badge A straight two-point path is measured by its length, not by the box around it, so its size badge now shows the length with two decimals at most instead of width x height. Other shapes and paths keep width x height. The shorter text makes the badge narrower, so it also shows on shorter lines; the rule is the same, the badge needs the line to be at least as long as the badge. Relates to #12064 AI-assisted-by: claude-opus-5-5 * 🐛 Hide the path size badge when the path is lower than it Paths other than a straight line only hid the size badge when their longest side was narrower than it, so a wide but low path, or a narrow but tall one, still showed it. Flat paths no longer need that special case, since straight lines get their own length badge. Use the same rule as any other shape: hide the badge when either the width or the height of the path is smaller than the badge. AI-assisted-by: claude-opus-5-5
733 lines
24 KiB
JavaScript
733 lines
24 KiB
JavaScript
import { test, expect } from "@playwright/test";
|
|
import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
|
import { presenceFixture, joinFixture2, joinFixture3 } from "../../data/workspace/ws-notifications";
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await WasmWorkspacePage.init(page);
|
|
});
|
|
|
|
test("User loads worskpace with empty file", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
|
|
await expect(workspacePage.pageName).toHaveText("Page 1");
|
|
});
|
|
|
|
test("User opens a file with a bad page id", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
pageId: "badpage",
|
|
});
|
|
|
|
await expect(workspacePage.pageName).toHaveText("Page 1");
|
|
});
|
|
|
|
test("User receives presence notifications updates in the workspace", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
|
|
await workspacePage.goToWorkspace();
|
|
await workspacePage.sendPresenceMessage(presenceFixture);
|
|
|
|
await expect(
|
|
page.getByTestId("active-users-list").getByAltText("Princesa Leia"),
|
|
).toHaveCount(2);
|
|
});
|
|
|
|
test("BUG 13058 - Presence list shows up to 3 user avatars", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
|
|
await workspacePage.goToWorkspace();
|
|
await workspacePage.sendPresenceMessage(presenceFixture);
|
|
await workspacePage.sendPresenceMessage(joinFixture2);
|
|
|
|
await expect(
|
|
page.getByTestId("active-users-list").getByAltText("Princesa Leia"),
|
|
).toHaveCount(3);
|
|
|
|
await workspacePage.sendPresenceMessage(joinFixture3);
|
|
await expect(
|
|
page.getByTestId("active-users-list").getByAltText("Princesa Leia"),
|
|
).toHaveCount(2);
|
|
|
|
await expect(page.getByTestId("active-users-list").getByText("+2")).toBeVisible();
|
|
});
|
|
|
|
test("User draws a rect", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-create-rect.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
await workspacePage.rectShapeButton.click();
|
|
await workspacePage.clickWithDragViewportAt(128, 128, 200, 100);
|
|
|
|
await workspacePage.hideUI();
|
|
await expect(workspacePage.canvas).toHaveScreenshot();
|
|
});
|
|
|
|
test("Selection size badge appears on selection and hides on deselect", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
/get\-file\?/,
|
|
"workspace/get-file-not-empty.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
|
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
|
});
|
|
|
|
const badge = page.locator(".selection-size-badge");
|
|
|
|
await expect(badge).toHaveCount(0);
|
|
|
|
await workspacePage.clickLeafLayer("Rectangle");
|
|
await expect(badge).toBeVisible();
|
|
|
|
await workspacePage.page.keyboard.press("Escape");
|
|
await expect(badge).toHaveCount(0);
|
|
});
|
|
|
|
test("Selection size badge uses component color for component selection", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockGetFile("components/get-file-13267.json");
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "e9c84e12-dd29-80fc-8007-86d559dced7f",
|
|
pageId: "e9c84e12-dd29-80fc-8007-86d559dced80",
|
|
});
|
|
|
|
await workspacePage.clickLeafLayer("A Component");
|
|
|
|
const badge = page.locator(".selection-size-badge");
|
|
await expect(badge).toBeVisible();
|
|
await expect(badge.locator("rect")).toHaveCSS("fill", "rgb(187, 151, 216)");
|
|
await expect(badge.locator("text")).toHaveCSS("fill", "rgb(255, 255, 255)");
|
|
});
|
|
|
|
test("Selection size badge shows unrotated dimensions for rotated single selection", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
/get\-file\?/,
|
|
"workspace/get-file-not-empty.json",
|
|
);
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-create-rect.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
|
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
|
});
|
|
|
|
await workspacePage.clickLeafLayer("Rectangle");
|
|
|
|
const badgeText = page.locator(".selection-size-badge text");
|
|
await expect(badgeText).toHaveText("126 x 134");
|
|
|
|
const rotationInput = workspacePage.rightSidebar.getByRole("textbox", {
|
|
name: "Rotation",
|
|
});
|
|
await rotationInput.fill("45");
|
|
await rotationInput.press("Enter");
|
|
|
|
await expect(rotationInput).toHaveValue("45");
|
|
await expect(badgeText).toHaveText("126 x 134");
|
|
});
|
|
|
|
test("Selection size badge shows dimensions for path shapes", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-empty.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
|
|
// Workaround: hover viewport first to avoid nil mouse position crash
|
|
await workspacePage.viewport.hover();
|
|
|
|
// Draw a path with two segments; a single straight segment places
|
|
// the size badge along the line instead
|
|
await workspacePage.pathButton.click();
|
|
await workspacePage.clickAt(779, 163);
|
|
await workspacePage.clickAt(951, 258);
|
|
await workspacePage.clickAt(1050, 163);
|
|
|
|
// Finish drawing (commits path, path enters edition mode)
|
|
await page.keyboard.press("Escape");
|
|
|
|
// Exit edition mode (path stays selected, badge becomes visible)
|
|
await page.keyboard.press("Escape");
|
|
|
|
const badgeText = page.locator(".selection-size-badge text");
|
|
await expect(badgeText).toBeVisible();
|
|
await expect(badgeText).toHaveText(/\d+\.?\d* x \d+\.?\d*/);
|
|
});
|
|
|
|
test("Selection size badge runs along straight line paths", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-empty.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
|
|
// Workaround: hover viewport first to avoid nil mouse position crash
|
|
await workspacePage.viewport.hover();
|
|
|
|
// Draw a path with a single straight segment, going down to the right
|
|
await workspacePage.pathButton.click();
|
|
await workspacePage.clickAt(779, 163);
|
|
await workspacePage.clickAt(951, 258);
|
|
|
|
// Finish drawing (commits path, path enters edition mode)
|
|
await page.keyboard.press("Escape");
|
|
|
|
// Exit edition mode (path stays selected)
|
|
await page.keyboard.press("Escape");
|
|
|
|
await expect(page.locator(".line-controls")).toBeVisible();
|
|
|
|
// A straight line shows its length, with two decimals at most
|
|
const badge = page.locator(".selection-size-badge");
|
|
await expect(badge.locator("text")).toHaveText(/^\d+(\.\d{1,2})?$/);
|
|
|
|
// The badge follows the line angle, about 29 degrees
|
|
const transform = await badge.getAttribute("transform");
|
|
const rotation = Number(transform.match(/rotate\(([^)]+)\)/)[1]);
|
|
expect(rotation).toBeGreaterThan(20);
|
|
expect(rotation).toBeLessThan(40);
|
|
});
|
|
|
|
test("User makes a group", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
/get\-file\?/,
|
|
"workspace/get-file-not-empty.json",
|
|
);
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-create-rect.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
|
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
|
});
|
|
await workspacePage.clickLeafLayer("Rectangle");
|
|
await workspacePage.page.keyboard.press("ControlOrMeta+g");
|
|
await workspacePage.expectSelectedLayer("Group");
|
|
});
|
|
|
|
test("Bug 7654 - Toolbar keeps toggling on and off on spacebar press", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.goToWorkspace();
|
|
|
|
await workspacePage.toggleToolbarButton.click();
|
|
await workspacePage.page.keyboard.press("Backspace");
|
|
await workspacePage.page.keyboard.press("Enter");
|
|
await workspacePage.expectHiddenToolbarOptions();
|
|
});
|
|
|
|
test("Bug 7525 - User moves a scrollbar and no selection rectangle appears", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
/get\-file\?/,
|
|
"workspace/get-file-not-empty.json",
|
|
);
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-create-rect.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
|
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
|
});
|
|
|
|
// Move created rect to a corner, in order to get scrollbars
|
|
await workspacePage.panOnViewportAt(128, 128, 600, 600);
|
|
|
|
// Check scrollbars appear
|
|
const horizontalScrollbar = workspacePage.horizontalScrollbar;
|
|
await expect(horizontalScrollbar).toBeVisible();
|
|
|
|
// Grab scrollbar and move
|
|
const { x, y } = await horizontalScrollbar.boundingBox();
|
|
await page.waitForTimeout(100);
|
|
await workspacePage.viewport.hover({ position: { x: x, y: y + 5 } });
|
|
await page.mouse.down();
|
|
await workspacePage.viewport.hover({ position: { x: x - 130, y: y - 95 } });
|
|
|
|
await expect(workspacePage.selectionRect).not.toBeInViewport();
|
|
});
|
|
|
|
test("User adds a library and its automatically selected in the color palette", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC(
|
|
"link-file-to-library",
|
|
"workspace/link-file-to-library.json",
|
|
);
|
|
await workspacePage.mockRPC(
|
|
"unlink-file-from-library",
|
|
"workspace/unlink-file-from-library.json",
|
|
);
|
|
await workspacePage.mockRPC(
|
|
"get-team-shared-files?team-id=*",
|
|
"workspace/get-team-shared-libraries-non-empty.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
|
|
// Add Testing library 1
|
|
await workspacePage.clickColorPalette();
|
|
await workspacePage.clickAssets();
|
|
// Now the get-file call should return a library
|
|
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-library.json");
|
|
await workspacePage.openLibrariesModal();
|
|
await workspacePage.librariesModal.getByRole("tab", { name: "Libraries" }).click();
|
|
await workspacePage.clickLibrary("Testing library 1");
|
|
await workspacePage.closeLibrariesModal();
|
|
|
|
await expect(
|
|
workspacePage.palette.getByRole("button", { name: "test-color-187cd5" }),
|
|
).toBeVisible();
|
|
|
|
// Remove Testing library 1
|
|
await workspacePage.openLibrariesModal();
|
|
await workspacePage.clickLibrary("Testing library 1");
|
|
await workspacePage.closeLibrariesModal();
|
|
|
|
await expect(
|
|
workspacePage.palette.getByText(
|
|
"There are no color styles in your library yet",
|
|
),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("Bug 10179 - Drag & drop doesn't add colors to the Recent Colors palette", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.goToWorkspace();
|
|
await workspacePage.moveButton.click();
|
|
|
|
await workspacePage.page.keyboard.press("Alt+p");
|
|
|
|
await expect(
|
|
workspacePage.palette.getByText(
|
|
"There are no color styles in your library yet",
|
|
),
|
|
).toBeVisible();
|
|
|
|
await page.getByRole("button", { name: "#E8E9EA" }).click();
|
|
await expect(page.getByTestId("colorpicker")).toBeVisible();
|
|
const handler = await page.getByTestId("ramp-handler");
|
|
await expect(handler).toBeVisible();
|
|
const saturation_selection = await page.getByTestId(
|
|
"value-saturation-selector",
|
|
);
|
|
await expect(saturation_selection).toBeVisible();
|
|
const saturation_box = await saturation_selection.boundingBox();
|
|
const handler_box = await handler.boundingBox();
|
|
await page.mouse.move(
|
|
handler_box.x + handler_box.width,
|
|
handler_box.y + handler_box.height / 2,
|
|
);
|
|
await page.mouse.down();
|
|
await page.mouse.move(
|
|
saturation_box.x + saturation_box.width / 2,
|
|
saturation_box.y + saturation_box.height / 2,
|
|
);
|
|
await page.mouse.up();
|
|
await expect(
|
|
workspacePage.palette.getByText(
|
|
"There are no color styles in your library yet",
|
|
),
|
|
).not.toBeVisible();
|
|
});
|
|
|
|
test("Bug 7489 - Workspace-palette items stay hidden when opening with keyboard-shortcut", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.goToWorkspace();
|
|
|
|
await workspacePage.clickTogglePalettesVisibility();
|
|
await workspacePage.page.keyboard.press("Alt+t");
|
|
|
|
await expect(
|
|
workspacePage.palette.getByText(
|
|
"There are no typography styles in your library yet",
|
|
),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("Bug 8784 - Use keyboard arrow to move inside a text input does not change tabs", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.goToWorkspace();
|
|
await workspacePage.pageName.click();
|
|
await page.keyboard.press("ArrowLeft");
|
|
|
|
await expect(workspacePage.pageName).toHaveText("Page 1");
|
|
});
|
|
|
|
test("Bug 9066 - Problem with grid layout", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-9066.json");
|
|
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-create-rect.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "e179d9df-de35-80bf-8005-283bbd5516b0",
|
|
pageId: "e179d9df-de35-80bf-8005-283bbd5516b1",
|
|
});
|
|
|
|
await workspacePage.clickToggableLayer("Board");
|
|
await workspacePage.clickToggableLayer("Group");
|
|
await page.getByText("A", { exact: true }).click();
|
|
|
|
await workspacePage.rightSidebar.getByTestId("component-pill-button").click();
|
|
|
|
await page.getByTitle("C", { exact: true }).click();
|
|
|
|
await expect(
|
|
page.getByTestId("children-6ad3e6b9-c5a0-80cf-8005-283bbe378bcb"),
|
|
).toHaveText(["CBCDEF"]);
|
|
});
|
|
|
|
test("User have toolbar", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.goToWorkspace();
|
|
|
|
await expect(page.getByTitle("toggle toolbar")).toBeVisible();
|
|
await expect(page.getByTitle("design")).toBeVisible();
|
|
});
|
|
|
|
test("User have edition menu entries", async ({ page }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.goToWorkspace();
|
|
|
|
await page.getByRole("button", { name: "Main menu" }).click();
|
|
await page.getByText("file").last().click();
|
|
|
|
await expect(page.getByText("Add as Shared Library")).toBeVisible();
|
|
|
|
await page.getByText("edit").click();
|
|
|
|
await expect(page.getByText("Undo")).toBeVisible();
|
|
await expect(page.getByText("Redo")).toBeVisible();
|
|
});
|
|
|
|
test("Copy/paste properties", async ({ page, context }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.mockRPC(
|
|
/get\-file\?/,
|
|
"workspace/get-file-copy-paste.json",
|
|
);
|
|
await workspacePage.mockRPC(
|
|
"get-file-fragment?file-id=*&fragment-id=*",
|
|
"workspace/get-file-copy-paste-fragment.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "870f9f10-87b5-8137-8005-934804124660",
|
|
pageId: "870f9f10-87b5-8137-8005-934804124661",
|
|
});
|
|
|
|
// Access to the read/write clipboard necesary for this functionality
|
|
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
|
|
|
await page.getByTestId("layer-item").getByRole("button").first().click();
|
|
await page
|
|
.getByTestId("children-0eef4dd0-b39b-807a-8005-934805578f93")
|
|
.getByText("Rectangle")
|
|
.click({ button: "right" });
|
|
await page.getByText("Copy/Paste as").hover();
|
|
await page.getByText("Copy properties").click();
|
|
|
|
await page
|
|
.getByTestId("layer-item")
|
|
.getByText("Uno dos tres cuatro")
|
|
.click({ button: "right" });
|
|
await page.getByText("Copy/Paste as").hover();
|
|
await page.getByText("Paste properties").click();
|
|
|
|
await page.getByText("Rectangle").first().click({ button: "right" });
|
|
await page.getByText("Copy/Paste as").hover();
|
|
await page.getByText("Paste properties").click();
|
|
|
|
await page.getByText("Board").nth(2).click({ button: "right" });
|
|
await page.getByText("Copy/Paste as").hover();
|
|
await page.getByText("Paste properties").click();
|
|
|
|
await page
|
|
.getByTestId("layer-item")
|
|
.locator("div")
|
|
.filter({ hasText: "Path" })
|
|
.nth(1)
|
|
.click({ button: "right" });
|
|
await page.getByText("Copy/Paste as").hover();
|
|
await page.getByText("Paste properties").click();
|
|
|
|
await page.getByText("Ellipse").click({ button: "right" });
|
|
await page.getByText("Copy/Paste as").hover();
|
|
await page.getByText("Paste properties").click();
|
|
});
|
|
|
|
test("[Taiga #9929] Paste text in workspace", async ({ page, context }) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.goToWorkspace();
|
|
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
|
await page.evaluate(() => navigator.clipboard.writeText("Lorem ipsum dolor"));
|
|
await workspacePage.viewport.click({ button: "right" });
|
|
await page.getByText(/^Paste/i).click();
|
|
await workspacePage.viewport
|
|
.getByRole("textbox")
|
|
.getByText("Lorem ipsum dolor");
|
|
});
|
|
|
|
// I've skipped this test because it doesn't make sense with the new render.
|
|
test.skip("[Taiga #9930] Zoom fit all doesn't fit all shapes", async ({
|
|
page,
|
|
context,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-9930.json");
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "8f843b59-7fbb-81ce-8005-aa6d47ae3111",
|
|
pageId: "fb9798e7-a547-80ae-8005-9ffda4a13e2c",
|
|
});
|
|
|
|
const zoom = page.getByTitle("Zoom");
|
|
await zoom.click();
|
|
|
|
const zoomIn = page.getByRole("button", { name: "Zoom in" });
|
|
await zoomIn.click();
|
|
await zoomIn.click();
|
|
await zoomIn.click();
|
|
|
|
// Zoom fit all
|
|
await page.keyboard.press("Shift+1");
|
|
// Select all shapes to display selrect
|
|
await workspacePage.page.keyboard.press("ControlOrMeta+a");
|
|
|
|
const ids = [
|
|
"shape-165d1e5a-5873-8010-8005-9ffdbeaeec59",
|
|
"shape-165d1e5a-5873-8010-8005-9ffdbeaf8d8a",
|
|
"shape-165d1e5a-5873-8010-8005-9ffdbeaf8d9e",
|
|
"shape-165d1e5a-5873-8010-8005-9ffdbeb053d9",
|
|
"shape-165d1e5a-5873-8010-8005-9ffdbeb09738",
|
|
"shape-165d1e5a-5873-8010-8005-9ffdbeb0f3fc",
|
|
];
|
|
|
|
function contains(container, contained) {
|
|
return (
|
|
container.x <= contained.x &&
|
|
container.y <= contained.y &&
|
|
container.width >= contained.width &&
|
|
container.height >= contained.height
|
|
);
|
|
}
|
|
|
|
const viewportBoundingBox = await workspacePage.viewport.boundingBox();
|
|
for (const id of ids) {
|
|
const shape = page.locator(`.viewport-selrect`);
|
|
const shapeBoundingBox = await shape.boundingBox();
|
|
expect(contains(viewportBoundingBox, shapeBoundingBox)).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test("Bug 9877, user navigation to dashboard from header goes to blank page", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
|
|
const popupPromise = page.waitForEvent("popup");
|
|
await page.getByText("Drafts").click();
|
|
|
|
const popup = await popupPromise;
|
|
await expect(popup).toHaveURL(
|
|
/&project-id=c7ce0794-0992-8105-8004-38e630f7920b/,
|
|
);
|
|
});
|
|
|
|
test("Bug 8371 - Flatten option is not visible in context menu", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.mockGetFile("workspace/get-file-8371.json");
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "7ce7750c-3efe-8009-8006-bf390a415df2",
|
|
pageId: "7ce7750c-3efe-8009-8006-bf390a415df3",
|
|
});
|
|
|
|
const shape = workspacePage.page.locator(
|
|
`[id="shape-40c555bd-1810-809a-8006-bf3912728203"]`,
|
|
);
|
|
|
|
await workspacePage.clickLeafLayer("Union");
|
|
await workspacePage.page
|
|
.locator(".viewport-selrect")
|
|
.click({ button: "right" });
|
|
await expect(workspacePage.contextMenuForShape).toBeVisible();
|
|
await expect(
|
|
workspacePage.contextMenuForShape
|
|
.getByText("Flatten")
|
|
// there are hidden elements in the context menu (in submenus) with "Flatten" text
|
|
.filter({ visible: true }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("BUG 13415 - Grid layout overlay is not removed when deleting a board", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile(page);
|
|
await workspacePage.mockGetFile("workspace/get-file-13415.json");
|
|
await workspacePage.mockRPC(
|
|
"update-file?id=*",
|
|
"workspace/update-file-13415.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
await workspacePage.clickLeafLayer("Board");
|
|
|
|
const currentRenderCount = await workspacePage.getRenderCount();
|
|
await workspacePage.page.keyboard.press("Delete");
|
|
|
|
await workspacePage.waitForNextRender(currentRenderCount);
|
|
await workspacePage.hideUI();
|
|
await expect(workspacePage.canvas).toHaveScreenshot();
|
|
});
|
|
|
|
test("BUG 13822 - Problems with z-index", async ({
|
|
page
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockGetFile("workspace/get-file-13822.json");
|
|
|
|
await workspacePage.goToWorkspace({
|
|
fileId: "7fd33337-c651-80ae-8007-c37410926e0f",
|
|
pageId: "af41758c-e196-8138-8007-c36f805c3f6d",
|
|
});
|
|
|
|
await workspacePage.waitForFirstRenderWithoutUI();
|
|
await expect(workspacePage.canvas).toHaveScreenshot();
|
|
});
|
|
|
|
test("BUG 14239 - Fix default path thickness", async ({
|
|
page
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC("update-file?id=*", "workspace/update-file-empty.json");
|
|
await workspacePage.goToWorkspace();
|
|
|
|
// (Workaround a bug in which mouse position can be nil and path editor crashes
|
|
// if we click on the Path tool without hovering over the viewport first)
|
|
await workspacePage.viewport.hover();
|
|
// 1. Draw a path
|
|
await workspacePage.pathButton.click();
|
|
await workspacePage.clickAt(779, 163);
|
|
await workspacePage.clickAt(951, 258);
|
|
// 2. Close it
|
|
await page.keyboard.press("Escape");
|
|
|
|
await expect(workspacePage.rightSidebar.getByRole("textbox", { name: "Stroke width" })).toHaveValue("1");
|
|
});
|
|
|
|
test("Bug 14250 - User with viewer role can select a locked board with a grid", async ({
|
|
page,
|
|
}) => {
|
|
const workspacePage = new WasmWorkspacePage(page);
|
|
await workspacePage.setupEmptyFile();
|
|
await workspacePage.mockRPC("get-teams", "get-teams-role-viewer.json");
|
|
await workspacePage.mockRPC(
|
|
/get\-file\?/,
|
|
"workspace/get-file-14250.json",
|
|
);
|
|
|
|
await workspacePage.goToWorkspace();
|
|
|
|
// Select the board from the layer tree to reveal its position
|
|
// on the canvas via the selection rectangle overlay
|
|
await workspacePage.clickLeafLayer("Locked Board with Grid");
|
|
await page.waitForSelector(".viewport-selrect");
|
|
|
|
// Get the selection rectangle bounding box (page coordinates)
|
|
// and calculate its center relative to the viewport element
|
|
const selrectBox = await page.locator(".viewport-selrect").boundingBox();
|
|
const viewportBox = await workspacePage.viewport.boundingBox();
|
|
|
|
const centerX = selrectBox.x + selrectBox.width / 2 - viewportBox.x;
|
|
const centerY = selrectBox.y + selrectBox.height / 2 - viewportBox.y;
|
|
|
|
// Deselect by pressing Escape
|
|
await page.keyboard.press("Escape");
|
|
|
|
// Click on the canvas at the board's center
|
|
await workspacePage.clickAt(centerX, centerY);
|
|
|
|
// Verify the board is now selected in the layers bar
|
|
await workspacePage.expectSelectedLayer("Locked Board with Grid");
|
|
});
|