mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
1425 lines
48 KiB
JavaScript
1425 lines
48 KiB
JavaScript
import { test, expect } from "@playwright/test";
|
|
import { BaseWebSocketPage } from "../../pages/BaseWebSocketPage";
|
|
import { WasmWorkspacePage } from "../../pages/WasmWorkspacePage";
|
|
import {
|
|
setupTokensFileRender,
|
|
setupTypographyTokensFileRender,
|
|
unfoldTokenType,
|
|
createToken,
|
|
} from "./helpers";
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await WasmWorkspacePage.init(page);
|
|
await BaseWebSocketPage.mockRPC(page, "get-teams", "get-teams-tokens.json");
|
|
});
|
|
|
|
test.describe("Tokens: Apply token", () => {
|
|
test("User applies color token to a shape", async ({ page }) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.filter({ hasText: "Button" })
|
|
.click();
|
|
|
|
await page.getByRole("tab", { name: "Tokens" }).click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "color");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "black" })
|
|
.click({ button: "right" });
|
|
await tokenContextMenuForToken.getByText("Fill").click();
|
|
|
|
await expect(
|
|
workspacePage.page.getByLabel("Name: colors.black"),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("User applies border-radius token to a shape from sidebar", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
// Open tokens sections on left sidebar
|
|
|
|
await page.getByRole("tab", { name: "Tokens" }).click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "border radius");
|
|
await expect(
|
|
tokensSidebar.getByRole("button", {
|
|
name: "borderRadius.sm",
|
|
exact: true,
|
|
}),
|
|
).toBeVisible();
|
|
|
|
// Apply border radius token from token panels
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "borderRadius.sm" })
|
|
.click();
|
|
|
|
// Check if border radius sections is visible on right sidebar
|
|
const borderRadiusSection = page.getByRole("region", {
|
|
name: "Border radius section",
|
|
});
|
|
await expect(borderRadiusSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const brTokenPillSM = borderRadiusSection.getByRole("button", {
|
|
name: "borderRadius.sm",
|
|
});
|
|
await expect(brTokenPillSM).toBeVisible();
|
|
await brTokenPillSM.click();
|
|
|
|
// Change token from dropdown
|
|
const brTokenOptionXl = borderRadiusSection.getByRole("option", {
|
|
name: "borderRadius.xl",
|
|
});
|
|
await expect(brTokenOptionXl).toBeVisible();
|
|
await brTokenOptionXl.click();
|
|
|
|
await expect(brTokenPillSM).not.toBeVisible();
|
|
const brTokenPillXL = borderRadiusSection.getByRole("button", {
|
|
name: "borderRadius.xl",
|
|
});
|
|
await expect(brTokenPillXL).toBeVisible();
|
|
|
|
// Detach token from design tab on right sidebar
|
|
const detachButton = borderRadiusSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.click();
|
|
await expect(brTokenPillXL).not.toBeVisible();
|
|
});
|
|
|
|
test("User applies opacity token to a shape from sidebar", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
// Open tokens sections on left sidebar
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
// Unfold opacity tokens
|
|
await unfoldTokenType(tokensSidebar, "opacity");
|
|
await expect(
|
|
tokensSidebar.getByRole("button", { name: "opacity.high" }),
|
|
).toBeVisible();
|
|
|
|
// Apply opacity token from token panels
|
|
await tokensSidebar.getByRole("button", { name: "opacity.high" }).click();
|
|
|
|
// Check if opacity sections is visible on right sidebar
|
|
const layerMenuSection = page.getByRole("region", {
|
|
name: "Layer menu section",
|
|
});
|
|
await expect(layerMenuSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const opacityHighPill = layerMenuSection.getByRole("button", {
|
|
name: "opacity.high",
|
|
});
|
|
await expect(opacityHighPill).toBeVisible();
|
|
|
|
// Detach token from design tab on right sidebar
|
|
const detachButton = layerMenuSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.click();
|
|
|
|
// Open dropdown from input
|
|
const dropdownBtn = layerMenuSection.getByRole("button", {
|
|
name: "Open token list",
|
|
});
|
|
await expect(dropdownBtn).toBeVisible();
|
|
await dropdownBtn.click();
|
|
|
|
// Change token from dropdown
|
|
const opacityLowOption = layerMenuSection.getByRole("option", {
|
|
name: "opacity.low",
|
|
});
|
|
await expect(opacityLowOption).toBeVisible();
|
|
await opacityLowOption.click();
|
|
|
|
await expect(opacityHighPill).not.toBeVisible();
|
|
const opacityLowPill = layerMenuSection.getByRole("button", {
|
|
name: "opacity.low",
|
|
});
|
|
await expect(opacityLowPill).toBeVisible();
|
|
});
|
|
|
|
test("User applies typography token to a text shape", async ({ page }) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTypographyTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.filter({ hasText: "Some Text" })
|
|
.click();
|
|
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
await tokensSidebar
|
|
.getByRole("button")
|
|
.filter({ hasText: "Typography" })
|
|
.click();
|
|
|
|
await tokensSidebar.getByRole("button", { name: "Full" }).click();
|
|
|
|
const fontSizeInput = workspacePage.rightSidebar.getByRole("textbox", {
|
|
name: "Font Size",
|
|
});
|
|
await expect(fontSizeInput).toBeVisible();
|
|
await expect(fontSizeInput).toHaveValue("100");
|
|
});
|
|
|
|
test("User adds shadow token with multiple shadows and applies it to shape", async ({
|
|
page,
|
|
}) => {
|
|
const { tokensUpdateCreateModal, tokensSidebar, workspacePage } =
|
|
await setupTokensFileRender(page, { flags: ["enable-token-shadow"] });
|
|
|
|
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
|
|
|
await test.step("Stage 1: Basic open", async () => {
|
|
// User adds shadow via the sidebar
|
|
await tokensTabPanel
|
|
.getByRole("button", { name: "Add Token: Shadow" })
|
|
.click();
|
|
|
|
await expect(tokensUpdateCreateModal).toBeVisible();
|
|
|
|
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
|
await nameField.fill("primary");
|
|
|
|
// User adds first shadow with a color from the color ramp
|
|
const firstShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-0",
|
|
);
|
|
await expect(firstShadowFields).toBeVisible();
|
|
|
|
// Fill in the shadow values
|
|
const offsetXInput = firstShadowFields.getByRole("textbox", {
|
|
name: "X",
|
|
});
|
|
const offsetYInput = firstShadowFields.getByRole("textbox", {
|
|
name: "Y",
|
|
});
|
|
const blurInput = firstShadowFields.getByRole("textbox", {
|
|
name: "Blur",
|
|
});
|
|
const spreadInput = firstShadowFields.getByRole("textbox", {
|
|
name: "Spread",
|
|
});
|
|
|
|
await offsetXInput.fill("2");
|
|
await offsetYInput.fill("2");
|
|
await blurInput.fill("4");
|
|
await spreadInput.fill("0");
|
|
|
|
// Add color using the color picker
|
|
const colorBullet = firstShadowFields.getByTestId(
|
|
"token-form-color-bullet",
|
|
);
|
|
await colorBullet.click();
|
|
|
|
// Click on the color ramp to select a color
|
|
const valueSaturationSelector = tokensUpdateCreateModal.getByTestId(
|
|
"value-saturation-selector",
|
|
);
|
|
await expect(valueSaturationSelector).toBeVisible();
|
|
await valueSaturationSelector.click({ position: { x: 50, y: 50 } });
|
|
|
|
// Verify that a color value was set
|
|
const colorInput = firstShadowFields.getByRole("textbox", {
|
|
name: "Color",
|
|
});
|
|
await expect(colorInput).toHaveValue(/^rgb(.*)$/);
|
|
|
|
// Wait for validation to complete
|
|
await expect(
|
|
tokensUpdateCreateModal.getByText(/Resolved value:/).first(),
|
|
).toBeVisible();
|
|
|
|
// Save button should be enabled
|
|
const submitButton = tokensUpdateCreateModal.getByRole("button", {
|
|
name: "Save",
|
|
});
|
|
await expect(submitButton).toBeEnabled();
|
|
});
|
|
|
|
await test.step("Stage 2: Shadow adding/removing works", async () => {
|
|
const firstShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-0",
|
|
);
|
|
const colorInput = firstShadowFields.getByRole("textbox", {
|
|
name: "Color",
|
|
});
|
|
const firstColorValue = await colorInput.inputValue();
|
|
|
|
// User adds a second shadow
|
|
const addButton = tokensUpdateCreateModal.getByRole("button", {
|
|
name: "Add Shadow",
|
|
});
|
|
await addButton.click();
|
|
|
|
const secondShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-1",
|
|
);
|
|
await expect(secondShadowFields).toBeVisible();
|
|
|
|
// User adds a third shadow
|
|
await addButton.click();
|
|
|
|
const thirdShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-2",
|
|
);
|
|
await expect(thirdShadowFields).toBeVisible();
|
|
|
|
// User adds values for the third shadow
|
|
const thirdOffsetXInput = thirdShadowFields.getByRole("textbox", {
|
|
name: "X",
|
|
});
|
|
const thirdOffsetYInput = thirdShadowFields.getByRole("textbox", {
|
|
name: "Y",
|
|
});
|
|
const thirdBlurInput = thirdShadowFields.getByRole("textbox", {
|
|
name: "Blur",
|
|
});
|
|
const thirdSpreadInput = thirdShadowFields.getByRole("textbox", {
|
|
name: "Spread",
|
|
});
|
|
const thirdColorInput = thirdShadowFields.getByRole("textbox", {
|
|
name: "Color",
|
|
});
|
|
|
|
await thirdOffsetXInput.fill("10");
|
|
await thirdOffsetYInput.fill("10");
|
|
await thirdBlurInput.fill("20");
|
|
await thirdSpreadInput.fill("5");
|
|
await thirdColorInput.fill("#FF0000");
|
|
|
|
// User removes the 2nd shadow
|
|
const removeButton2 = secondShadowFields.getByRole("button", {
|
|
name: "Remove Shadow",
|
|
});
|
|
await removeButton2.click();
|
|
|
|
// Verify that we have only two shadow fields
|
|
await expect(thirdShadowFields).not.toBeVisible();
|
|
|
|
// Verify that the first shadow kept its values
|
|
const firstOffsetXValue = await firstShadowFields
|
|
.getByRole("textbox", { name: "X" })
|
|
.inputValue();
|
|
const firstOffsetYValue = await firstShadowFields
|
|
.getByRole("textbox", { name: "Y" })
|
|
.inputValue();
|
|
const firstBlurValue = await firstShadowFields
|
|
.getByRole("textbox", { name: "Blur" })
|
|
.inputValue();
|
|
const firstSpreadValue = await firstShadowFields
|
|
.getByRole("textbox", { name: "Spread" })
|
|
.inputValue();
|
|
const firstColorValueAfter = await firstShadowFields
|
|
.getByRole("textbox", { name: "Color" })
|
|
.inputValue();
|
|
|
|
await expect(firstOffsetXValue).toBe("2");
|
|
await expect(firstOffsetYValue).toBe("2");
|
|
await expect(firstBlurValue).toBe("4");
|
|
await expect(firstSpreadValue).toBe("0");
|
|
await expect(firstColorValueAfter).toBe(firstColorValue);
|
|
|
|
// Verify that the second kept its values (after shadow 3)
|
|
// After removing index 1, the third shadow becomes the second shadow at index 1
|
|
const newSecondShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-1",
|
|
);
|
|
await expect(newSecondShadowFields).toBeVisible();
|
|
|
|
const secondOffsetXValue = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "X" })
|
|
.inputValue();
|
|
const secondOffsetYValue = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Y" })
|
|
.inputValue();
|
|
const secondBlurValue = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Blur" })
|
|
.inputValue();
|
|
const secondSpreadValue = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Spread" })
|
|
.inputValue();
|
|
const secondColorValue = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Color" })
|
|
.inputValue();
|
|
|
|
await expect(secondOffsetXValue).toBe("10");
|
|
await expect(secondOffsetYValue).toBe("10");
|
|
await expect(secondBlurValue).toBe("20");
|
|
await expect(secondSpreadValue).toBe("5");
|
|
await expect(secondColorValue).toBe("#FF0000");
|
|
});
|
|
|
|
await test.step("Stage 3: Restore when switching tabs works", async () => {
|
|
const firstShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-0",
|
|
);
|
|
const newSecondShadowFields = tokensUpdateCreateModal.getByTestId(
|
|
"shadow-input-fields-1",
|
|
);
|
|
const colorInput = firstShadowFields.getByRole("textbox", {
|
|
name: "Color",
|
|
});
|
|
const firstColorValue = await colorInput.inputValue();
|
|
|
|
// Switch to reference tab
|
|
const referenceTabButton =
|
|
tokensUpdateCreateModal.getByTestId("reference-opt");
|
|
await referenceTabButton.click();
|
|
|
|
// Verify we're in reference mode - the composite fields should not be visible
|
|
await expect(firstShadowFields).not.toBeVisible();
|
|
|
|
// Switch back to composite tab
|
|
const compositeTabButton =
|
|
tokensUpdateCreateModal.getByTestId("composite-opt");
|
|
await compositeTabButton.click();
|
|
|
|
// Verify that shadows are restored
|
|
await expect(firstShadowFields).toBeVisible();
|
|
await expect(newSecondShadowFields).toBeVisible();
|
|
|
|
// Verify first shadow values are still there
|
|
const restoredFirstOffsetX = await firstShadowFields
|
|
.getByRole("textbox", { name: "X" })
|
|
.inputValue();
|
|
const restoredFirstOffsetY = await firstShadowFields
|
|
.getByRole("textbox", { name: "Y" })
|
|
.inputValue();
|
|
const restoredFirstBlur = await firstShadowFields
|
|
.getByRole("textbox", { name: "Blur" })
|
|
.inputValue();
|
|
const restoredFirstSpread = await firstShadowFields
|
|
.getByRole("textbox", { name: "Spread" })
|
|
.inputValue();
|
|
const restoredFirstColor = await firstShadowFields
|
|
.getByRole("textbox", { name: "Color" })
|
|
.inputValue();
|
|
|
|
await expect(restoredFirstOffsetX).toBe("2");
|
|
await expect(restoredFirstOffsetY).toBe("2");
|
|
await expect(restoredFirstBlur).toBe("4");
|
|
await expect(restoredFirstSpread).toBe("0");
|
|
await expect(restoredFirstColor).toBe(firstColorValue);
|
|
|
|
// Verify second shadow values are still there
|
|
const restoredSecondOffsetX = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "X" })
|
|
.inputValue();
|
|
const restoredSecondOffsetY = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Y" })
|
|
.inputValue();
|
|
const restoredSecondBlur = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Blur" })
|
|
.inputValue();
|
|
const restoredSecondSpread = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Spread" })
|
|
.inputValue();
|
|
const restoredSecondColor = await newSecondShadowFields
|
|
.getByRole("textbox", { name: "Color" })
|
|
.inputValue();
|
|
|
|
await expect(restoredSecondOffsetX).toBe("10");
|
|
await expect(restoredSecondOffsetY).toBe("10");
|
|
await expect(restoredSecondBlur).toBe("20");
|
|
await expect(restoredSecondSpread).toBe("5");
|
|
await expect(restoredSecondColor).toBe("#FF0000");
|
|
});
|
|
|
|
await test.step("Stage 4: Layer application works", async () => {
|
|
// Save the token
|
|
const submitButton = tokensUpdateCreateModal.getByRole("button", {
|
|
name: "Save",
|
|
});
|
|
await submitButton.click();
|
|
await expect(tokensUpdateCreateModal).not.toBeVisible();
|
|
|
|
// Verify token appears in sidebar
|
|
const shadowToken = tokensSidebar.getByRole("button", {
|
|
name: "primary",
|
|
});
|
|
await expect(shadowToken).toBeEnabled();
|
|
|
|
// Apply the shadow
|
|
await workspacePage.clickLayers();
|
|
await workspacePage.clickLeafLayer("Button");
|
|
|
|
const shadowSection = workspacePage.rightSidebar.getByText("Drop shadow");
|
|
await expect(shadowSection).toHaveCount(0);
|
|
|
|
await page.getByRole("tab", { name: "Tokens" }).click();
|
|
await shadowToken.click();
|
|
|
|
await expect(shadowSection).toHaveCount(2);
|
|
});
|
|
});
|
|
|
|
test("User applies dimension token to a shape on width and height", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
// Unfolds dimensions on token panel
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "dimensions");
|
|
|
|
// Apply token to width and height token from token panel
|
|
await tokensSidebar.getByRole("button", { name: "dimension.sm" }).click();
|
|
|
|
// Check if measures sections is visible on right sidebar
|
|
const measuresSection = page.getByRole("region", {
|
|
name: "shape-measures-section",
|
|
});
|
|
await expect(measuresSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
|
name: "dimension.sm",
|
|
});
|
|
await expect(dimensionSMTokenPill).toHaveCount(2);
|
|
await dimensionSMTokenPill.nth(1).click();
|
|
|
|
// Change token from dropdown
|
|
const dimensionTokenOptionXl = measuresSection.getByRole("option", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
await dimensionTokenOptionXl.click();
|
|
|
|
await expect(dimensionSMTokenPill).toHaveCount(1);
|
|
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionXLTokenPill).toBeVisible();
|
|
|
|
// Detach token from design tab on right sidebar
|
|
const detachButton = measuresSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.nth(1).click();
|
|
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
});
|
|
|
|
test("User applies dimension token to a shape on x position", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
// Unfolds dimensions on token panel
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "dimensions");
|
|
|
|
// Apply token to width and height token from token panel
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "dimension.sm" })
|
|
.click({ button: "right" });
|
|
await tokenContextMenuForToken.getByText("AxisX").click();
|
|
|
|
// Check if measures sections is visible on right sidebar
|
|
const measuresSection = page.getByRole("region", {
|
|
name: "shape-measures-section",
|
|
});
|
|
await expect(measuresSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
|
name: "dimension.sm",
|
|
});
|
|
await expect(dimensionSMTokenPill).toBeVisible();
|
|
await dimensionSMTokenPill.click();
|
|
|
|
// Change token from dropdown
|
|
const dimensionTokenOptionXl = measuresSection.getByRole("option", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
await dimensionTokenOptionXl.click();
|
|
|
|
await expect(dimensionSMTokenPill).not.toBeVisible();
|
|
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionXLTokenPill).toBeVisible();
|
|
|
|
// Detach token from design tab on right sidebar
|
|
const detachButton = measuresSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.nth(0).click();
|
|
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
});
|
|
|
|
test("User applies dimension token to a shape on y position", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
// Unfolds dimensions on token panel
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "dimensions");
|
|
|
|
// Apply token to width and height token from token panel
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "dimension.sm" })
|
|
.click({ button: "right" });
|
|
await tokenContextMenuForToken.getByText("Y", { exact: true }).click();
|
|
|
|
// Check if measures sections is visible on right sidebar
|
|
const measuresSection = page.getByRole("region", {
|
|
name: "shape-measures-section",
|
|
});
|
|
await expect(measuresSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
|
name: "dimension.sm",
|
|
});
|
|
await expect(dimensionSMTokenPill).toBeVisible();
|
|
await dimensionSMTokenPill.click();
|
|
|
|
// Change token from dropdown
|
|
const dimensionTokenOptionXl = measuresSection.getByRole("option", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
await dimensionTokenOptionXl.click();
|
|
|
|
await expect(dimensionSMTokenPill).not.toBeVisible();
|
|
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionXLTokenPill).toBeVisible();
|
|
|
|
// Detach token from design tab on right sidebar
|
|
const detachButton = measuresSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.nth(0).click();
|
|
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
});
|
|
|
|
test("User applies dimension token to a shape border-radius", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
// Unfolds dimensions on token panel
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(2).click();
|
|
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "dimensions");
|
|
|
|
// Apply token to width and height token from token panel
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "dimension.xs" })
|
|
.click({ button: "right" });
|
|
await tokenContextMenuForToken.getByText("Border radius").hover();
|
|
await tokenContextMenuForToken.getByText("RadiusAll").click();
|
|
|
|
// Check if border radius sections is visible on right sidebar
|
|
const borderRadiusSection = page.getByRole("region", {
|
|
name: "Border radius section",
|
|
});
|
|
await expect(borderRadiusSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const dimensionXSTokenPill = borderRadiusSection.getByRole("button", {
|
|
name: "dimension.xs",
|
|
});
|
|
await expect(dimensionXSTokenPill).toBeVisible();
|
|
await dimensionXSTokenPill.click();
|
|
|
|
// Change token from dropdown
|
|
const dimensionTokenOptionXl = borderRadiusSection.getByRole("option", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
await dimensionTokenOptionXl.click();
|
|
|
|
await expect(dimensionXSTokenPill).not.toBeVisible();
|
|
const dimensionXLTokenPill = borderRadiusSection.getByRole("button", {
|
|
name: "dimension.xl",
|
|
});
|
|
await expect(dimensionXLTokenPill).toBeVisible();
|
|
|
|
// Detach token from design tab on right sidebar
|
|
const detachButton = borderRadiusSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.nth(0).click();
|
|
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
});
|
|
|
|
test("User applies stroke width token to a shape", async ({ page }) => {
|
|
const workspace = new WasmWorkspacePage(page, {
|
|
textEditor: true,
|
|
});
|
|
// Set up
|
|
await workspace.mockConfigFlags(["enable-feature-token-input"]);
|
|
await workspace.setupEmptyFile();
|
|
await workspace.mockGetFile("workspace/get-file-layout-stroke-token-json");
|
|
await workspace.goToWorkspace();
|
|
|
|
// Select shape apply stroke
|
|
await workspace.layers.getByTestId("layer-row").nth(0).click();
|
|
const rightSidebar = page.getByTestId("right-sidebar");
|
|
await expect(rightSidebar).toBeVisible();
|
|
await rightSidebar.getByTestId("add-stroke").click();
|
|
|
|
// Apply stroke width token from token panel
|
|
const tokensTab = page.getByRole("tab", { name: "Tokens" });
|
|
await expect(tokensTab).toBeVisible();
|
|
await tokensTab.click();
|
|
await page.getByRole("button", { name: "Stroke Width 2" }).click();
|
|
const tokensSidebar = workspace.tokensSidebar;
|
|
await expect(
|
|
tokensSidebar.getByRole("button", { name: "width-big" }),
|
|
).toBeVisible();
|
|
await tokensSidebar.getByRole("button", { name: "width-big" }).click();
|
|
|
|
// Check if token pill is visible on right sidebar
|
|
const strokeSectionSidebar = rightSidebar.getByRole("region", {
|
|
name: "Stroke section",
|
|
});
|
|
await expect(strokeSectionSidebar).toBeVisible();
|
|
const firstStrokeRow = strokeSectionSidebar.getByLabel("stroke-row-0");
|
|
await expect(firstStrokeRow).toBeVisible();
|
|
const StrokeWidthPill = firstStrokeRow.getByRole("button", {
|
|
name: "width-big",
|
|
});
|
|
await expect(StrokeWidthPill).toBeVisible();
|
|
|
|
// Detach token from right sidebar and apply another from dropdown
|
|
const detachButton = firstStrokeRow.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.click();
|
|
await expect(StrokeWidthPill).not.toBeVisible();
|
|
|
|
const tokenDropdown = firstStrokeRow.getByRole("button", {
|
|
name: "Open token list",
|
|
});
|
|
await tokenDropdown.click();
|
|
|
|
const widthOptionSmall = firstStrokeRow.getByRole("option", {
|
|
name: "width-small",
|
|
});
|
|
await expect(widthOptionSmall).toBeVisible();
|
|
await widthOptionSmall.click();
|
|
const StrokeWidthPillSmall = firstStrokeRow.getByRole("button", {
|
|
name: "width-small",
|
|
});
|
|
await expect(StrokeWidthPillSmall).toBeVisible();
|
|
});
|
|
|
|
test("User applies margin token to a shape", async ({ page }) => {
|
|
const workspace = new WasmWorkspacePage(page, {
|
|
textEditor: true,
|
|
});
|
|
// Set up
|
|
await workspace.mockConfigFlags(["enable-feature-token-input"]);
|
|
await workspace.setupEmptyFile();
|
|
await workspace.mockGetFile("workspace/get-file-layout-stroke-token-json");
|
|
await workspace.goToWorkspace();
|
|
|
|
// Select shape apply stroke
|
|
await workspace.layers
|
|
.getByTestId("layer-row")
|
|
.nth(1)
|
|
.getByTestId("toggle-content")
|
|
.click();
|
|
|
|
await workspace.layers.getByTestId("layer-row").nth(2).click();
|
|
|
|
const rightSidebar = page.getByTestId("right-sidebar");
|
|
await expect(rightSidebar).toBeVisible();
|
|
await rightSidebar.getByTestId("add-stroke").click();
|
|
|
|
// Apply margin token from token panel
|
|
const tokensTab = page.getByRole("tab", { name: "Tokens" });
|
|
await expect(tokensTab).toBeVisible();
|
|
await tokensTab.click();
|
|
await unfoldTokenType(workspace.tokensSidebar, "dimensions");
|
|
const tokensSidebar = workspace.tokensSidebar;
|
|
await expect(
|
|
tokensSidebar.getByRole("button", { name: "dim.md" }),
|
|
).toBeVisible();
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "dim.md" })
|
|
.click({ button: "right" });
|
|
await page
|
|
.getByTestId("tokens-context-menu-for-token")
|
|
.getByText("Spacing")
|
|
.hover();
|
|
await page
|
|
.getByTestId("tokens-context-menu-for-token")
|
|
.getByText("Horizontal")
|
|
.click();
|
|
|
|
// Check if token pill is visible on right sidebar
|
|
const layoutItemSectionSidebar = rightSidebar.getByRole("region", {
|
|
name: "Layout item section",
|
|
});
|
|
await expect(layoutItemSectionSidebar).toBeVisible();
|
|
const marginPillMd = layoutItemSectionSidebar.getByRole("button", {
|
|
name: "dim.md",
|
|
});
|
|
await expect(marginPillMd).toBeVisible();
|
|
|
|
await marginPillMd.click();
|
|
const dimensionTokenOptionXl = page.getByRole("option", { name: "dim.xl" });
|
|
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
await dimensionTokenOptionXl.click();
|
|
|
|
const marginPillXL = layoutItemSectionSidebar.getByRole("button", {
|
|
name: "dim.xl",
|
|
});
|
|
await expect(marginPillXL).toBeVisible();
|
|
|
|
// Detach token from right sidebar and apply another from dropdown
|
|
const detachButton = layoutItemSectionSidebar.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.click();
|
|
await expect(marginPillXL).not.toBeVisible();
|
|
const horizontalMarginInput = layoutItemSectionSidebar.getByRole("button", {
|
|
name: "Open token list",
|
|
});
|
|
await horizontalMarginInput.nth(1).click();
|
|
|
|
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
await dimensionTokenOptionXl.click();
|
|
|
|
await expect(marginPillXL).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe("Tokens: Detach token", () => {
|
|
test("User applies border-radius token to a shape from sidebar", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
// Open tokens sections on left sidebar
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
|
|
// Unfold border radius tokens
|
|
await unfoldTokenType(tokensSidebar, "Border Radius");
|
|
await expect(
|
|
tokensSidebar.getByRole("button", { name: "borderRadius.sm" }),
|
|
).toBeVisible();
|
|
|
|
// Apply border radius token from token panels
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "borderRadius.sm" })
|
|
.click();
|
|
|
|
// Check if border radius sections is visible on right sidebar
|
|
const borderRadiusSection = page.getByRole("region", {
|
|
name: "Border radius section",
|
|
});
|
|
await expect(borderRadiusSection).toBeVisible();
|
|
|
|
// Check if token pill is visible on design tab on right sidebar
|
|
const brTokenPillSM = borderRadiusSection.getByRole("button", {
|
|
name: "borderRadius.sm",
|
|
});
|
|
await expect(brTokenPillSM).toBeVisible();
|
|
await brTokenPillSM.click();
|
|
|
|
// Rename token
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "borderRadius.sm" })
|
|
.click({ button: "right" });
|
|
await expect(page.getByText("Edit token")).toBeVisible();
|
|
await page.getByText("Edit token").click();
|
|
const editModal = page.getByTestId("token-update-create-modal");
|
|
await expect(editModal).toBeVisible();
|
|
await expect(
|
|
editModal.getByRole("textbox", { name: "Name" }),
|
|
).toBeVisible();
|
|
await editModal
|
|
.getByRole("textbox", { name: "Name" })
|
|
.fill("BorderRadius.smBis");
|
|
const submitButton = editModal.getByRole("button", { name: "Save" });
|
|
await expect(submitButton).toBeEnabled();
|
|
await submitButton.click();
|
|
await expect(page.getByText("Don't remap")).toBeVisible();
|
|
await page.getByText("Don't remap").click();
|
|
const brokenPill = borderRadiusSection.getByRole("button", {
|
|
name: "is not in any active set",
|
|
});
|
|
await expect(brokenPill).toBeVisible();
|
|
|
|
// Detach broken token
|
|
const detachButton = borderRadiusSection.getByRole("button", {
|
|
name: "Detach token",
|
|
});
|
|
await detachButton.click();
|
|
await expect(brokenPill).not.toBeVisible();
|
|
|
|
//De-select and select shape again to double check token is detached
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(0).click();
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
await expect(brokenPill).not.toBeVisible();
|
|
});
|
|
});
|
|
|
|
test("Bug: 13959, User select shapes with different hidden state.", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage } = await setupTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
const layerMenuSection = page.getByRole("region", {
|
|
name: "Layer menu section",
|
|
});
|
|
await expect(layerMenuSection).toBeVisible();
|
|
await layerMenuSection
|
|
.getByRole("button", { name: "Toggle layer visibility" })
|
|
.click();
|
|
await expect(layerMenuSection).toBeVisible();
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.nth(0)
|
|
.click({ modifiers: ["Shift"] });
|
|
await expect(layerMenuSection).toBeVisible();
|
|
});
|
|
|
|
test("Bug: 13960, User select shapes with different opacity and input show mixed state.", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage } = await setupTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
const layerMenuSection = page.getByRole("region", {
|
|
name: "Layer menu section",
|
|
});
|
|
await expect(layerMenuSection).toBeVisible();
|
|
await layerMenuSection.getByRole("textbox", { name: "Opacity" }).fill("50");
|
|
await expect(layerMenuSection).toBeVisible();
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.nth(0)
|
|
.click({ modifiers: ["Shift"] });
|
|
await expect(
|
|
layerMenuSection.getByRole("textbox", { name: "Opacity" }),
|
|
).toBeVisible();
|
|
await expect(
|
|
layerMenuSection.getByRole("textbox", { name: "Opacity" }),
|
|
).toBeVisible();
|
|
|
|
await expect(
|
|
layerMenuSection.getByRole("textbox", { name: "Opacity" }),
|
|
).toHaveAttribute("placeholder", "Mixed");
|
|
});
|
|
|
|
test("BUG: 13930, Token colors are shown on selected colors section", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page);
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.filter({ hasText: "Button" })
|
|
.click();
|
|
|
|
await page.getByRole("tab", { name: "Tokens" }).click();
|
|
|
|
await unfoldTokenType(tokensSidebar, "color");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "black" })
|
|
.click({ button: "right" });
|
|
await tokenContextMenuForToken.getByText("Fill").click();
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.filter({ hasText: "Rectangle" })
|
|
.first()
|
|
.click({ modifiers: ["Shift"] });
|
|
|
|
await expect(
|
|
workspacePage.page.getByRole("region", { name: "Color selection section" }),
|
|
).toBeVisible();
|
|
|
|
await workspacePage.page
|
|
.getByRole("button", { name: "Resolved value: #7f9cf5" })
|
|
.click();
|
|
await expect(
|
|
workspacePage.page.getByRole("region", { name: "Color selection section" }),
|
|
).toBeVisible();
|
|
|
|
await expect(
|
|
workspacePage.page
|
|
.getByTestId("colorpicker")
|
|
.getByRole("button", { name: "colors.black" }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test.describe("Numeric Input and Token Integration Tests", () => {
|
|
test("Token pill persists after blur in gap inputs", async ({ page }) => {
|
|
// Setup the workspace with token features enabled
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
// Transform a rectangle into a flex container to expose gap properties
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const layoutSection =
|
|
workspacePage.rightSidebar.getByTestId("inspect-layout");
|
|
|
|
const addLayoutButton = layoutSection
|
|
.getByRole("button", { name: "Add layout" })
|
|
.first();
|
|
await addLayoutButton.click();
|
|
await page.getByText("Flex layout").click();
|
|
|
|
// Apply a spacing token to the Column gap property
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
await unfoldTokenType(tokensSidebar, "spacing");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "spacing.lg" })
|
|
.click({ button: "right" });
|
|
|
|
await tokenContextMenuForToken.getByText("Column gap").click();
|
|
|
|
// Verify that the token pill appears in the layout section, check after blur
|
|
await expect(
|
|
page
|
|
.getByTestId("inspect-layout")
|
|
.getByRole("button", { name: "spacing.lg" }),
|
|
).toBeVisible();
|
|
|
|
await page
|
|
.getByTestId("inspect-layout")
|
|
.getByRole("textbox", { name: "Vertical padding" })
|
|
.click();
|
|
|
|
await expect(
|
|
page
|
|
.getByTestId("inspect-layout")
|
|
.getByRole("button", { name: "spacing.lg" }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("Padding tokens are applied to both vertical or horizontal properties", async ({
|
|
page,
|
|
}) => {
|
|
// Setup the workspace with token features enabled
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
// Transform a rectangle into a flex container to expose gap properties
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const layoutSection =
|
|
workspacePage.rightSidebar.getByTestId("inspect-layout");
|
|
|
|
const addLayoutButton = layoutSection
|
|
.getByRole("button", { name: "Add layout" })
|
|
.first();
|
|
await addLayoutButton.click();
|
|
await page.getByText("Flex layout").click();
|
|
|
|
// Apply a spacing token to the Column gap property
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
await unfoldTokenType(tokensSidebar, "spacing");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "spacing.lg" })
|
|
.click({ button: "right" });
|
|
|
|
await tokenContextMenuForToken.getByText("Horizontal").click();
|
|
|
|
// Verify that the token pill appears in the layout section, check after blur
|
|
await expect(
|
|
page
|
|
.getByTestId("inspect-layout")
|
|
.getByRole("button", { name: "spacing.lg" }),
|
|
).toBeVisible();
|
|
|
|
await layoutSection
|
|
.getByRole("button", { name: "Show 4 sided padding options" })
|
|
.click();
|
|
|
|
await expect(
|
|
page
|
|
.getByTestId("inspect-layout")
|
|
.getByRole("button", { name: "spacing.lg" }),
|
|
).toHaveCount(2);
|
|
|
|
await layoutSection
|
|
.getByRole("button", { name: "Show 4 sided padding options" })
|
|
.click();
|
|
|
|
await expect(
|
|
page
|
|
.getByTestId("inspect-layout")
|
|
.getByRole("button", { name: "spacing.lg" }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("Token pill persists after blur in min/max width inputs", async ({
|
|
page,
|
|
}) => {
|
|
// Setup the workspace with token features enabled
|
|
const { workspacePage } = await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
// Create a flex container to expose min/max width properties
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(2).click();
|
|
|
|
const layoutSection =
|
|
workspacePage.rightSidebar.getByTestId("inspect-layout");
|
|
|
|
const addLayoutButton = layoutSection
|
|
.getByRole("button", { name: "Add layout" })
|
|
.first();
|
|
await addLayoutButton.click();
|
|
await page.getByText("Flex layout").click();
|
|
|
|
// Verify that the flex container (Flex board) is created
|
|
await expect(
|
|
page.getByRole("button", { name: "Flex board" }),
|
|
).toBeVisible();
|
|
|
|
// Select element inside flex container to access to layout constrains inputs
|
|
// Apply token to min width property
|
|
await workspacePage.layers
|
|
.getByTestId("layer-row")
|
|
.nth(2)
|
|
.getByTestId("toggle-content")
|
|
.click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(3).click();
|
|
|
|
const layoutItemSection = page.getByRole("region", {
|
|
name: "Layout item section",
|
|
});
|
|
|
|
await layoutItemSection.getByTestId("behaviour-h-fill").click();
|
|
|
|
const constraintsSection = layoutItemSection.getByRole("region", {
|
|
name: "layout item size constraints",
|
|
});
|
|
await expect(constraintsSection).toBeVisible();
|
|
|
|
await constraintsSection
|
|
.getByRole("button", { name: "Open token list" })
|
|
.nth(0)
|
|
.click();
|
|
|
|
await expect(
|
|
page.getByRole("option", { name: "dimension.md" }),
|
|
).toBeVisible();
|
|
await page.getByRole("option", { name: "dimension.md" }).click();
|
|
|
|
await expect(
|
|
constraintsSection.getByRole("button", { name: "dimension.md" }),
|
|
).toBeVisible();
|
|
|
|
// Focus another input (Max width) to trigger blur and check if token pill persists
|
|
await constraintsSection
|
|
.getByRole("textbox", { name: "Max width" })
|
|
.click();
|
|
|
|
await expect(
|
|
constraintsSection.getByRole("button", { name: "dimension.md" }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("Invalid formula reverts to previous value in padding inputs", async ({
|
|
page,
|
|
}) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const layoutSection =
|
|
workspacePage.rightSidebar.getByTestId("inspect-layout");
|
|
|
|
const addLayoutButton = layoutSection
|
|
.getByRole("button", { name: "Add layout" })
|
|
.first();
|
|
|
|
await addLayoutButton.click();
|
|
|
|
await page.getByText("Flex layout").click();
|
|
|
|
// Apply a spacing token to the Column gap property
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
await unfoldTokenType(tokensSidebar, "spacing");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "spacing.lg" })
|
|
.click({ button: "right" });
|
|
|
|
await tokenContextMenuForToken.getByText("Column gap").click();
|
|
|
|
const verticalPaddingInput = layoutSection.getByRole("textbox", {
|
|
name: "Vertical padding",
|
|
});
|
|
|
|
// Enter a valid value first
|
|
await verticalPaddingInput.fill("23");
|
|
await verticalPaddingInput.press("Enter");
|
|
// Wait for potential error handling
|
|
await page.waitForTimeout(500);
|
|
|
|
expect(await verticalPaddingInput.inputValue()).toMatch("23");
|
|
|
|
// Enter invalid expression
|
|
await verticalPaddingInput.fill("abc+1");
|
|
await verticalPaddingInput.press("Enter");
|
|
|
|
// Wait for potential error handling
|
|
await page.waitForTimeout(500);
|
|
|
|
// Value should revert to previous valid value
|
|
expect(await verticalPaddingInput.inputValue()).toMatch("23");
|
|
|
|
// Should NOT contain invalid characters
|
|
expect(await verticalPaddingInput.inputValue()).not.toContain("abc");
|
|
});
|
|
|
|
test("Division by zero reverts to previous value", async ({ page }) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const layoutSection =
|
|
workspacePage.rightSidebar.getByTestId("inspect-layout");
|
|
|
|
const addLayoutButton = layoutSection
|
|
.getByRole("button", { name: "Add layout" })
|
|
.first();
|
|
|
|
await addLayoutButton.click();
|
|
|
|
await page.getByText("Flex layout").click();
|
|
|
|
// Apply a spacing token to the Column gap property
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
await unfoldTokenType(tokensSidebar, "spacing");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "spacing.lg" })
|
|
.click({ button: "right" });
|
|
|
|
await tokenContextMenuForToken.getByText("Column gap").click();
|
|
|
|
const verticalPaddingInput = layoutSection.getByRole("textbox", {
|
|
name: "Vertical padding",
|
|
});
|
|
|
|
// Enter a valid value first
|
|
await verticalPaddingInput.fill("23");
|
|
await verticalPaddingInput.press("Enter");
|
|
// Wait for potential error handling
|
|
await page.waitForTimeout(500);
|
|
|
|
expect(await verticalPaddingInput.inputValue()).toMatch("23");
|
|
|
|
// Enter invalid expression
|
|
await verticalPaddingInput.fill("10/0");
|
|
await verticalPaddingInput.press("Enter");
|
|
|
|
// Wait for potential error handling
|
|
await page.waitForTimeout(500);
|
|
|
|
// Value should revert to previous valid value
|
|
expect(await verticalPaddingInput.inputValue()).toMatch("23");
|
|
|
|
// Should NOT contain invalid characters
|
|
expect(await verticalPaddingInput.inputValue()).not.toContain("10/0");
|
|
|
|
// Value should revert
|
|
expect(await verticalPaddingInput.inputValue()).toMatch(/^(\d+|--)$/);
|
|
expect(await verticalPaddingInput.inputValue()).not.toBe("Infinity");
|
|
});
|
|
|
|
test("Negative expression result handled correctly", async ({ page }) => {
|
|
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
const widthInput = workspacePage.rightSidebar.getByRole("textbox", {
|
|
name: "Width",
|
|
});
|
|
await expect(widthInput).toBeVisible();
|
|
|
|
// Enter a valid value first
|
|
await widthInput.fill("23");
|
|
await widthInput.press("Enter");
|
|
|
|
// Wait for potential error handling
|
|
await page.waitForTimeout(500);
|
|
expect(await widthInput.inputValue()).toMatch("23");
|
|
|
|
// Enter a negative expression
|
|
await widthInput.fill("10-50");
|
|
await widthInput.press("Enter");
|
|
|
|
// Wait for potential error handling
|
|
await page.waitForTimeout(500);
|
|
|
|
expect(await widthInput.inputValue()).toMatch("0.01");
|
|
|
|
// Should NOT negative values
|
|
expect(await widthInput.inputValue()).not.toContain("-40");
|
|
});
|
|
|
|
test("Token pill show broken reference when set is not activated", async ({
|
|
page,
|
|
}) => {
|
|
// Setup the workspace with token features enabled
|
|
const {
|
|
workspacePage,
|
|
tokensSidebar,
|
|
tokenContextMenuForToken,
|
|
tokenThemesSetsSidebar,
|
|
} = await setupTokensFileRender(page, {
|
|
flags: ["enable-token-combobox", "enable-feature-token-input"],
|
|
});
|
|
// Create a token with a reference value in other set.
|
|
await createToken(page, "Dimensions", "reference-token", "Value", "{card.padding}");
|
|
|
|
|
|
// Apply this token to a shape
|
|
await page.getByRole("tab", { name: "Layers" }).click();
|
|
|
|
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
|
|
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
await tokensTabButton.click();
|
|
await unfoldTokenType(tokensSidebar, "dimensions");
|
|
|
|
await tokensSidebar
|
|
.getByRole("button", { name: "reference-token" })
|
|
.click({ button: "right" });
|
|
|
|
await tokenContextMenuForToken.getByText("X", { exact: true }).click();
|
|
|
|
//Check if token is applied and visible on right sidebar
|
|
const measuresSection = page.getByRole("region", {
|
|
name: "shape-measures-section",
|
|
});
|
|
await expect(measuresSection).toBeVisible();
|
|
|
|
await expect(measuresSection.getByRole('button', { name: 'reference-token' })).toBeVisible();
|
|
|
|
// Deactivate token set where reference token exist to make token broken
|
|
await tokenThemesSetsSidebar.getByRole('button', { name: 'theme' }).getByRole('checkbox').click();
|
|
|
|
// Check if token pill show broken reference state
|
|
const brokenPill = measuresSection.getByRole("button", {
|
|
name: "is not in any active set",
|
|
});
|
|
await expect(brokenPill).toHaveCount(2);
|
|
});
|
|
});
|