diff --git a/frontend/playwright/data/workspace/update-file-create-rect.json b/frontend/playwright/data/workspace/update-file-create-rect.json
new file mode 100644
index 000000000..671fef98f
--- /dev/null
+++ b/frontend/playwright/data/workspace/update-file-create-rect.json
@@ -0,0 +1,9 @@
+[
+  {
+    "~:id": "~u088df3d4-d383-80f6-8004-527e50ea4f1f",
+    "~:revn": 21,
+    "~:file-id": "~uc7ce0794-0992-8105-8004-38f280443849",
+    "~:session-id": "~u1dc6d4fa-7bd3-803a-8004-527dd9df2c62",
+    "~:changes": []
+  }
+]
diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js
index f89c57a7a..ce9b78dab 100644
--- a/frontend/playwright/ui/pages/WorkspacePage.js
+++ b/frontend/playwright/ui/pages/WorkspacePage.js
@@ -39,9 +39,11 @@ export class WorkspacePage extends BaseWebSocketPage {
 
   constructor(page) {
     super(page);
-    // TODO: add locators
     this.pageName = page.getByTestId("page-name");
     this.presentUserListItems = page.getByTestId("active-users-list").getByAltText("Princesa Leia");
+    this.viewport = page.getByTestId("viewport");
+    this.rootShape = page.locator(`[id="shape-00000000-0000-0000-0000-000000000000"]`);
+    this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" });
   }
 
   async goToWorkspace() {
@@ -86,4 +88,12 @@ export class WorkspacePage extends BaseWebSocketPage {
     await this.mockRPC("get-file-fragment?file-id=*", "workspace/get-file-fragment-blank.json");
     await this.mockRPC("get-file-libraries?file-id=*", "workspace/get-file-libraries-empty.json");
   }
+
+  async clickWithDragViewportAt(x, y, width, height) {
+    await this.page.waitForTimeout(100);
+    await this.viewport.hover({ position: { x, y } });
+    await this.page.mouse.down();
+    await this.viewport.hover({ position: { x: x + width, y: y + height } });
+    await this.page.mouse.up();
+  }
 }
diff --git a/frontend/playwright/ui/specs/workspace.spec.js b/frontend/playwright/ui/specs/workspace.spec.js
index 663e76b02..832617911 100644
--- a/frontend/playwright/ui/specs/workspace.spec.js
+++ b/frontend/playwright/ui/specs/workspace.spec.js
@@ -24,3 +24,17 @@ test("User receives presence notifications updates in the workspace", async ({ p
 
   await expect(page.getByTestId("active-users-list").getByAltText("Princesa Leia")).toHaveCount(2);
 });
+
+test("User draws a rect", async ({ page }) => {
+  const workspacePage = new WorkspacePage(page);
+  await workspacePage.setupEmptyFile();
+  await workspacePage.mockRPC("update-file?id=*", "workspace/update-file-create-rect.json");
+
+  await workspacePage.goToWorkspace();
+  await workspacePage.rectShapeButton.click();
+  await workspacePage.clickWithDragViewportAt(128, 128, 200, 100);
+
+  const shape = await workspacePage.rootShape.locator("rect");
+  expect(shape).toHaveAttribute("width", "200");
+  expect(shape).toHaveAttribute("height", "100");
+});
diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs
index d20d35e3c..d2697e018 100644
--- a/frontend/src/app/main/ui/workspace/viewport.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport.cljs
@@ -276,7 +276,7 @@
     (hooks/setup-shortcuts node-editing? drawing-path? text-editing? grid-editing?)
     (hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox)
 
-    [:div.viewport {:style #js {"--zoom" zoom}}
+    [:div.viewport {:style #js {"--zoom" zoom} :data-testid "viewport"}
      [:& top-bar/top-bar {:layout layout}]
      [:div.viewport-overlays
       ;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap