Reuse the existing workspace drag interaction for pinned rows and persist their local order across grouping modes. Keep pressed and dragged row scrims aligned with the active backdrop, and preserve memoized row rendering on web.
111 lines
4.2 KiB
TypeScript
111 lines
4.2 KiB
TypeScript
import type { Locator } from "@playwright/test";
|
|
import { expect, test } from "../support/fixtures";
|
|
import { gotoAppShell } from "../support/helpers/app";
|
|
import { projectEquivalenceViewKey } from "../support/helpers/project-view-key";
|
|
import { getServerId } from "../support/helpers/server-id";
|
|
import { seedWorkspace } from "../support/helpers/seed-client";
|
|
import { waitForSidebarHydration } from "../support/helpers/workspace-ui";
|
|
|
|
async function rowTestIds(rows: Locator) {
|
|
return rows.evaluateAll((elements) =>
|
|
elements.map((element) => element.getAttribute("data-testid")),
|
|
);
|
|
}
|
|
|
|
async function visibleBoundingBox(row: Locator) {
|
|
const box = await row.boundingBox();
|
|
if (!box) throw new Error("Expected a visible draggable row");
|
|
return box;
|
|
}
|
|
|
|
async function pressProjectRow(rows: Locator) {
|
|
await rows.page().mouse.down();
|
|
}
|
|
|
|
async function pressWorkspaceRow(rows: Locator) {
|
|
const solidScrimStop = rows
|
|
.nth(0)
|
|
.getByTestId("sidebar-workspace-trailing-scrim")
|
|
.locator("stop")
|
|
.nth(1);
|
|
const hoverScrimColor = await solidScrimStop.getAttribute("stop-color");
|
|
await rows.page().mouse.down();
|
|
await expect.poll(() => solidScrimStop.getAttribute("stop-color")).not.toBe(hoverScrimColor);
|
|
}
|
|
|
|
async function quickDragFirstRowAfterSecond(
|
|
rows: Locator,
|
|
pressRow: (rows: Locator) => Promise<void>,
|
|
) {
|
|
await expect(rows).toHaveCount(2);
|
|
const before = await rowTestIds(rows);
|
|
const sourceBox = await visibleBoundingBox(rows.nth(0));
|
|
const targetBox = await visibleBoundingBox(rows.nth(1));
|
|
|
|
const page = rows.page();
|
|
const source = { x: sourceBox.x + sourceBox.width / 2, y: sourceBox.y + sourceBox.height / 2 };
|
|
const target = { x: targetBox.x + targetBox.width / 2, y: targetBox.y + targetBox.height / 2 };
|
|
|
|
await page.mouse.move(source.x, source.y);
|
|
const trailingScrim = rows.nth(0).getByTestId("sidebar-workspace-trailing-scrim");
|
|
await pressRow(rows);
|
|
await page.mouse.move(source.x, source.y + 7);
|
|
await expect(trailingScrim).toHaveCount(0);
|
|
await page.mouse.move(target.x, target.y, { steps: 4 });
|
|
await page.mouse.up();
|
|
|
|
await expect.poll(() => rowTestIds(rows)).toEqual([before[1], before[0]]);
|
|
}
|
|
|
|
test("projects, workspaces, and pinned chats reorder with an immediate mouse drag", async ({
|
|
page,
|
|
}) => {
|
|
const firstProject = await seedWorkspace({ repoPrefix: "sidebar-reorder-first-" });
|
|
const secondProject = await seedWorkspace({ repoPrefix: "sidebar-reorder-second-" });
|
|
|
|
try {
|
|
const secondWorkspace = await firstProject.client.createWorkspace({
|
|
source: {
|
|
kind: "directory",
|
|
path: firstProject.repoPath,
|
|
projectId: firstProject.projectId,
|
|
},
|
|
title: "Second workspace",
|
|
});
|
|
if (!secondWorkspace.workspace) {
|
|
throw new Error(secondWorkspace.error ?? "Failed to seed a second workspace");
|
|
}
|
|
|
|
await gotoAppShell(page);
|
|
await waitForSidebarHydration(page);
|
|
|
|
const firstProjectTestId = `sidebar-project-row-${projectEquivalenceViewKey(firstProject.projectKey)}`;
|
|
const secondProjectTestId = `sidebar-project-row-${projectEquivalenceViewKey(secondProject.projectKey)}`;
|
|
await quickDragFirstRowAfterSecond(
|
|
page.locator(`[data-testid="${firstProjectTestId}"], [data-testid="${secondProjectTestId}"]`),
|
|
pressProjectRow,
|
|
);
|
|
const firstWorkspaceTestId = `sidebar-workspace-row-${getServerId()}:${firstProject.workspaceId}`;
|
|
const secondWorkspaceTestId = `sidebar-workspace-row-${getServerId()}:${secondWorkspace.workspace.id}`;
|
|
await quickDragFirstRowAfterSecond(
|
|
page.locator(
|
|
`[data-testid="${firstWorkspaceTestId}"], [data-testid="${secondWorkspaceTestId}"]`,
|
|
),
|
|
pressWorkspaceRow,
|
|
);
|
|
|
|
await firstProject.client.setWorkspacePinned(firstProject.workspaceId, true);
|
|
await secondProject.client.setWorkspacePinned(secondProject.workspaceId, true);
|
|
const secondProjectWorkspaceTestId = `sidebar-workspace-row-${getServerId()}:${secondProject.workspaceId}`;
|
|
await quickDragFirstRowAfterSecond(
|
|
page.locator(
|
|
`[data-testid="${firstWorkspaceTestId}"], [data-testid="${secondProjectWorkspaceTestId}"]`,
|
|
),
|
|
pressWorkspaceRow,
|
|
);
|
|
} finally {
|
|
await firstProject.cleanup();
|
|
await secondProject.cleanup();
|
|
}
|
|
});
|