Files
paseo/packages/server/src/shared/messages.workspaces.test.ts
T

354 lines
10 KiB
TypeScript

import { describe, expect, test } from "vitest";
import { SessionInboundMessageSchema, SessionOutboundMessageSchema } from "./messages.js";
describe("workspace message schemas", () => {
test("parses fetch_workspaces_request", () => {
const parsed = SessionInboundMessageSchema.parse({
type: "fetch_workspaces_request",
requestId: "req-1",
filter: {
query: "repo",
projectId: 12,
idPrefix: "/Users/me",
},
sort: [{ key: "activity_at", direction: "desc" }],
page: { limit: 50 },
subscribe: {},
});
expect(parsed.type).toBe("fetch_workspaces_request");
});
test("parses open_project_request", () => {
const parsed = SessionInboundMessageSchema.parse({
type: "open_project_request",
cwd: "/tmp/repo",
requestId: "req-open",
});
expect(parsed.type).toBe("open_project_request");
});
test("parses list_available_editors_request", () => {
const parsed = SessionInboundMessageSchema.parse({
type: "list_available_editors_request",
requestId: "req-editors",
});
expect(parsed.type).toBe("list_available_editors_request");
});
test("parses open_in_editor_request with flexible editor ids", () => {
const knownEditor = SessionInboundMessageSchema.parse({
type: "open_in_editor_request",
requestId: "req-open-webstorm",
editorId: "webstorm",
path: "/tmp/repo",
});
const unknownEditor = SessionInboundMessageSchema.parse({
type: "open_in_editor_request",
requestId: "req-open-custom",
editorId: "unknown-editor",
path: "/tmp/repo",
});
expect(knownEditor.type).toBe("open_in_editor_request");
expect(unknownEditor.type).toBe("open_in_editor_request");
});
test("parses open_in_editor_response", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "open_in_editor_response",
payload: {
requestId: "req-open-editor",
error: null,
},
});
expect(parsed.type).toBe("open_in_editor_response");
});
test("parses list_available_editors_response with unknown editor ids", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "list_available_editors_response",
payload: {
requestId: "req-editors",
editors: [
{ id: "cursor", label: "Cursor" },
{ id: "unknown-editor", label: "Unknown Editor" },
],
error: null,
},
});
expect(parsed.type).toBe("list_available_editors_response");
});
test("rejects empty editor ids", () => {
const result = SessionInboundMessageSchema.safeParse({
type: "open_in_editor_request",
requestId: "req-open-empty",
editorId: "",
path: "/tmp/repo",
});
expect(result.success).toBe(false);
});
test("rejects invalid workspace update payload", () => {
const result = SessionOutboundMessageSchema.safeParse({
type: "workspace_update",
payload: {
kind: "upsert",
workspace: {
id: 1,
projectId: 1,
projectDisplayName: "repo",
projectRootPath: "/repo",
projectKind: "directory",
workspaceKind: "checkout",
name: "",
status: "not-a-bucket",
activityAt: null,
scripts: [],
},
},
});
expect(result.success).toBe(false);
});
test("parses workspace descriptors with scripts", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "workspace_update",
payload: {
kind: "upsert",
workspace: {
id: 1,
projectId: 1,
projectDisplayName: "repo",
projectRootPath: "/repo",
workspaceDirectory: "/repo",
projectKind: "directory",
workspaceKind: "checkout",
name: "repo",
status: "done",
activityAt: null,
scripts: [
{
scriptName: "web",
hostname: "web.localhost",
port: 3000,
proxyUrl: "http://web.localhost:6767",
lifecycle: "running",
health: "healthy",
},
],
},
},
});
expect(parsed.type).toBe("workspace_update");
if (parsed.type !== "workspace_update" || parsed.payload.kind !== "upsert") {
throw new Error("Expected workspace_update upsert payload");
}
expect(parsed.payload.workspace.scripts).toEqual([
{
scriptName: "web",
type: "service",
hostname: "web.localhost",
port: 3000,
proxyUrl: "http://web.localhost:6767",
lifecycle: "running",
health: "healthy",
exitCode: null,
},
]);
});
test("parses legacy workspace descriptor enum values", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "workspace_update",
payload: {
kind: "upsert",
workspace: {
id: "legacy-workspace",
projectId: "legacy-project",
projectDisplayName: "repo",
projectRootPath: "/repo",
workspaceDirectory: "/repo",
projectKind: "non_git",
workspaceKind: "directory",
name: "repo",
status: "done",
activityAt: null,
scripts: [],
},
},
});
expect(parsed.type).toBe("workspace_update");
if (parsed.type !== "workspace_update" || parsed.payload.kind !== "upsert") {
throw new Error("Expected workspace_update upsert payload");
}
expect(parsed.payload.workspace.projectKind).toBe("non_git");
expect(parsed.payload.workspace.workspaceKind).toBe("directory");
});
test("parses script_status_update payload", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "script_status_update",
payload: {
workspaceId: "/repo",
scripts: [
{
scriptName: "web",
hostname: "web.localhost",
port: null,
proxyUrl: null,
lifecycle: "stopped",
health: null,
},
],
},
});
expect(parsed.type).toBe("script_status_update");
expect(parsed.payload.workspaceId).toBe("/repo");
expect(parsed.payload.scripts[0]).toMatchObject({
type: "service",
exitCode: null,
});
});
test("parses workspace_setup_progress payload", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "workspace_setup_progress",
payload: {
workspaceId: "/repo/.paseo/worktrees/feature-a",
status: "completed",
detail: {
type: "worktree_setup",
worktreePath: "/repo/.paseo/worktrees/feature-a",
branchName: "feature-a",
log: "done",
commands: [
{
index: 1,
command: "npm install",
cwd: "/repo/.paseo/worktrees/feature-a",
log: "done",
status: "completed",
exitCode: 0,
durationMs: 100,
},
],
},
error: null,
},
});
expect(parsed.type).toBe("workspace_setup_progress");
});
test("parses workspace_setup_status_request", () => {
const parsed = SessionInboundMessageSchema.parse({
type: "workspace_setup_status_request",
workspaceId: "/repo/.paseo/worktrees/feature-a",
requestId: "req-status",
});
expect(parsed.type).toBe("workspace_setup_status_request");
});
test("parses workspace_setup_status_response payload", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "workspace_setup_status_response",
payload: {
requestId: "req-status",
workspaceId: "/repo/.paseo/worktrees/feature-a",
snapshot: {
status: "completed",
detail: {
type: "worktree_setup",
worktreePath: "/repo/.paseo/worktrees/feature-a",
branchName: "feature-a",
log: "done",
commands: [],
},
error: null,
},
},
});
expect(parsed.type).toBe("workspace_setup_status_response");
});
test("parses legacy fetch_agents_response checkout payloads without worktreeRoot", () => {
const result = SessionOutboundMessageSchema.safeParse({
type: "fetch_agents_response",
payload: {
requestId: "req-1",
entries: [
{
agent: {
id: "agent-1",
provider: "codex",
cwd: "C:\\repo",
model: null,
features: [],
thinkingOptionId: null,
effectiveThinkingOptionId: null,
createdAt: "2026-04-04T00:00:00.000Z",
updatedAt: "2026-04-04T00:00:00.000Z",
lastUserMessageAt: null,
status: "running",
capabilities: {
supportsStreaming: true,
supportsSessionPersistence: true,
supportsDynamicModes: true,
supportsMcpServers: true,
supportsReasoningStream: true,
supportsToolInvocations: true,
},
currentModeId: null,
availableModes: [],
pendingPermissions: [],
persistence: null,
title: "Agent 1",
labels: {},
requiresAttention: false,
attentionReason: null,
},
project: {
projectKey: "remote:github.com/acme/repo",
projectName: "acme/repo",
checkout: {
cwd: "C:\\repo",
isGit: true,
currentBranch: "main",
remoteUrl: "https://github.com/acme/repo.git",
isPaseoOwnedWorktree: false,
mainRepoRoot: null,
},
},
},
],
pageInfo: {
nextCursor: null,
prevCursor: null,
hasMore: false,
},
},
});
expect(result.success).toBe(true);
if (!result.success) {
return;
}
const checkout = result.data.payload.entries[0]?.project.checkout;
expect(checkout?.worktreeRoot).toBe("C:\\repo");
});
});