Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh
2025-10-31 12:13:29 +01:00
62 changed files with 1089 additions and 330 deletions

View File

@@ -0,0 +1,31 @@
import { test, expect } from "@playwright/test";
import DashboardPage from "../pages/DashboardPage";
test.beforeEach(async ({ page }) => {
await DashboardPage.init(page);
await DashboardPage.mockRPC(
page,
"get-profile",
"logged-in-user/get-profile-logged-in-no-onboarding.json",
);
});
test("BUG 12359 - Selected invitations count is not pluralized", async ({
page,
}) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await dashboardPage.setupTeamInvitations();
await dashboardPage.goToSecondTeamInvitationsSection();
await expect(page.getByText("test1@mail.com")).toBeVisible();
// NOTE: we cannot use check() or getByLabel() because the checkbox
// is hidden inside the label.
await page.getByText("test1@mail.com").click();
await expect(page.getByText("1 invitation selected")).toBeVisible();
await page.getByText("test2@mail.com").check();
await expect(page.getByText("2 invitations selected")).toBeVisible();
});

View File

@@ -320,3 +320,50 @@ test("BUG 12287 Fix identical text fills not being added/removed", async ({
workspace.page.getByRole("button", { name: "#B1B2B5" }),
).toHaveCount(3);
});
test("BUG 12384 - Export crashing when exporting a board", async ({ page }) => {
const workspace = new WorkspacePage(page);
await workspace.setupEmptyFile();
await workspace.mockRPC(/get\-file\?/, "design/get-file-12384.json");
let hasExportRequestBeenIntercepted = false;
await workspace.page.route("**/api/export", (route) => {
if (hasExportRequestBeenIntercepted) {
route.continue();
return;
}
hasExportRequestBeenIntercepted = true;
const payload = route.request().postData();
const parsedPayload = JSON.parse(payload);
expect(parsedPayload["~:exports"]).toHaveLength(1);
expect(parsedPayload["~:exports"][0]["~:file-id"]).toBe(
"~ufa6ce865-34dd-80ac-8006-fe0dab5539a7",
);
expect(parsedPayload["~:exports"][0]["~:page-id"]).toBe(
"~ufa6ce865-34dd-80ac-8006-fe0dab5539a8",
);
route.fulfill({
status: 200,
contentType: "application/json",
response: {},
});
});
await workspace.goToWorkspace({
fileId: "fa6ce865-34dd-80ac-8006-fe0dab5539a7",
pageId: "fa6ce865-34dd-80ac-8006-fe0dab5539a8",
});
await workspace.clickLeafLayer("Board");
let exportRequest = workspace.page.waitForRequest("**/api/export");
await workspace.rightSidebar
.getByRole("button", { name: "Export 1 element" })
.click();
await exportRequest;
});

View File

@@ -101,6 +101,24 @@ const setupTypographyTokensFile = async (page, options = {}) => {
});
};
const checkInputFieldWithError = async (tokenThemeUpdateCreateModal, inputLocator) => {
await expect(inputLocator).toHaveAttribute("aria-invalid", "true");
const errorMessageId = await inputLocator.getAttribute("aria-describedby");
await expect(
tokenThemeUpdateCreateModal.locator(`#${errorMessageId}`),
).toBeVisible();
};
const checkInputFieldWithoutError = async (tokenThemeUpdateCreateModal, inputLocator) => {
expect(
await inputLocator.getAttribute("aria-invalid")
).toBeNull();
expect(
await inputLocator.getAttribute("aria-describedby")
).toBeNull();
};
test.describe("Tokens: Tokens Tab", () => {
test("Clicking tokens tab button opens tokens sidebar tab", async ({
page,
@@ -812,18 +830,25 @@ test.describe("Tokens: Themes modal", () => {
})
.click();
await tokenThemeUpdateCreateModal
.getByLabel("Group")
.fill("New Group name");
await tokenThemeUpdateCreateModal
.getByLabel("Theme")
.fill("New Theme name");
const groupInput = tokenThemeUpdateCreateModal.getByLabel("Group");
const nameInput = tokenThemeUpdateCreateModal.getByLabel("Theme");
const saveButton = tokenThemeUpdateCreateModal.getByRole("button", {
name: "Save theme",
});
await groupInput.fill("Core"); // Invalid because "Core / Light" theme already exists
await nameInput.fill("Light");
await tokenThemeUpdateCreateModal
.getByRole("button", {
name: "Save theme",
})
.click();
await checkInputFieldWithError(tokenThemeUpdateCreateModal, nameInput);
await expect(saveButton).toBeDisabled();
await groupInput.fill("New Group name");
await nameInput.fill("New Theme name");
await checkInputFieldWithoutError(tokenThemeUpdateCreateModal, nameInput);
await expect(saveButton).not.toBeDisabled();
await saveButton.click();
await expect(
tokenThemeUpdateCreateModal.getByText("New Theme name"),
@@ -851,12 +876,36 @@ test.describe("Tokens: Themes modal", () => {
.first()
.click();
await tokenThemeUpdateCreateModal
.getByLabel("Theme")
.fill("Changed Theme name");
await tokenThemeUpdateCreateModal
.getByLabel("Group")
.fill("Changed Group name");
const groupInput = tokenThemeUpdateCreateModal.getByLabel("Group");
const nameInput = tokenThemeUpdateCreateModal.getByLabel("Theme");
const saveButton = tokenThemeUpdateCreateModal.getByRole("button", {
name: "Save theme",
});
await groupInput.fill("Core"); // Invalid because "Core / Dark" theme already exists
await nameInput.fill("Dark");
await checkInputFieldWithError(tokenThemeUpdateCreateModal, nameInput);
await expect(saveButton).toBeDisabled();
await groupInput.fill("Core"); // Valid because "Core / Light" theme already exists
await nameInput.fill("Light"); // but it's the same theme we are editing
await checkInputFieldWithoutError(tokenThemeUpdateCreateModal, nameInput);
await expect(saveButton).not.toBeDisabled();
await nameInput.fill("Changed Theme name"); // New names should be also valid
await groupInput.fill("Changed Group name");
await checkInputFieldWithoutError(tokenThemeUpdateCreateModal, nameInput);
await expect(saveButton).not.toBeDisabled();
expect(
await nameInput.getAttribute("aria-invalid")
).toBeNull();
expect(
await nameInput.getAttribute("aria-describedby")
).toBeNull();
const checkboxes = await tokenThemeUpdateCreateModal
.locator('[role="checkbox"]')
@@ -876,11 +925,9 @@ test.describe("Tokens: Themes modal", () => {
await firstButton.click();
await tokenThemeUpdateCreateModal
.getByRole("button", {
name: "Save theme",
})
.click();
await expect(saveButton).not.toBeDisabled();
await saveButton.click();
await expect(
tokenThemeUpdateCreateModal.getByText("Changed Theme name"),

View File

@@ -150,8 +150,8 @@ test("User copy paste a variant container", async ({ page }) => {
await workspacePage.clickAt(500, 500);
await workspacePage.page.keyboard.press("Control+v");
const variant_original = await findVariant(workspacePage, 0);
const variant_duplicate = await findVariant(workspacePage, 1);
const variant_original = await findVariant(workspacePage, 1);
const variant_duplicate = await findVariant(workspacePage, 0);
// Expand the layers
await variant_duplicate.container.getByRole("button").first().click();