🔧 Fix broken / flaky tests

This commit is contained in:
Belén Albeza
2026-01-26 16:46:31 +01:00
parent daedc660b9
commit e3b97638b4
7 changed files with 116 additions and 62 deletions

View File

@@ -1,4 +1,5 @@
import { defineConfig, devices } from "@playwright/test";
import { platform } from "os";
/**
* Read environment variables from file.
@@ -6,6 +7,9 @@ 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' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" : undefined;
/**
* @see https://playwright.dev/docs/test-configuration
*/
@@ -49,6 +53,7 @@ export default defineConfig({
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: {

View File

@@ -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"
}

View File

@@ -390,12 +390,38 @@ export class WorkspacePage extends BaseWebSocketPage {
}
/**
* 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<void>}
*/
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 });
}
/**
@@ -448,11 +474,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) {

View File

@@ -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")

View File

@@ -90,7 +90,7 @@ 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 WasmWorkspacePage(page);
@@ -109,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;

View File

@@ -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])

View File

@@ -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}