Files
kandev/apps/web/e2e/tests/settings/executor-profile-routing.spec.ts
2026-09-22 21:24:43 +01:00

127 lines
5.7 KiB
TypeScript

import type { Page } from "@playwright/test";
import { expect, test } from "../../fixtures/test-base";
import { waitForHttp } from "../../helpers/causal-waits";
import { setSettingsMenuMode } from "../../helpers/settings-menu";
const INITIAL_IMAGE_TAG = "kandev/e2e:routing-initial";
const EDITED_IMAGE_TAG = "kandev/e2e:routing-edited";
const DRAFT_IMAGE_TAG = "kandev/e2e:routing-draft";
const DOCKERFILE = "FROM busybox\nWORKDIR /workspace\n";
function canonicalProfilePath(profileId: string): string {
return `/settings/executors/${encodeURIComponent(profileId)}`;
}
async function expectDockerProfileEditor(testPage: Page, profileId: string) {
await expect(testPage).toHaveURL(canonicalProfilePath(profileId));
await expect(testPage.locator("#image-tag")).toBeVisible();
await expect(testPage.getByText("Dockerfile", { exact: true })).toBeVisible();
await expect(testPage.getByRole("button", { name: "Build Image" })).toBeVisible();
}
test.describe("executor profile routing", () => {
test("converges desktop entry points on the complete Docker profile editor", async ({
testPage,
apiClient,
}) => {
test.setTimeout(60_000);
const executor = await apiClient.createExecutor("E2E profile routing executor", "local_docker");
const profile = await apiClient.createExecutorProfile(executor.id, {
name: "E2E profile routing Docker",
config: { dockerfile: DOCKERFILE, image_tag: INITIAL_IMAGE_TAG },
prepare_script: "",
cleanup_script: "",
env_vars: [],
});
await testPage.route("**/api/v1/docker/build", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/x-ndjson",
body: JSON.stringify({ stream: "Successfully built\n" }) + "\n",
});
});
try {
await testPage.goto("/settings/executors");
const profileCard = testPage.getByTestId(`executor-profile-card-${profile.id}`);
await expect(profileCard).toBeVisible();
await expect(profileCard.getByText(profile.name, { exact: true })).toBeVisible();
await profileCard.click();
await expectDockerProfileEditor(testPage, profile.id);
const buildResponse = waitForHttp(testPage, "POST", /^\/api\/v1\/docker\/build$/, {
predicate: (response) => response.ok(),
});
await testPage.getByRole("button", { name: "Build Image" }).click();
await buildResponse;
await expect(testPage.getByText("Success", { exact: true })).toBeVisible();
await testPage.locator("#image-tag").fill(EDITED_IMAGE_TAG);
const floatingSave = testPage.getByTestId("settings-floating-save");
const saveResponse = waitForHttp(
testPage,
"PATCH",
/^\/api\/v1\/executors\/[^/]+\/profiles\/[^/]+$/,
{ predicate: (response) => response.ok() },
);
await floatingSave.getByRole("button", { name: "Save changes" }).click();
await saveResponse;
await expect(testPage.getByText("Profile saved")).toBeVisible();
await expect
.poll(
async () =>
(await apiClient.getExecutorProfile(executor.id, profile.id)).config?.image_tag,
)
.toBe(EDITED_IMAGE_TAG);
await testPage.reload();
await expect(testPage.locator("#image-tag")).toHaveValue(EDITED_IMAGE_TAG);
await setSettingsMenuMode(testPage, "accordion");
const settingsTree = testPage.getByTestId("app-sidebar-settings-mode");
const expandExecutors = settingsTree.getByRole("button", { name: /Expand Executors/i });
if (await expandExecutors.count()) await expandExecutors.click();
const expandExecutor = settingsTree.getByRole("button", {
name: `Expand ${executor.name}`,
});
if (await expandExecutor.count()) await expandExecutor.click();
const profileLink = settingsTree.locator(`a[href="${canonicalProfilePath(profile.id)}"]`);
await expect(profileLink).toBeVisible({ timeout: 10_000 });
await profileLink.click();
await expectDockerProfileEditor(testPage, profile.id);
await testPage.goto(`/settings/executor/${encodeURIComponent(executor.id)}`);
await testPage.getByText(profile.name, { exact: true }).click();
await expectDockerProfileEditor(testPage, profile.id);
const legacyBookmark =
`/settings/executor/${encodeURIComponent(executor.id)}/profile/${encodeURIComponent(profile.id)}` +
"?tab=advanced#docker";
await testPage.goto(legacyBookmark);
await expect(testPage).toHaveURL(`${canonicalProfilePath(profile.id)}?tab=advanced#docker`);
await expect(testPage.locator("#image-tag")).toHaveValue(EDITED_IMAGE_TAG);
await expect(testPage.getByRole("button", { name: "Build Image" })).toBeVisible();
await testPage.locator("#image-tag").fill(DRAFT_IMAGE_TAG);
const executorsLink = settingsTree.locator('a[href="/settings/executors"]');
await executorsLink.click();
const leaveDialog = testPage.getByRole("alertdialog");
await expect(leaveDialog).toBeVisible();
await leaveDialog.getByRole("button", { name: "Continue editing" }).click();
await expect(testPage).toHaveURL(`${canonicalProfilePath(profile.id)}?tab=advanced#docker`);
await expect(testPage.locator("#image-tag")).toHaveValue(DRAFT_IMAGE_TAG);
await executorsLink.click();
await expect(leaveDialog).toBeVisible();
await leaveDialog.getByRole("button", { name: "Discard and leave" }).click();
await expect(testPage).toHaveURL(/\/settings\/executors$/);
await testPage.goto(canonicalProfilePath(profile.id));
await expect(testPage.locator("#image-tag")).toHaveValue(EDITED_IMAGE_TAG);
} finally {
await apiClient.deleteExecutor(executor.id).catch(() => {});
}
});
});