diff --git a/frontend/playwright/data/workspace/get-file-library.json b/frontend/playwright/data/workspace/get-file-library.json new file mode 100644 index 000000000..de4775427 --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-library.json @@ -0,0 +1,242 @@ +{ + "~:features":{ + "~#set":[ + "layout/grid", + "styles/v2", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:permissions":{ + "~:type":"~:membership", + "~:is-owner":true, + "~:is-admin":true, + "~:can-edit":true, + "~:can-read":true, + "~:is-logged":true + }, + "~:has-media-trimmed":false, + "~:comment-thread-seqn":0, + "~:name":"Testing library 1", + "~:revn":2, + "~:modified-at":"~m1717512948250", + "~:id":"~uc1249a66-fce0-8175-8004-7433fe4be8bc", + "~:is-shared":true, + "~:version":48, + "~:project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b", + "~:created-at":"~m1717512934704", + "~:data":{ + "~:pages":[ + "~uc1249a66-fce0-8175-8004-7433fe4be8bd" + ], + "~:pages-index":{ + "~uc1249a66-fce0-8175-8004-7433fe4be8bd":{ + "~:options":{ + + }, + "~:objects":{ + "~u00000000-0000-0000-0000-000000000000":{ + "~#shape":{ + "~:y":0, + "~:hide-fill-on-export":false, + "~:transform":{ + "~#matrix":{ + "~:a":1.0, + "~:b":0.0, + "~:c":0.0, + "~:d":1.0, + "~:e":0.0, + "~:f":0.0 + } + }, + "~:rotation":0, + "~:name":"Root Frame", + "~:width":0.01, + "~:type":"~:frame", + "~:points":[ + { + "~#point":{ + "~:x":0, + "~:y":0 + } + }, + { + "~#point":{ + "~:x":0.01, + "~:y":0 + } + }, + { + "~#point":{ + "~:x":0.01, + "~:y":0.01 + } + }, + { + "~#point":{ + "~:x":0, + "~:y":0.01 + } + } + ], + "~:proportion-lock":false, + "~:transform-inverse":{ + "~#matrix":{ + "~:a":1.0, + "~:b":0.0, + "~:c":0.0, + "~:d":1.0, + "~:e":0.0, + "~:f":0.0 + } + }, + "~:id":"~u00000000-0000-0000-0000-000000000000", + "~:parent-id":"~u00000000-0000-0000-0000-000000000000", + "~:frame-id":"~u00000000-0000-0000-0000-000000000000", + "~:strokes":[ + + ], + "~:x":0, + "~:proportion":1.0, + "~:selrect":{ + "~#rect":{ + "~:x":0, + "~:y":0, + "~:width":0.01, + "~:height":0.01, + "~:x1":0, + "~:y1":0, + "~:x2":0.01, + "~:y2":0.01 + } + }, + "~:fills":[ + { + "~:fill-color":"#FFFFFF", + "~:fill-opacity":1 + } + ], + "~:flip-x":null, + "~:height":0.01, + "~:flip-y":null, + "~:shapes":[ + "~uc70224ec-c410-807b-8004-743400e00be8" + ] + } + }, + "~uc70224ec-c410-807b-8004-743400e00be8":{ + "~#shape":{ + "~:y":255, + "~:rx":0, + "~:transform":{ + "~#matrix":{ + "~:a":1.0, + "~:b":0.0, + "~:c":0.0, + "~:d":1.0, + "~:e":0.0, + "~:f":0.0 + } + }, + "~:rotation":0, + "~:grow-type":"~:fixed", + "~:hide-in-viewer":false, + "~:name":"Rectangle", + "~:width":279.0000000000001, + "~:type":"~:rect", + "~:points":[ + { + "~#point":{ + "~:x":523, + "~:y":255 + } + }, + { + "~#point":{ + "~:x":802.0000000000001, + "~:y":255 + } + }, + { + "~#point":{ + "~:x":802.0000000000001, + "~:y":534 + } + }, + { + "~#point":{ + "~:x":523, + "~:y":534 + } + } + ], + "~:proportion-lock":false, + "~:transform-inverse":{ + "~#matrix":{ + "~:a":1.0, + "~:b":0.0, + "~:c":0.0, + "~:d":1.0, + "~:e":0.0, + "~:f":0.0 + } + }, + "~:id":"~uc70224ec-c410-807b-8004-743400e00be8", + "~:parent-id":"~u00000000-0000-0000-0000-000000000000", + "~:frame-id":"~u00000000-0000-0000-0000-000000000000", + "~:strokes":[ + + ], + "~:x":523, + "~:proportion":1, + "~:selrect":{ + "~#rect":{ + "~:x":523, + "~:y":255, + "~:width":279.0000000000001, + "~:height":279, + "~:x1":523, + "~:y1":255, + "~:x2":802.0000000000001, + "~:y2":534 + } + }, + "~:fills":[ + { + "~:fill-color":"#B1B2B5", + "~:fill-opacity":1 + } + ], + "~:flip-x":null, + "~:ry":0, + "~:height":279, + "~:flip-y":null + } + } + }, + "~:id":"~uc1249a66-fce0-8175-8004-7433fe4be8bd", + "~:name":"Page 1" + } + }, + "~:id":"~uc1249a66-fce0-8175-8004-7433fe4be8bc", + "~:options":{ + "~:components-v2":true + }, + "~:recent-colors":[ + { + "~:color":"#187cd5", + "~:opacity":1 + } + ], + "~:colors":{ + "~uc70224ec-c410-807b-8004-74340616cffb":{ + "~:path":"", + "~:color":"#187cd5", + "~:name":"test-color-187cd5", + "~:modified-at":"~m1717512945259", + "~:opacity":1, + "~:id":"~uc70224ec-c410-807b-8004-74340616cffb" + } + } + } +} \ No newline at end of file diff --git a/frontend/playwright/data/workspace/get-team-shared-libraries-non-empty.json b/frontend/playwright/data/workspace/get-team-shared-libraries-non-empty.json new file mode 100644 index 000000000..05a5c8c3c --- /dev/null +++ b/frontend/playwright/data/workspace/get-team-shared-libraries-non-empty.json @@ -0,0 +1,47 @@ +{ + "~#set":[ + { + "~:name":"Testing library 1", + "~:revn":2, + "~:modified-at":"~m1717512948250", + "~:thumbnail-uri":"http://localhost:3000/assets/by-id/5ad7a7a7-c64e-4bb8-852d-15708d125905", + "~:id":"~uc1249a66-fce0-8175-8004-7433fe4be8bc", + "~:is-shared":true, + "~:project-id":"~uc7ce0794-0992-8105-8004-38e630f7920b", + "~:created-at":"~m1717512934704", + "~:library-summary":{ + "~:components":{ + "~:count":0, + "~:sample":[ + + ] + }, + "~:media":{ + "~:count":0, + "~:sample":[ + + ] + }, + "~:colors":{ + "~:count":1, + "~:sample":[ + { + "~:path":"", + "~:color":"#187cd5", + "~:name":"test-color", + "~:modified-at":"~m1717512945259", + "~:opacity":1, + "~:id":"~uc70224ec-c410-807b-8004-74340616cffb" + } + ] + }, + "~:typographies":{ + "~:count":0, + "~:sample":[ + + ] + } + } + } + ] +} \ No newline at end of file diff --git a/frontend/playwright/data/workspace/link-file-to-library.json b/frontend/playwright/data/workspace/link-file-to-library.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/frontend/playwright/data/workspace/link-file-to-library.json @@ -0,0 +1 @@ +{} diff --git a/frontend/playwright/data/workspace/unlink-file-from-library.json b/frontend/playwright/data/workspace/unlink-file-from-library.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/frontend/playwright/data/workspace/unlink-file-from-library.json @@ -0,0 +1 @@ +{} diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index 5bcfa5f9f..3dafef465 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -45,6 +45,11 @@ export class WorkspacePage extends BaseWebSocketPage { this.rootShape = page.locator(`[id="shape-00000000-0000-0000-0000-000000000000"]`); this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" }); this.colorpicker = page.getByTestId("colorpicker"); + this.palette = page.getByTestId("palette"); + this.assets = page.getByTestId("assets"); + this.libraries = page.getByTestId("libraries"); + this.closeLibraries = page.getByTestId("close-libraries"); + this.librariesModal = page.getByTestId("libraries-modal"); } async goToWorkspace() { @@ -97,4 +102,30 @@ export class WorkspacePage extends BaseWebSocketPage { await this.viewport.hover({ position: { x: x + width, y: y + height } }); await this.page.mouse.up(); } + + async clickAssets(clickOptions = {}) { + await this.assets.click(clickOptions); + } + + async clickLibraries(clickOptions = {}) { + await this.libraries.click(clickOptions); + } + + async clickLibrary(name, clickOptions = {}) { + await this.page + .getByTestId("library-item") + .filter({ hasText: name }) + .getByRole("button") + .click(clickOptions); + } + + async clickCloseLibraries(clickOptions = {}) { + await this.closeLibraries.click(clickOptions); + } + + async clickColorPalette(clickOptions = {}) { + await this.palette + .getByRole("button", { name: "Color Palette (Alt+P)" }) + .click(clickOptions); + } } diff --git a/frontend/playwright/ui/specs/workspace.spec.js b/frontend/playwright/ui/specs/workspace.spec.js index 58e9e5697..529965613 100644 --- a/frontend/playwright/ui/specs/workspace.spec.js +++ b/frontend/playwright/ui/specs/workspace.spec.js @@ -38,3 +38,31 @@ test("User draws a rect", async ({ page }) => { await expect(shape).toHaveAttribute("width", "200"); await expect(shape).toHaveAttribute("height", "100"); }); + +test("User adds a library and its automatically selected in the color palette", async ({ page }) => { + const workspacePage = new WorkspacePage(page); + await workspacePage.setupEmptyFile(); + await workspacePage.mockRPC("link-file-to-library", "workspace/link-file-to-library.json"); + await workspacePage.mockRPC("unlink-file-from-library", "workspace/unlink-file-from-library.json"); + await workspacePage.mockRPC("get-team-shared-files?team-id=*", "workspace/get-team-shared-libraries-non-empty.json"); + + await workspacePage.goToWorkspace(); + + // Add Testing library 1 + await workspacePage.clickColorPalette(); + await workspacePage.clickAssets(); + // Now the get-file call should return a library + await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-library.json"); + await workspacePage.clickLibraries(); + await workspacePage.clickLibrary("Testing library 1") + await workspacePage.clickCloseLibraries(); + + await expect(workspacePage.palette.getByRole("button", { name: "test-color-187cd5" })).toBeVisible(); + + // Remove Testing library 1 + await workspacePage.clickLibraries(); + await workspacePage.clickLibrary("Testing library 1") + await workspacePage.clickCloseLibraries(); + + await expect(workspacePage.palette.getByText('There are no color styles in your library yet')).toBeVisible(); +}); diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container.cljs index 20c79a417..1e3b99079 100644 --- a/frontend/src/app/main/ui/components/tab_container.cljs +++ b/frontend/src/app/main/ui/components/tab_container.cljs @@ -59,6 +59,7 @@ [:div {:key (str/concat "tab-" sid) :title tooltip :data-id sid + :data-testid sid :on-click on-click :class (stl/css-case :tab-container-tab-title true diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index e28f28f96..d07517c7b 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -230,7 +230,8 @@ (for [{:keys [id name] :as library} linked-libraries] [:div {:class (stl/css :section-list-item) - :key (dm/str id)} + :key (dm/str id) + :data-testid "library-item"} [:div {:class (stl/css :item-content)} [:div {:class (stl/css :item-name)} name] [:ul {:class (stl/css :item-contents)} @@ -263,7 +264,8 @@ [:div {:class (stl/css :section-list-shared)} (for [{:keys [id name] :as library} shared-libraries] [:div {:class (stl/css :section-list-item) - :key (dm/str id)} + :key (dm/str id) + :data-testid "library-item"} [:div {:class (stl/css :item-content)} [:div {:class (stl/css :item-name)} name] [:ul {:class (stl/css :item-contents)} @@ -513,10 +515,11 @@ (when team-id (st/emit! (dwl/fetch-shared-files {:team-id team-id})))) - [:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside} + [:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside :data-testid "libraries-modal"} [:div {:class (stl/css :modal-dialog)} [:button {:class (stl/css :close-btn) - :on-click close-dialog} + :on-click close-dialog + :data-testid "close-libraries"} close-icon] [:div {:class (stl/css :modal-title)} (tr "workspace.libraries.libraries")] diff --git a/frontend/src/app/main/ui/workspace/palette.cljs b/frontend/src/app/main/ui/workspace/palette.cljs index eedaeda61..b0d246a99 100644 --- a/frontend/src/app/main/ui/workspace/palette.cljs +++ b/frontend/src/app/main/ui/workspace/palette.cljs @@ -141,7 +141,8 @@ (swap! state* assoc :width width))) [:div {:class (stl/css :palette-wrapper) - :style (calculate-palette-padding rulers?)} + :style (calculate-palette-padding rulers?) + :data-testid "palette"} (when-not workspace-read-only? [:div {:ref parent-ref :class (dm/str size-classname " " (stl/css-case :palettes true diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index b3f755fc5..af12d40ab 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -157,7 +157,8 @@ [:div {:class (stl/css :assets-header)} (when-not ^boolean read-only? [:button {:class (stl/css :libraries-button) - :on-click show-libraries-dialog} + :on-click show-libraries-dialog + :data-testid "libraries"} [:span {:class (stl/css :libraries-icon)} i/library] (tr "workspace.assets.libraries")])