126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { type Page } from "@playwright/test";
|
|
import { test, expect } from "../../fixtures/test-base";
|
|
import type { SeedData } from "../../fixtures/test-base";
|
|
import type { ApiClient } from "../../helpers/api-client";
|
|
import { SessionPage } from "../../pages/session-page";
|
|
|
|
/**
|
|
* Resolve the code-server install directory. Checks the default kandev install
|
|
* path at ~/.kandev/tools/code-server/ (real HOME, not e2e temp HOME).
|
|
*/
|
|
function findCodeServerInstall(): string | null {
|
|
const home = os.homedir();
|
|
const installDir = path.join(home, ".kandev", "tools", "code-server");
|
|
if (!fs.existsSync(installDir)) return null;
|
|
|
|
const entries = fs.readdirSync(installDir);
|
|
for (const entry of entries) {
|
|
const binPath = path.join(installDir, entry, "bin", "code-server");
|
|
if (fs.existsSync(binPath)) return installDir;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Seed a task + session via the API and navigate directly to the session page.
|
|
* Waits for the mock agent to complete its turn (idle input visible).
|
|
*/
|
|
async function seedTaskWithSession(
|
|
testPage: Page,
|
|
apiClient: ApiClient,
|
|
seedData: SeedData,
|
|
title: string,
|
|
): Promise<{ session: SessionPage; sessionId: string }> {
|
|
const task = await apiClient.createTaskWithAgent(
|
|
seedData.workspaceId,
|
|
title,
|
|
seedData.agentProfileId,
|
|
{
|
|
description: "/e2e:simple-message",
|
|
workflow_id: seedData.workflowId,
|
|
workflow_step_id: seedData.startStepId,
|
|
repository_ids: [seedData.repositoryId],
|
|
},
|
|
);
|
|
|
|
if (!task.session_id) throw new Error("createTaskWithAgent did not return a session_id");
|
|
|
|
await testPage.goto(`/t/${task.id}`);
|
|
|
|
const session = new SessionPage(testPage);
|
|
await session.waitForLoad();
|
|
await expect(session.idleInput()).toBeVisible({ timeout: 30_000 });
|
|
|
|
return { session, sessionId: task.session_id };
|
|
}
|
|
|
|
test.describe("VS Code open panel", () => {
|
|
test.describe.configure({ retries: 1 });
|
|
|
|
const codeServerDir = findCodeServerInstall();
|
|
|
|
test.beforeEach(async ({ backend }) => {
|
|
if (!codeServerDir) {
|
|
test.skip(true, "code-server not installed — skipping VS Code e2e tests");
|
|
return;
|
|
}
|
|
|
|
// Symlink the real code-server install into the e2e backend's HOME so
|
|
// ResolveBinary finds the pre-installed binary without re-downloading.
|
|
const targetDir = path.join(backend.tmpDir, ".kandev", "tools", "code-server");
|
|
if (!fs.existsSync(targetDir)) {
|
|
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
fs.symlinkSync(codeServerDir, targetDir);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Regression test for VS Code panel placement.
|
|
*
|
|
* Adding the VS Code panel via the dockview "+" menu must place it in the
|
|
* center group (alongside agent sessions), not in the right sidebar.
|
|
*/
|
|
test("opens VS Code panel in the center group", async ({ testPage, apiClient, seedData }) => {
|
|
const pageErrors: Error[] = [];
|
|
testPage.on("pageerror", (err) => pageErrors.push(err));
|
|
|
|
const { session } = await seedTaskWithSession(
|
|
testPage,
|
|
apiClient,
|
|
seedData,
|
|
"VSCode Open Panel Test",
|
|
);
|
|
|
|
// Open the "+" dropdown in the center group header and click "VS Code"
|
|
await session.addPanelButton().click();
|
|
await testPage.getByRole("menuitem", { name: "VS Code" }).click();
|
|
|
|
// Assert: VS Code tab appears in dockview
|
|
await expect(session.vscodeTab()).toBeVisible({ timeout: 10_000 });
|
|
|
|
// Assert: VS Code tab is in the center group (same tab bar as the session),
|
|
// not in the right sidebar.
|
|
const centerTabBar = testPage.locator(
|
|
".dv-tabs-and-actions-container:has(.dv-default-tab:has-text('VS Code'))",
|
|
);
|
|
await expect(centerTabBar.locator("[data-testid^='session-tab-']")).toBeVisible({
|
|
timeout: 5_000,
|
|
});
|
|
|
|
// Assert: "Starting VS Code Server" progress text is visible while booting
|
|
await expect(testPage.getByText("Starting VS Code Server")).toBeVisible({ timeout: 30_000 });
|
|
|
|
// Assert: code-server iframe loads
|
|
await expect(session.vscodeIframe()).toBeVisible({ timeout: 90_000 });
|
|
|
|
// Assert: no dockview referencePanel errors were thrown
|
|
const referencePanelErrors = pageErrors.filter(
|
|
(e) => e.message.includes("referencePanel") && e.message.includes("does not exist"),
|
|
);
|
|
expect(referencePanelErrors).toHaveLength(0);
|
|
});
|
|
});
|