Update terminal activity E2E for finished attention
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import type { Page } from "@playwright/test";
|
import type { Page } from "@playwright/test";
|
||||||
import type { TerminalActivityState } from "@getpaseo/protocol/terminal-activity";
|
import type { TerminalActivity, TerminalActivityState } from "@getpaseo/protocol/terminal-activity";
|
||||||
import { createTempGitRepo } from "./workspace";
|
import { createTempGitRepo } from "./workspace";
|
||||||
import { navigateToTerminal, setupDeterministicPrompt } from "./terminal-perf";
|
import { navigateToTerminal, setupDeterministicPrompt } from "./terminal-perf";
|
||||||
import { connectSeedClient, type SeedDaemonClient } from "./seed-client";
|
import { connectSeedClient, type SeedDaemonClient } from "./seed-client";
|
||||||
@@ -84,6 +84,7 @@ export class TerminalE2EHarness {
|
|||||||
async waitForTerminalActivity(input: {
|
async waitForTerminalActivity(input: {
|
||||||
terminalId: string;
|
terminalId: string;
|
||||||
state: TerminalActivityState | null;
|
state: TerminalActivityState | null;
|
||||||
|
attentionReason?: TerminalActivity["attentionReason"] | null;
|
||||||
timeoutMs?: number;
|
timeoutMs?: number;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const timeoutMs = input.timeoutMs ?? 10_000;
|
const timeoutMs = input.timeoutMs ?? 10_000;
|
||||||
@@ -91,13 +92,21 @@ export class TerminalE2EHarness {
|
|||||||
while (Date.now() < deadline) {
|
while (Date.now() < deadline) {
|
||||||
const result = await this.client.listTerminals(this.tempRepo.path);
|
const result = await this.client.listTerminals(this.tempRepo.path);
|
||||||
const terminal = result.terminals.find((entry) => entry.id === input.terminalId);
|
const terminal = result.terminals.find((entry) => entry.id === input.terminalId);
|
||||||
if ((terminal?.activity?.state ?? null) === input.state) {
|
const activity = terminal?.activity ?? null;
|
||||||
|
const attentionMatches =
|
||||||
|
input.attentionReason === undefined ||
|
||||||
|
(activity?.attentionReason ?? null) === input.attentionReason;
|
||||||
|
if ((activity?.state ?? null) === input.state && attentionMatches) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await sleep(50);
|
await sleep(50);
|
||||||
}
|
}
|
||||||
|
const attentionSuffix =
|
||||||
|
input.attentionReason === undefined
|
||||||
|
? ""
|
||||||
|
: ` with attention ${input.attentionReason ?? "none"}`;
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Timed out waiting for terminal ${input.terminalId} activity state ${input.state ?? "unknown"}`,
|
`Timed out waiting for terminal ${input.terminalId} activity state ${input.state ?? "unknown"}${attentionSuffix}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { test, expect, type Page } from "./fixtures";
|
|||||||
import { TerminalE2EHarness, type TerminalInstance } from "./helpers/terminal-dsl";
|
import { TerminalE2EHarness, type TerminalInstance } from "./helpers/terminal-dsl";
|
||||||
|
|
||||||
type HookActivityState = "running" | "idle" | "needs-input";
|
type HookActivityState = "running" | "idle" | "needs-input";
|
||||||
type TabStatusBucket = "running" | "needs_input" | "none";
|
type TabStatusBucket = "running" | "needs_input" | "attention" | "none";
|
||||||
|
|
||||||
const TERMINAL_ACTIVITY_REPORTER_SCRIPT = `
|
const TERMINAL_ACTIVITY_REPORTER_SCRIPT = `
|
||||||
const fs = require("node:fs");
|
const fs = require("node:fs");
|
||||||
@@ -52,16 +52,21 @@ async function reportActivity(state) {
|
|||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function internalActivityState(state: HookActivityState): "working" | "idle" | "attention" {
|
function internalActivityState(state: HookActivityState): "working" | "idle" {
|
||||||
if (state === "running") return "working";
|
if (state === "running") return "working";
|
||||||
if (state === "needs-input") return "attention";
|
|
||||||
return "idle";
|
return "idle";
|
||||||
}
|
}
|
||||||
|
|
||||||
function tabStatusBucket(state: HookActivityState): TabStatusBucket {
|
function tabStatusBucket(state: HookActivityState): TabStatusBucket {
|
||||||
if (state === "running") return "running";
|
if (state === "running") return "running";
|
||||||
if (state === "needs-input") return "needs_input";
|
if (state === "needs-input") return "needs_input";
|
||||||
return "none";
|
return "attention";
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectedAttentionReason(state: HookActivityState): "finished" | "needs_input" | null {
|
||||||
|
if (state === "idle") return "finished";
|
||||||
|
if (state === "needs-input") return "needs_input";
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function terminalTab(page: Page, terminalId: string) {
|
function terminalTab(page: Page, terminalId: string) {
|
||||||
@@ -96,6 +101,7 @@ class ControlledActivityTerminal {
|
|||||||
await this.harness.waitForTerminalActivity({
|
await this.harness.waitForTerminalActivity({
|
||||||
terminalId: this.terminal.id,
|
terminalId: this.terminal.id,
|
||||||
state: internalActivityState(state),
|
state: internalActivityState(state),
|
||||||
|
attentionReason: expectedAttentionReason(state),
|
||||||
timeoutMs: 15_000,
|
timeoutMs: 15_000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -166,6 +172,7 @@ test.describe("Terminal activity indicators", () => {
|
|||||||
await harness.waitForTerminalActivity({
|
await harness.waitForTerminalActivity({
|
||||||
terminalId: activityTerminal.terminal.id,
|
terminalId: activityTerminal.terminal.id,
|
||||||
state: "idle",
|
state: "idle",
|
||||||
|
attentionReason: null,
|
||||||
timeoutMs: 15_000,
|
timeoutMs: 15_000,
|
||||||
});
|
});
|
||||||
await expectTerminalTabStatus(page, activityTerminal.terminal.id, "none");
|
await expectTerminalTabStatus(page, activityTerminal.terminal.id, "none");
|
||||||
|
|||||||
Reference in New Issue
Block a user