diff --git a/frontend/playwright/data/workspace/get-team-tokens.json b/frontend/playwright/data/workspace/get-team-tokens.json new file mode 100644 index 0000000000..855b1506ac --- /dev/null +++ b/frontend/playwright/data/workspace/get-team-tokens.json @@ -0,0 +1,24 @@ +{ + "~:features": { + "~#set": [ + "design-tokens/v1", + "layout/grid", + "styles/v2", + "fdata/pointer-map", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true + }, + "~:name": "Default", + "~:modified-at": "~m1713533116375", + "~:id": "~uc7ce0794-0992-8105-8004-38e630f40f6d", + "~:created-at": "~m1713533116375", + "~:is-default": true +} diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index 71c20b639f..42326e4841 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -76,6 +76,10 @@ export class WorkspacePage extends BaseWebSocketPage { this.togglePalettesVisibility = page.getByTestId( "toggle-palettes-visibility", ); + this.tokensUpdateCreateModal = page.getByTestId( + "token-update-create-modal", + ); + this.tokenThemesSetsSidebar = page.getByTestId("token-themes-sets-sidebar"); } async goToWorkspace({ diff --git a/frontend/playwright/ui/specs/tokens.spec.js b/frontend/playwright/ui/specs/tokens.spec.js new file mode 100644 index 0000000000..2f920c275d --- /dev/null +++ b/frontend/playwright/ui/specs/tokens.spec.js @@ -0,0 +1,102 @@ +import { test, expect } from "@playwright/test"; +import { WorkspacePage } from "../pages/WorkspacePage"; + +test.beforeEach(async ({ page }) => { + await WorkspacePage.init(page); +}); + +const setupFileWithTokens = async (page) => { + const workspacePage = new WorkspacePage(page); + await workspacePage.setupEmptyFile(); + await workspacePage.mockRPC( + "get-team?id=*", + "workspace/get-team-tokens.json", + ); + + await workspacePage.goToWorkspace(); + + const tokensTabButton = page.getByRole("tab", { name: "Tokens" }); + await tokensTabButton.click(); + + return { workspacePage }; +}; + +test.describe("Tokens: Tab", () => { + test("Clicking tokens tab button opens tokens sidebar tab", async ({ + page, + }) => { + const { workspacePage } = await setupFileWithTokens(page); + + const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" }); + + await expect(tokensTabPanel).toHaveText(/TOKENS/); + await expect(tokensTabPanel).toHaveText(/Themes/); + }); + + test("User creates color token and auto created set show up in the sidebar", async ({ + page, + }) => { + const { workspacePage } = await setupFileWithTokens(page); + + const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" }); + await tokensTabPanel.getByTitle("Add token: Color").click(); + + // Create color token with mouse + + await expect(workspacePage.tokensUpdateCreateModal).toBeVisible(); + + const nameField = workspacePage.tokensUpdateCreateModal.getByLabel("Name"); + const valueField = + workspacePage.tokensUpdateCreateModal.getByLabel("Value"); + + await nameField.click(); + await nameField.fill("color.primary"); + + await valueField.click(); + await valueField.fill("red"); + + const submitButton = workspacePage.tokensUpdateCreateModal.getByRole( + "button", + { + name: "Save", + }, + ); + await expect(submitButton).toBeEnabled(); + await submitButton.click(); + + await expect(tokensTabPanel.getByText("color.primary")).toBeEnabled(); + + // Create token referencing the previous one with keyboard + + await tokensTabPanel.getByTitle("Add token: Color").click(); + await expect(workspacePage.tokensUpdateCreateModal).toBeVisible(); + + await nameField.click(); + await nameField.fill("color.secondary"); + await nameField.press("Tab"); + + await valueField.click(); + await valueField.fill("{color.primary}"); + + await expect(submitButton).toBeEnabled(); + await nameField.press("Enter"); + + const referenceToken = tokensTabPanel.getByText("color.secondary"); + await expect(referenceToken).toBeEnabled(); + + // Tokens tab panel should have two tokens with the color red / #ff0000 + await expect(tokensTabPanel.getByTitle("#ff0000")).toHaveCount(2); + + // Global set has been auto created and is active + await expect( + workspacePage.tokenThemesSetsSidebar.getByRole("button", { + name: "Global", + }), + ).toHaveCount(1); + await expect( + workspacePage.tokenThemesSetsSidebar.getByRole("button", { + name: "Global", + }), + ).toHaveAttribute("aria-checked", "true"); + }); +}); diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index de24713031..a23ea972c2 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -360,8 +360,8 @@ Token names should only contain letters and digits separated by . characters.")} (dom/prevent-default e) (modal/hide!)))] - [:form {:class (stl/css :form-wrapper) - :on-submit on-submit} + [:form {:class (stl/css :form-wrapper) + :on-submit on-submit} [:div {:class (stl/css :token-rows)} [:> heading* {:level 2 :typography "headline-medium" :class (stl/css :form-modal-title)} (if (= action "edit") diff --git a/frontend/src/app/main/ui/workspace/tokens/modals.cljs b/frontend/src/app/main/ui/workspace/tokens/modals.cljs index a34ccfe618..56a77ccd72 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals.cljs @@ -48,7 +48,8 @@ (fn [] (modal/hide!)))] [:div {:class (stl/css :token-modal-wrapper) - :style wrapper-style} + :style wrapper-style + :data-testid "token-update-create-modal"} [:> icon-button* {:on-click close-modal :class (stl/css :close-btn) :icon i/close diff --git a/frontend/src/app/main/ui/workspace/tokens/sets.cljs b/frontend/src/app/main/ui/workspace/tokens/sets.cljs index 127f13c3fa..49c41b0610 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sets.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sets.cljs @@ -111,7 +111,7 @@ [{:keys [set label tree-depth tree-path selected? on-select active? on-toggle editing? on-edit on-edit-reset on-edit-submit]}] (let [set-name (.-name set) editing?' (editing? tree-path) - active?' (active? set-name) + active?' (some? (active? set-name)) on-click (mf/use-fn (mf/deps editing?' tree-path) @@ -138,7 +138,8 @@ :selected-set selected?) :on-click on-click :on-double-click #(on-edit tree-path) - :on-context-menu on-context-menu} + :on-context-menu on-context-menu + :aria-checked active?'} [:> icon* {:id "document" :class (stl/css-case :icon true diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index b496a2d974..a6b28ecb6e 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -148,7 +148,8 @@ :open? open?} [:& cmm/asset-section-block {:role :title-button} [:button {:class (stl/css :action-button) - :on-click on-popover-open-click} + :on-click on-popover-open-click + :title (str "Add token: " title)} i/add]] (when open? [:& cmm/asset-section-block {:role :content} @@ -238,7 +239,8 @@ on-open (mf/use-fn #(reset! open? true))] [:& sets-context/provider {} [:& sets-context-menu] - [:article {:class (stl/css :sets-section-wrapper) + [:article {:data-testid "token-themes-sets-sidebar" + :class (stl/css :sets-section-wrapper) :style {"--resize-height" (str resize-height "px")}} [:div {:class (stl/css :sets-sidebar)} [:& themes-header]