From 1703cf46b400abb1becef94cd03d423509a3d7be Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Thu, 29 Oct 2026 13:41:40 +0100 Subject: [PATCH] :sparkles: Test the detach option on nested broken copies Design confirmed the expected behavior: a broken copy nested in a main offers "Detach instance", and one nested in a copy does not. The fixture already had both cases ("Banner" with "Nested in main" and its copy with "Nested in copy"); the tests delete the "Icon" main to break them, check the broken indicator, and check the options menu: present with Detach for the first, absent for the second. AI-assisted-by: claude-opus-5-5 --- .../ui/specs/broken-copy-indicator.spec.js | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/frontend/playwright/ui/specs/broken-copy-indicator.spec.js b/frontend/playwright/ui/specs/broken-copy-indicator.spec.js index 47dc5b1c62..6609f888d7 100644 --- a/frontend/playwright/ui/specs/broken-copy-indicator.spec.js +++ b/frontend/playwright/ui/specs/broken-copy-indicator.spec.js @@ -75,3 +75,47 @@ test("Shows the broken indicator when every selected copy is broken", async ({ await expect(brokenIndicator(workspacePage)).toBeVisible(); }); + +// "Banner" is a main with a copy of "Icon" inside ("Nested in main"), and +// "Banner copy" is a copy of it ("Nested in copy"). Deleting the "Icon" main +// breaks both nested copies. +const breakNestedCopies = async (workspacePage) => { + await workspacePage.clickLeafLayer("Icon"); + await workspacePage.page.keyboard.press("Delete"); + + for (const parent of ["Banner", "Banner copy"]) { + await workspacePage.layers + .getByTestId("layer-row") + .filter({ has: workspacePage.page.getByText(parent, { exact: true }) }) + .getByTestId("toggle-content") + .click(); + } +}; + +const openComponentMenu = async (workspacePage) => { + await workspacePage.rightSidebar + .getByRole("button", { name: "Options" }) + .click(); +}; + +test("Offers detach on a broken copy nested in a main", async ({ page }) => { + const workspacePage = new WorkspacePage(page); + await breakNestedCopies(workspacePage); + await workspacePage.clickLeafLayer("Nested in main"); + + await expect(brokenIndicator(workspacePage)).toBeVisible(); + await openComponentMenu(workspacePage); + await expect(page.getByText("Detach instance")).toBeVisible(); +}); + +test("Offers no detach on a broken copy nested in a copy", async ({ page }) => { + const workspacePage = new WorkspacePage(page); + await breakNestedCopies(workspacePage); + await workspacePage.clickLeafLayer("Nested in copy"); + + await expect(brokenIndicator(workspacePage)).toBeVisible(); + // A copy inside another copy has no menu entries, so no options button. + await expect( + workspacePage.rightSidebar.getByRole("button", { name: "Options" }), + ).toHaveCount(0); +});