diff --git a/frontend/playwright.config.js b/frontend/playwright.config.js index 09f33d68d1..e673f1da8f 100644 --- a/frontend/playwright.config.js +++ b/frontend/playwright.config.js @@ -1,4 +1,5 @@ import { defineConfig, devices } from "@playwright/test"; +import { platform } from "os"; /** * Read environment variables from file. @@ -6,6 +7,10 @@ import { defineConfig, devices } from "@playwright/test"; */ // require('dotenv').config(); +const userAgent = platform === 'darwin' ? + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" : + undefined; + /** * @see https://playwright.dev/docs/test-configuration */ @@ -43,12 +48,20 @@ export default defineConfig({ projects: [ { name: "default", - use: { ...devices["Desktop Chrome"] }, testDir: "./playwright/ui/specs", use: { + ...devices["Desktop Chrome"], + viewport: { width: 1920, height: 1080 }, // Add custom viewport size video: 'retain-on-failure', trace: 'retain-on-failure', - } + userAgent, + }, + snapshotPathTemplate: "{testDir}/{testFilePath}-snapshots/{arg}.png", + expect: { + toHaveScreenshot: { + maxDiffPixelRatio: 0.001, + }, + }, }, { name: "ds", diff --git a/frontend/playwright/data/workspace/create-file-object-thumbnail.json b/frontend/playwright/data/workspace/create-file-object-thumbnail.json new file mode 100644 index 0000000000..ffe22d334d --- /dev/null +++ b/frontend/playwright/data/workspace/create-file-object-thumbnail.json @@ -0,0 +1,7 @@ +{ + "~:file-id": "~u8d38942d-b01f-800e-8007-79ee6a9bac45", + "~:tag": "component", + "~:object-id": "8d38942d-b01f-800e-8007-79ee6a9bac45/8d38942d-b01f-800e-8007-79ee6a9bac46/6b68aedd-4c5b-80b9-8007-7b38c1d34ce4/component", + "~:media-id": "~ube2dc82e-615b-486b-a193-8768bdb51d7a", + "~:created-at": "~m1769523563389" +} \ No newline at end of file diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index 7947fb4368..a9d6e1d939 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -253,7 +253,7 @@ export class WorkspacePage extends BaseWebSocketPage { async #waitForWebSocketReadiness() { // TODO: find a better event to settle whether the app is ready to receive notifications via ws - await expect(this.pageName).toHaveText("Page 1"); + await expect(this.pageName).toHaveText("Page 1", { timeout: 30000 }) } async sendPresenceMessage(fixture) { @@ -383,19 +383,46 @@ export class WorkspacePage extends BaseWebSocketPage { await this.page.keyboard.press("T"); await this.page.waitForTimeout(timeToWait); await this.clickAndMove(x1, y1, x2, y2); - await this.page.waitForTimeout(timeToWait); + await expect(this.page.getByTestId("text-editor")).toBeVisible(); + if (initialText) { await this.page.keyboard.type(initialText); } } /** - * Copies the selected element into the clipboard. + * Copies the selected element into the clipboard, or copy the + * content of the locator into the clipboard. * * @returns {Promise} */ - async copy() { - return this.page.keyboard.press("Control+C"); + async copy(kind = "keyboard", locator = undefined) { + if (kind === "context-menu" && locator) { + await locator.click({ button: "right" }); + await this.page.getByText("Copy", { exact: true }).click(); + } else { + await this.page.keyboard.press("ControlOrMeta+C"); + } + // wait for the clipboard to be updated + await this.page.waitForFunction(async () => { + const content = await navigator.clipboard.readText() + return content !== ""; + }, { timeout: 1000 }); + } + + async cut(kind = "keyboard", locator = undefined) { + if (kind === "context-menu" && locator) { + await locator.click({ button: "right" }); + await this.page.getByText("Cut", { exact: true }).click(); + } else { + await this.page.keyboard.press("ControlOrMeta+X"); + } + // wait for the clipboard to be updated + await this.page.waitForFunction(async () => { + const content = await navigator.clipboard.readText() + return content !== ""; + }, { timeout: 1000 }); + } /** @@ -407,9 +434,9 @@ export class WorkspacePage extends BaseWebSocketPage { async paste(kind = "keyboard") { if (kind === "context-menu") { await this.viewport.click({ button: "right" }); - return this.page.getByText("PasteCtrlV").click(); + return this.page.getByText("Paste", { exact: true }).click(); } - return this.page.keyboard.press("Control+V"); + return this.page.keyboard.press("ControlOrMeta+V"); } async panOnViewportAt(x, y, width, height) { @@ -448,11 +475,11 @@ export class WorkspacePage extends BaseWebSocketPage { const layer = this.layers .getByTestId("layer-row") .filter({ hasText: name }); - const button = layer.getByRole("button"); + const button = layer.getByTestId("toggle-content"); - await button.waitFor(); + await expect(button).toBeVisible(); await button.click(clickOptions); - await this.page.waitForTimeout(500); + await button.waitFor({ ariaExpanded: true }); } async expectSelectedLayer(name) { @@ -495,13 +522,7 @@ export class WorkspacePage extends BaseWebSocketPage { async clickColorPalette(clickOptions = {}) { await this.palette - .getByRole("button", { name: "Color Palette (Alt+P)" }) - .click(clickOptions); - } - - async clickColorPalette(clickOptions = {}) { - await this.palette - .getByRole("button", { name: "Color Palette (Alt+P)" }) + .getByRole("button", { name: /Color Palette/ }) .click(clickOptions); } diff --git a/frontend/playwright/ui/specs/onboarding.spec.js b/frontend/playwright/ui/specs/onboarding.spec.js index b39c3b958b..a14b0abe42 100644 --- a/frontend/playwright/ui/specs/onboarding.spec.js +++ b/frontend/playwright/ui/specs/onboarding.spec.js @@ -15,6 +15,8 @@ test("User can complete the onboarding", async ({ page }) => { const dashboardPage = new DashboardPage(page); const onboardingPage = new OnboardingPage(page); + await dashboardPage.mockConfigFlags(["enable-onboarding"]); + await dashboardPage.goToDashboard(); await expect( page.getByRole("heading", { name: "Help us get to know you" }), diff --git a/frontend/playwright/ui/specs/render-wasm.spec.js b/frontend/playwright/ui/specs/render-wasm.spec.js index d8b72d13be..1c336bf6a8 100644 --- a/frontend/playwright/ui/specs/render-wasm.spec.js +++ b/frontend/playwright/ui/specs/render-wasm.spec.js @@ -1,5 +1,5 @@ import { test, expect } from "@playwright/test"; -import { WasmWorkspacePage, WASM_FLAGS } from "../pages/WasmWorkspacePage"; +import { WasmWorkspacePage } from "../pages/WasmWorkspacePage"; test.beforeEach(async ({ page }) => { await WasmWorkspacePage.init(page); diff --git a/frontend/playwright/ui/specs/text-editor-v2.spec.js b/frontend/playwright/ui/specs/text-editor-v2.spec.js index 9651c8e4b4..299430fad1 100644 --- a/frontend/playwright/ui/specs/text-editor-v2.spec.js +++ b/frontend/playwright/ui/specs/text-editor-v2.spec.js @@ -5,7 +5,7 @@ import { WorkspacePage } from "../pages/WorkspacePage"; const timeToWait = 100; test.beforeEach(async ({ page, context }) => { - await Clipboard.enable(context, Clipboard.Permission.ONLY_WRITE); + await Clipboard.enable(context, Clipboard.Permission.ALL); await WorkspacePage.init(page); await WorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]); diff --git a/frontend/playwright/ui/specs/variants.spec.js b/frontend/playwright/ui/specs/variants.spec.js index 26c083239d..51eafa2156 100644 --- a/frontend/playwright/ui/specs/variants.spec.js +++ b/frontend/playwright/ui/specs/variants.spec.js @@ -1,12 +1,19 @@ import { test, expect } from "@playwright/test"; -import { WorkspacePage } from "../pages/WorkspacePage"; +import { WorkspacePage } from "../pages/WorkspacePage"; import { BaseWebSocketPage } from "../pages/BaseWebSocketPage"; +import { Clipboard } from "../../helpers/Clipboard"; + +test.beforeEach(async ({ page, context }) => { + await Clipboard.enable(context, Clipboard.Permission.ALL); -test.beforeEach(async ({ page }) => { await WorkspacePage.init(page); await BaseWebSocketPage.mockRPC(page, "get-teams", "get-teams-variants.json"); }); +test.afterEach(async ({ context }) => { + context.clearPermissions(); +}); + const setupVariantsFile = async (workspacePage) => { await workspacePage.setupEmptyFile(); await workspacePage.mockRPC( @@ -34,9 +41,9 @@ const setupVariantsFileWithVariant = async (workspacePage) => { await setupVariantsFile(workspacePage); await workspacePage.clickLeafLayer("Rectangle"); - await workspacePage.page.keyboard.press("Control+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); await workspacePage.page.waitForTimeout(500); - await workspacePage.page.keyboard.press("Control+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); await workspacePage.page.waitForTimeout(500); // We wait until layer-row starts looking like it an component @@ -156,7 +163,7 @@ test("User duplicates a variant container", async ({ page }) => { await variant.container.click(); //Duplicate the variant container - await workspacePage.page.keyboard.press("Control+d"); + await workspacePage.page.keyboard.press("ControlOrMeta+d"); const variant_original = await findVariant(workspacePage, 1); // On duplicate, the new item is the first const variant_duplicate = await findVariant(workspacePage, 0); @@ -169,25 +176,27 @@ test("User duplicates a variant container", async ({ page }) => { await validateVariant(variant_duplicate); }); -test("User copy paste a variant container", async ({ page }) => { +test("User copy paste a variant container", async ({ page, context }) => { const workspacePage = new WorkspacePage(page); + // Access to the read/write clipboard necesary for this functionality await setupVariantsFileWithVariant(workspacePage); + await workspacePage.mockRPC( + /create-file-object-thumbnail.*/, + "workspace/create-file-object-thumbnail.json", + ); const variant = findVariantNoWait(workspacePage, 0); - // await variant.container.waitFor(); - - // Select the variant container - await variant.container.click(); - - await workspacePage.page.waitForTimeout(1000); - // Copy the variant container - await workspacePage.page.keyboard.press("Control+c"); + await workspacePage.clickLeafLayer("Rectangle"); + await workspacePage.copy("keyboard"); // Paste the variant container await workspacePage.clickAt(400, 400); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); + + const variants = workspacePage.layers.getByText("Rectangle"); + await expect(variants).toHaveCount(2); const variantDuplicate = findVariantNoWait(workspacePage, 0); const variantOriginal = findVariantNoWait(workspacePage, 1); @@ -212,18 +221,17 @@ test("User cut paste a variant container", async ({ page }) => { await variant.container.click(); //Cut the variant container - await workspacePage.page.keyboard.press("Control+x"); - await workspacePage.page.waitForTimeout(500); + await workspacePage.cut("keyboard"); //Paste the variant container await workspacePage.clickAt(500, 500); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); await workspacePage.page.waitForTimeout(500); const variantPasted = await findVariant(workspacePage, 0); // Expand the layers - await variantPasted.container.locator("button").first().click(); + await workspacePage.clickToggableLayer("Rectangle"); // The variants are valid await validateVariant(variantPasted); @@ -239,27 +247,34 @@ test("User cut paste a variant container into a board, and undo twice", async ({ //Create a board await workspacePage.boardButton.click(); - await workspacePage.clickWithDragViewportAt(500, 500, 100, 100); + // NOTE: this board should not intersect the existing variants, otherwise + // this test is flaky + await workspacePage.clickWithDragViewportAt(200, 200, 100, 100); await workspacePage.clickAt(495, 495); const board = await workspacePage.rootShape.locator("Board"); // Select the variant container - await variant.container.click(); + // await variant.container.click(); + await workspacePage.clickLeafLayer("Rectangle"); //Cut the variant container - await workspacePage.page.keyboard.press("Control+x"); - await workspacePage.page.waitForTimeout(500); + await workspacePage.cut("keyboard"); + await expect(variant.container).not.toBeVisible(); //Select the board await workspacePage.clickLeafLayer("Board"); //Paste the variant container inside the board - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); + await expect(variant.container).toBeVisible(); //Undo twice - await workspacePage.page.keyboard.press("Control+z"); - await workspacePage.page.keyboard.press("Control+z"); - await workspacePage.page.waitForTimeout(500); + await workspacePage.page.keyboard.press("ControlOrMeta+z"); + + await expect(variant.container).not.toBeVisible(); + + await workspacePage.page.keyboard.press("ControlOrMeta+z"); + await expect(variant.container).toBeVisible(); const variantAfterUndo = await findVariant(workspacePage, 0); @@ -276,12 +291,12 @@ test("User copy paste a variant", async ({ page }) => { // Select the variant1 await variant.variant1.click(); - //Cut the variant - await workspacePage.page.keyboard.press("Control+c"); + // Copy the variant + await workspacePage.copy("keyboard"); - //Paste the variant + // Paste the variant await workspacePage.clickAt(500, 500); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); const copy = await workspacePage.layers .getByTestId("layer-row") @@ -302,11 +317,11 @@ test("User cut paste a variant outside the container", async ({ page }) => { await variant.variant1.click(); //Cut the variant - await workspacePage.page.keyboard.press("Control+x"); + await workspacePage.cut("keyboard"); //Paste the variant await workspacePage.clickAt(500, 500); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); const component = await workspacePage.layers .getByTestId("layer-row") @@ -324,15 +339,11 @@ test("User drag and drop a variant outside the container", async ({ page }) => { const variant = await findVariant(workspacePage, 0); // Drag and drop the variant - await workspacePage.clickWithDragViewportAt(350, 400, 0, 200); + // FIXME: to make this test more resilient, we should get the bounding box of the Value 1 variant + // and use it to calculate the target position + await workspacePage.clickWithDragViewportAt(600, 500, 0, 300); - const component = await workspacePage.layers - .getByTestId("layer-row") - .filter({ has: workspacePage.page.getByText("Rectangle / Value 1") }) - .filter({ has: workspacePage.page.getByTestId("icon-component") }); - - //The component exists and is visible - await expect(component).toBeVisible(); + await expect(workspacePage.layers.getByText("Rectangle / Value 1")).toBeVisible(); }); test("User cut paste a component inside a variant", async ({ page }) => { @@ -345,14 +356,14 @@ test("User cut paste a component inside a variant", async ({ page }) => { await workspacePage.ellipseShapeButton.click(); await workspacePage.clickWithDragViewportAt(500, 500, 20, 20); await workspacePage.clickLeafLayer("Ellipse"); - await workspacePage.page.keyboard.press("Control+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); //Cut the component - await workspacePage.page.keyboard.press("Control+x"); + await workspacePage.cut("keyboard"); //Paste the component inside the variant await variant.container.click(); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); const variant3 = await workspacePage.layers .getByTestId("layer-row") @@ -376,7 +387,7 @@ test("User cut paste a component with path inside a variant", async ({ await workspacePage.ellipseShapeButton.click(); await workspacePage.clickWithDragViewportAt(500, 500, 20, 20); await workspacePage.clickLeafLayer("Ellipse"); - await workspacePage.page.keyboard.press("Control+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); //Rename the component await workspacePage.layers.getByText("Ellipse").dblclick(); @@ -387,11 +398,11 @@ test("User cut paste a component with path inside a variant", async ({ await workspacePage.page.keyboard.press("Enter"); //Cut the component - await workspacePage.page.keyboard.press("Control+x"); + await workspacePage.cut("keyboard"); //Paste the component inside the variant await variant.container.click(); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); const variant3 = await workspacePage.layers .getByTestId("layer-row") @@ -415,7 +426,7 @@ test("User drag and drop a component with path inside a variant", async ({ await workspacePage.ellipseShapeButton.click(); await workspacePage.clickWithDragViewportAt(500, 500, 20, 20); await workspacePage.clickLeafLayer("Ellipse"); - await workspacePage.page.keyboard.press("Control+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); //Rename the component await workspacePage.layers.getByText("Ellipse").dblclick(); @@ -426,7 +437,7 @@ test("User drag and drop a component with path inside a variant", async ({ await workspacePage.page.keyboard.press("Enter"); //Drag and drop the component the component - await workspacePage.clickWithDragViewportAt(510, 510, 0, -200); + await workspacePage.clickWithDragViewportAt(510, 510, 200, 0); const variant3 = await workspacePage.layers .getByTestId("layer-row") @@ -446,8 +457,8 @@ test("User cut paste a variant into another container", async ({ page }) => { await workspacePage.ellipseShapeButton.click(); await workspacePage.clickWithDragViewportAt(500, 500, 20, 20); await workspacePage.clickLeafLayer("Ellipse"); - await workspacePage.page.keyboard.press("Control+k"); - await workspacePage.page.keyboard.press("Control+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); + await workspacePage.page.keyboard.press("ControlOrMeta+k"); const variantOrigin = await findVariantNoWait(workspacePage, 1); @@ -457,11 +468,11 @@ test("User cut paste a variant into another container", async ({ page }) => { await variantOrigin.variant1.click(); //Cut the variant - await workspacePage.page.keyboard.press("Control+x"); + await workspacePage.cut("keyboard"); //Paste the variant await workspacePage.layers.getByText("Ellipse").first().click(); - await workspacePage.page.keyboard.press("Control+v"); + await workspacePage.paste("keyboard"); const variant3 = workspacePage.layers .getByTestId("layer-row") diff --git a/frontend/playwright/ui/specs/workspace.spec.js b/frontend/playwright/ui/specs/workspace.spec.js index 8489cf122f..8d13802a97 100644 --- a/frontend/playwright/ui/specs/workspace.spec.js +++ b/frontend/playwright/ui/specs/workspace.spec.js @@ -1,13 +1,13 @@ import { test, expect } from "@playwright/test"; -import { WorkspacePage } from "../pages/WorkspacePage"; +import { WasmWorkspacePage } from "../pages/WasmWorkspacePage"; import { presenceFixture } from "../../data/workspace/ws-notifications"; test.beforeEach(async ({ page }) => { - await WorkspacePage.init(page); + await WasmWorkspacePage.init(page); }); test("User loads worskpace with empty file", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.goToWorkspace(); @@ -16,7 +16,7 @@ test("User loads worskpace with empty file", async ({ page }) => { }); test("User opens a file with a bad page id", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.goToWorkspace({ @@ -29,7 +29,7 @@ test("User opens a file with a bad page id", async ({ page }) => { test("User receives presence notifications updates in the workspace", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.goToWorkspace(); @@ -41,7 +41,7 @@ test("User receives presence notifications updates in the workspace", async ({ }); test("User draws a rect", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.mockRPC( "update-file?id=*", @@ -52,13 +52,12 @@ test("User draws a rect", async ({ page }) => { await workspacePage.rectShapeButton.click(); await workspacePage.clickWithDragViewportAt(128, 128, 200, 100); - const shape = await workspacePage.rootShape.locator("rect"); - await expect(shape).toHaveAttribute("width", "200"); - await expect(shape).toHaveAttribute("height", "100"); + await workspacePage.hideUI(); + await expect(workspacePage.canvas).toHaveScreenshot(); }); test("User makes a group", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.mockRPC( /get\-file\?/, @@ -74,14 +73,14 @@ test("User makes a group", async ({ page }) => { pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375", }); await workspacePage.clickLeafLayer("Rectangle"); - await workspacePage.page.keyboard.press("Control+g"); + 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 WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.goToWorkspace(); @@ -91,10 +90,10 @@ test("Bug 7654 - Toolbar keeps toggling on and off on spacebar press", async ({ await workspacePage.expectHiddenToolbarOptions(); }); -test("Bug 7525 - User moves a scrollbar and no selciont rectangle appears", async ({ +test("Bug 7525 - User moves a scrollbar and no selection rectangle appears", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.mockRPC( /get\-file\?/, @@ -110,8 +109,8 @@ test("Bug 7525 - User moves a scrollbar and no selciont rectangle appears", asyn pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375", }); - // Move created rect to a corner, in orther to get scrollbars - await workspacePage.panOnViewportAt(128, 128, 300, 300); + // 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; @@ -130,7 +129,7 @@ test("Bug 7525 - User moves a scrollbar and no selciont rectangle appears", asyn test("User adds a library and its automatically selected in the color palette", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.mockRPC( "link-file-to-library", @@ -175,7 +174,7 @@ test("User adds a library and its automatically selected in the color palette", test("Bug 10179 - Drag & drop doesn't add colors to the Recent Colors palette", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.goToWorkspace(); await workspacePage.moveButton.click(); @@ -218,7 +217,7 @@ test("Bug 10179 - Drag & drop doesn't add colors to the Recent Colors palette", test("Bug 7489 - Workspace-palette items stay hidden when opening with keyboard-shortcut", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.goToWorkspace(); @@ -235,7 +234,7 @@ test("Bug 7489 - Workspace-palette items stay hidden when opening with keyboard- test("Bug 8784 - Use keyboard arrow to move inside a text input does not change tabs", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(); await workspacePage.goToWorkspace(); await workspacePage.pageName.click(); @@ -245,7 +244,7 @@ test("Bug 8784 - Use keyboard arrow to move inside a text input does not change }); test("Bug 9066 - Problem with grid layout", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-9066.json"); @@ -273,7 +272,7 @@ test("Bug 9066 - Problem with grid layout", async ({ page }) => { }); test("User have toolbar", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.goToWorkspace(); @@ -282,7 +281,7 @@ test("User have toolbar", async ({ page }) => { }); test("User have edition menu entries", async ({ page }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.goToWorkspace(); @@ -298,7 +297,7 @@ test("User have edition menu entries", async ({ page }) => { }); test("Copy/paste properties", async ({ page, context }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.mockRPC( /get\-file\?/, @@ -355,23 +354,23 @@ test("Copy/paste properties", async ({ page, context }) => { }); test("[Taiga #9929] Paste text in workspace", async ({ page, context }) => { - const workspacePage = new WorkspacePage(page); + 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("PasteCtrlV").click(); + await page.getByText(/^Paste/i).click(); await workspacePage.viewport .getByRole("textbox") .getByText("Lorem ipsum dolor"); }); -test("[Taiga #9930] Zoom fit all doesn't fits all", async ({ +test("[Taiga #9930] Zoom fit all doesn't fit all shapes", async ({ page, context, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-9930.json"); await workspacePage.goToWorkspace({ @@ -379,16 +378,18 @@ test("[Taiga #9930] Zoom fit all doesn't fits all", async ({ pageId: "fb9798e7-a547-80ae-8005-9ffda4a13e2c", }); - const zoom = await page.getByTitle("Zoom"); + const zoom = page.getByTitle("Zoom"); await zoom.click(); - const zoomIn = await page.getByRole("button", { name: "Zoom in" }); + 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", @@ -410,7 +411,7 @@ test("[Taiga #9930] Zoom fit all doesn't fits all", async ({ const viewportBoundingBox = await workspacePage.viewport.boundingBox(); for (const id of ids) { - const shape = await page.locator(`.ws-shape-wrapper > g#${id}`); + const shape = page.locator(`.viewport-selrect`); const shapeBoundingBox = await shape.boundingBox(); expect(contains(viewportBoundingBox, shapeBoundingBox)).toBeTruthy(); } @@ -419,7 +420,7 @@ test("[Taiga #9930] Zoom fit all doesn't fits all", async ({ test("Bug 9877, user navigation to dashboard from header goes to blank page", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.goToWorkspace(); @@ -436,7 +437,7 @@ test("Bug 9877, user navigation to dashboard from header goes to blank page", as test("Bug 8371 - Flatten option is not visible in context menu", async ({ page, }) => { - const workspacePage = new WorkspacePage(page); + const workspacePage = new WasmWorkspacePage(page); await workspacePage.setupEmptyFile(page); await workspacePage.mockGetFile("workspace/get-file-8371.json"); await workspacePage.goToWorkspace({ diff --git a/frontend/playwright/ui/specs/workspace.spec.js-snapshots/User-draws-a-rect-1.png b/frontend/playwright/ui/specs/workspace.spec.js-snapshots/User-draws-a-rect-1.png new file mode 100644 index 0000000000..fa630d5164 Binary files /dev/null and b/frontend/playwright/ui/specs/workspace.spec.js-snapshots/User-draws-a-rect-1.png differ diff --git a/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs b/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs index e3b3104fa8..0a317d7339 100644 --- a/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs +++ b/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs @@ -21,7 +21,7 @@ (def ^:private schema:properties-row [:map [:term :string] - [:detail :string] + [:detail {:optional true} [:maybe :string]] [:property {:optional true} :string] ;; CSS valid property [:token {:optional true} :any] ;; resolved token object [:copiable {:optional true} :boolean]]) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs index 909ba2eca7..98e82162e2 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs @@ -401,7 +401,8 @@ (dm/fmt "scale(%)" maybe-zoom))}))] [:g.text-editor {:clip-path (dm/fmt "url(#%)" clip-id) - :transform (dm/str transform)} + :transform (dm/str transform) + :data-testid "text-editor"} [:defs [:clipPath {:id clip-id} [:rect {:x x :y y :width width :height height}]]] diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index 5b1d42c50e..d65b1cbfc8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -119,6 +119,9 @@ [:button {:class (stl/css-case :toggle-content true :inverse expanded?) + :data-testid "toggle-content" + :aria-expanded expanded? + :aria-labelledby (dm/str "layer-name-" id) :on-click on-toggle-collapse} deprecated-icon/arrow]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_name.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_name.cljs index 642b3d27f5..ffe019638d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_name.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_name.cljs @@ -108,6 +108,7 @@ :on-blur accept-edit :on-key-down on-key-down :auto-focus true + :id (dm/str "layer-name-" shape-id) :default-value (d/nilv default-value "")}] [:* [:span @@ -118,6 +119,7 @@ :hidden is-hidden :type-comp type-comp :type-frame type-frame) + :id (dm/str "layer-name-" shape-id) :style {"--depth" depth "--parent-size" parent-size} :ref ref :on-double-click start-edit}