@@ -2525,34 +2525,59 @@ test.describe("Workspace Manager V2 bootstrap", () => {
25252525 await expect(page.locator("#statusLog")).toHaveValue(/OK Grouped 2 shapes into group-1\./);
25262526 await expect(selectedShapeActions.locator("[data-shape-list-action='ungroup']")).toBeEnabled();
25272527 await expect(page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-shape-group-id='group-1']")).toHaveCount(2);
2528- const groupIconColors = await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-shape-group-id='group-1']").evaluateAll((icons) => icons.map((icon) => getComputedStyle(icon).color));
2528+ const groupIconColors = await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-shape-group-id='group-1'] .object-vector-studio-v2__shape-group-indicator ").evaluateAll((icons) => icons.map((icon) => getComputedStyle(icon).color));
25292529 expect(new Set(groupIconColors).size).toBe(1);
25302530 expect(groupIconColors[0]).not.toBe("");
25312531 const groupIconLayout = await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] .object-vector-studio-v2__object-tile-shape-row").first().evaluate((row) => {
25322532 const label = row.querySelector(".object-vector-studio-v2__shape-select-label");
2533+ const visibility = row.querySelector("[data-shape-visibility-index]");
25332534 const deleteButton = row.querySelector("[data-shape-delete-index]");
2534- const groupIcon = row.querySelector("[data-shape-group-id='group-1']");
2535+ const groupButton = row.querySelector("[data-shape-group-id='group-1']");
25352536 const rowRect = row.getBoundingClientRect();
25362537 const labelRect = label.getBoundingClientRect();
2538+ const visibilityRect = visibility.getBoundingClientRect();
25372539 const deleteRect = deleteButton.getBoundingClientRect();
2538- const groupRect = groupIcon .getBoundingClientRect();
2540+ const groupRect = groupButton .getBoundingClientRect();
25392541 return {
2540- groupAfterActions: groupRect.left > deleteRect.right,
2541- groupAtFarRight: Math.abs(rowRect.right - groupRect.right) <= 4,
2542+ actionButtonOrder: Array.from(row.querySelectorAll(".object-vector-studio-v2__shape-inline-actions > button")).map((button) => {
2543+ if (button.matches("[data-shape-group-id]")) return "group";
2544+ if (button.matches("[data-shape-visibility-index]")) return "eye";
2545+ if (button.matches("[data-shape-delete-index]")) return "trash";
2546+ return "unknown";
2547+ }),
2548+ groupAfterLabel: groupRect.left > labelRect.right,
2549+ groupButtonTag: groupButton.tagName.toLowerCase(),
2550+ groupBeforeEye: groupRect.right < visibilityRect.left,
25422551 labelStartsLeft: labelRect.left < deleteRect.left,
2543- labelText: label.textContent.trim()
2552+ labelText: label.textContent.trim(),
2553+ nestedButtons: row.querySelectorAll(".object-vector-studio-v2__shape-select button").length,
2554+ trashAtFarRight: Math.abs(rowRect.right - deleteRect.right) <= 4
25442555 };
25452556 });
25462557 expect(groupIconLayout).toEqual({
2547- groupAfterActions: true,
2548- groupAtFarRight: true,
2558+ actionButtonOrder: ["group", "eye", "trash"],
2559+ groupAfterLabel: true,
2560+ groupButtonTag: "button",
2561+ groupBeforeEye: true,
25492562 labelStartsLeft: true,
2550- labelText: "1. Circle"
2563+ labelText: "1. Circle",
2564+ nestedButtons: 0,
2565+ trashAtFarRight: true
25512566 });
25522567 await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-object-tile-shape-index='0']").click();
25532568 await expect(page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-object-tile-shape-index='0']")).toHaveAttribute("aria-pressed", "true");
25542569 await expect(page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-object-tile-shape-index='1']")).toHaveAttribute("aria-pressed", "true");
25552570 await expect(page.locator("#statusLog")).toHaveValue(/Multi-select count: 2/);
2571+ await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] .object-vector-studio-v2__object-tile-shape-row:has([data-object-tile-shape-index='1']) [data-shape-group-id='group-1']").click();
2572+ await expect.poll(async () => page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)).toBe(0);
2573+ await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-shape-visibility-index='1']").click();
2574+ await expect.poll(async () => page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)).toBe(0);
2575+ await expect(page.locator("#statusLog")).toHaveValue(/[Ss]hape row 1 visibility set to hidden/);
2576+ await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-shape-visibility-index='1']").click();
2577+ await expect.poll(async () => page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)).toBe(0);
2578+ await expect(page.locator("#statusLog")).toHaveValue(/[Ss]hape row 1 visibility set to visible/);
2579+ await page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-object-tile-shape-index='1']").click();
2580+ await expect.poll(async () => page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)).toBe(1);
25562581 await selectedShapeActions.locator("[data-shape-list-action='ungroup']").click();
25572582 await expect(page.locator("#objectVectorStudioV2JsonDetails")).not.toContainText('"groupId": "group-1"');
25582583 await expect(page.locator(".object-vector-studio-v2__object-tile[data-object-id='object.asteroids.object-1'] [data-shape-group-id='group-1']")).toHaveCount(0);
@@ -2656,21 +2681,45 @@ test.describe("Workspace Manager V2 bootstrap", () => {
26562681 await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveAttribute("viewBox", "-16000 -11000 32000 22000");
26572682 await page.locator("#objectVectorStudioV2ResetViewButton").click();
26582683 await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveAttribute("viewBox", "-1600 -1100 3200 2200");
2659- await page.locator("#objectVectorStudioV2RenderSurface").hover();
2684+ const wheelAnchor = await page.locator("#objectVectorStudioV2RenderSurface").evaluate((surface) => {
2685+ const rect = surface.getBoundingClientRect();
2686+ const clientX = Math.round(rect.left + rect.width * 0.75);
2687+ const clientY = Math.round(rect.top + rect.height * 0.35);
2688+ return {
2689+ before: window.__objectVectorStudioV2App.viewportPointFromClient(clientX, clientY),
2690+ clientX,
2691+ clientY
2692+ };
2693+ });
2694+ await page.mouse.move(wheelAnchor.clientX, wheelAnchor.clientY);
26602695 await page.mouse.wheel(0, -240);
26612696 await expect(page.locator("#objectVectorStudioV2CoordinateDisplay")).toContainText("Zoom 110%");
26622697 await expect(page.locator("#objectVectorStudioV2RenderSurface [data-grid-rendered='true']")).toHaveCount(1);
26632698 await expect(page.locator("#objectVectorStudioV2RenderSurface [data-center-origin='0,0']")).toHaveCount(1);
2664- const zoomedGridState = await page.locator("#objectVectorStudioV2RenderSurface").evaluate((surface) => ({
2665- backgroundImage: getComputedStyle(surface).backgroundImage,
2666- gridLineCount: surface.querySelectorAll("[data-grid-rendered='true'] line").length,
2667- viewBox: surface.getAttribute("viewBox")
2668- }));
2699+ const zoomedGridState = await page.locator("#objectVectorStudioV2RenderSurface").evaluate((surface, anchor) => {
2700+ const app = window.__objectVectorStudioV2App;
2701+ const after = app.viewportPointFromClient(anchor.clientX, anchor.clientY);
2702+ return {
2703+ backgroundImage: getComputedStyle(surface).backgroundImage,
2704+ gridLineCount: surface.querySelectorAll("[data-grid-rendered='true'] line").length,
2705+ pointerDelta: {
2706+ x: Math.abs(after.x - anchor.before.x),
2707+ y: Math.abs(after.y - anchor.before.y)
2708+ },
2709+ viewport: { ...app.viewport },
2710+ viewBox: surface.getAttribute("viewBox")
2711+ };
2712+ }, wheelAnchor);
26692713 expect(zoomedGridState.backgroundImage).toBe("none");
26702714 expect(zoomedGridState.gridLineCount).toBeGreaterThan(0);
2671- expect(zoomedGridState.viewBox).toBe("-1454.545 -1000 2909.091 2000");
2715+ expect(zoomedGridState.pointerDelta.x).toBeLessThan(0.001);
2716+ expect(zoomedGridState.pointerDelta.y).toBeLessThan(0.001);
2717+ expect(Math.abs(zoomedGridState.viewport.x)).toBeGreaterThan(1);
2718+ expect(Math.abs(zoomedGridState.viewport.y)).toBeGreaterThan(1);
2719+ expect(zoomedGridState.viewBox).not.toBe("-1454.545 -1000 2909.091 2000");
26722720 await page.mouse.wheel(0, 240);
26732721 await expect(page.locator("#objectVectorStudioV2CoordinateDisplay")).toContainText("Zoom 100%");
2722+ await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveAttribute("viewBox", "-1600 -1100 3200 2200");
26742723 await page.evaluate(() => {
26752724 window.__objectVectorStudioV2App.zoomViewport(0.25);
26762725 });
@@ -3581,7 +3630,10 @@ test.describe("Workspace Manager V2 bootstrap", () => {
35813630 iconKey: "delete",
35823631 iconName: "nf-md-trash_can_outline"
35833632 });
3633+ await page.evaluate(() => window.__objectVectorStudioV2App.selectShape(0, "trash click selection guard"));
3634+ await expect.poll(async () => page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)).toBe(0);
35843635 await page.locator("[data-shape-delete-index='2']").click();
3636+ await expect.poll(async () => page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)).toBe(0);
35853637 await expect(page.locator("[data-object-tile-shape-index='2']")).toHaveCount(0);
35863638 await expect(page.locator("[data-object-tile-shape-index='1']")).toHaveCount(1);
35873639 await expect(page.locator("[data-object-tile-shape-index='0']")).toHaveCount(1);
0 commit comments