tests/e2e/workspace-changed-files.spec.ts
Rama main · réplica de lectura del repositorio original.
import { expect, test } from "@playwright/test";
import { enableScopedE2EAuth, scopedPath } from "./helpers/auth";
import {
initializeTrackedEvents,
mockActivationFlow,
} from "./helpers/activation-fixtures";
type ChangesPayload = {
branch: string;
baseBranch: string;
ahead: number;
behind: number;
files: Array<{
path: string;
status: string;
additions: number;
deletions: number;
}>;
};
const DIRTY: ChangesPayload = {
branch: "mogplex/agent-e2e",
baseBranch: "main",
ahead: 0,
behind: 0,
files: [
{ path: "src/app.ts", status: "modified", additions: 3, deletions: 1 },
{ path: "docs/new.md", status: "untracked", additions: 7, deletions: 0 },
],
};
test("the agent pane lists sandbox changes with diff, revert, and commit actions", async ({
page,
}) => {
await initializeTrackedEvents(page);
await enableScopedE2EAuth(page);
await mockActivationFlow(page);
let changes: ChangesPayload = DIRTY;
let delayedStatus: Promise<void> | null = null;
const posts: Array<Record<string, unknown>> = [];
await page.route(
/\/api\/sandbox\/[^/]+\/changes(?:\?.*)?$/,
async (route) => {
const request = route.request();
const url = new URL(request.url());
if (request.method() === "GET" && url.searchParams.has("path")) {
await route.fulfill({
json: {
path: url.searchParams.get("path"),
diff: "--- a/src/app.ts\n+++ b/src/app.ts\n@@ -1,2 +1,2 @@\n-const old = 1;\n+const fresh = 2;\n unchanged\n",
},
});
return;
}
if (request.method() === "GET") {
if (delayedStatus) await delayedStatus;
await route.fulfill({ json: changes });
return;
}
const body = request.postDataJSON() as Record<string, unknown>;
posts.push(body);
if (body.action === "revert") {
const reverted = new Set(body.paths as string[]);
changes = {
...changes,
files: changes.files.filter((file) => !reverted.has(file.path)),
};
await route.fulfill({ json: { reverted: [...reverted], changes } });
return;
}
changes = { ...changes, files: [], ahead: 1 };
await route.fulfill({
json: {
committed: true,
sha: "abc123",
pushed: true,
pullRequestUrl: "https://github.com/acme/demo-app/pull/7",
changes,
},
});
}
);
await page.goto(scopedPath("projects/workspace"));
await page.waitForLoadState("networkidle");
await page.getByTestId("home-sync-repos").click();
await page.getByTestId("home-open-workspace-repo-1").click();
await expect(page.getByTestId("preview-grab-button")).toBeEnabled();
const bar = page.getByTestId("changed-files-bar");
await expect(bar).toContainText("2 files changed");
await expect(bar).toContainText("mogplex/agent-e2e");
await page.getByTestId("changed-files-toggle").click();
await expect(page.getByTestId("changed-file-src/app.ts")).toBeVisible();
await page
.getByTestId("changed-file-src/app.ts")
.getByText("src/app.ts")
.click();
await expect(page.getByRole("dialog")).toContainText("const fresh = 2;");
await page.keyboard.press("Escape");
await page
.getByTestId("changed-file-docs/new.md")
.getByTestId("changed-file-revert")
.click();
await page
.getByTestId("changed-file-docs/new.md")
.getByTestId("changed-file-revert-confirm")
.click();
await expect(bar).toContainText("1 file changed");
expect(posts[0]).toEqual({ action: "revert", paths: ["docs/new.md"] });
await page.getByTestId("changed-files-commit").click();
const message = page.getByTestId("changed-files-commit-message");
await message.fill("Rename the constant");
let releaseStatus!: () => void;
delayedStatus = new Promise<void>((resolve) => {
releaseStatus = resolve;
});
const refreshRequest = page.waitForRequest(
(request) =>
request.method() === "GET" && request.url().endsWith("/changes")
);
await page.getByRole("button", { name: "Refresh changes" }).click();
await refreshRequest;
try {
await expect(page.getByTestId("changed-files-revert-all")).toBeDisabled();
await expect(page.getByTestId("changed-files-commit-pr")).toBeDisabled();
} finally {
releaseStatus();
delayedStatus = null;
}
await expect(page.getByTestId("changed-files-commit-pr")).toBeEnabled();
await page.getByTestId("changed-files-commit-pr").click();
await expect(page.getByTestId("changed-files-delivery")).toContainText(
"Pushed mogplex/agent-e2e"
);
await expect(
page.getByRole("link", { name: "Open pull request" })
).toHaveAttribute("href", "https://github.com/acme/demo-app/pull/7");
expect(posts[1]).toEqual({
action: "commit",
message: "Rename the constant",
push: true,
openPullRequest: true,
});
});
test("clean ahead branches retain push recovery after a failed delivery and remount", async ({
page,
}) => {
await initializeTrackedEvents(page);
await enableScopedE2EAuth(page);
await mockActivationFlow(page);
let changes: ChangesPayload = DIRTY;
let failPush = true;
await page.route(/\/api\/sandbox\/[^/]+\/changes$/, async (route) => {
if (route.request().method() === "GET") {
await route.fulfill({ json: changes });
return;
}
changes = { ...DIRTY, files: [], ahead: 1 };
if (failPush) {
failPush = false;
await route.fulfill({ status: 500, json: { error: "Push failed" } });
} else {
changes = { ...changes, ahead: 0 };
await route.fulfill({
json: { committed: false, pushed: true, sha: "abc123", changes },
});
}
});
const openWorkspace = async () => {
await page.goto(scopedPath("projects/workspace"));
await page.getByTestId("home-sync-repos").click();
await page.getByTestId("home-open-workspace-repo-1").click();
};
await openWorkspace();
await page.getByTestId("changed-files-commit").click();
await page
.getByTestId("changed-files-commit-message")
.fill("Commit before push fails");
await page.getByTestId("changed-files-commit-push").click();
await expect(
page.getByRole("alert").filter({ hasText: "Push failed" })
).toBeVisible();
// Re-entering the workspace reconstructs state from Git, without a local
// delivery result or the old error keeping the panel visible.
await page.reload();
await expect(page.getByTestId("changed-files-bar")).toContainText(
"0 files changed"
);
await expect(page.getByTestId("changed-files-commit")).toHaveText("Push");
await page.getByTestId("changed-files-commit").click();
await expect(page.getByTestId("changed-files-commit-push")).toBeEnabled();
await page.getByTestId("changed-files-commit-push").click();
await expect(page.getByTestId("changed-files-delivery")).toContainText(
"Pushed"
);
});