From 756471be71785caf15bdf9fab2dd439a575ffd73 Mon Sep 17 00:00:00 2001 From: Aidan Daly Date: Thu, 24 Sep 2026 21:17:45 +0000 Subject: [PATCH 1/5] test(harness): inline imperative screen configuration --- .../harness/create/create.screen.test.tsx | 55 ++++++++++++---- .../harness/delete/delete.screen.test.tsx | 33 ++++++++-- .../endpoint/create/create.screen.test.tsx | 16 +++-- .../endpoint/delete/delete.screen.test.tsx | 16 +++-- .../endpoint/list/list.screen.test.tsx | 32 ++++++++-- .../endpoint/update/update.screen.test.tsx | 16 +++-- .../harness/exec/exec.screen.test.tsx | 32 ++++++---- src/handlers/harness/get/get.screen.test.tsx | 40 +++++++++--- .../harness/invoke/invoke.screen.test.tsx | 64 +++++++++++++------ .../harness/list/list.screen.test.tsx | 13 +++- .../harness/update/update.screen.test.tsx | 43 ++++++++++--- .../harness/version/list/list.screen.test.tsx | 40 +++++++++--- 12 files changed, 300 insertions(+), 100 deletions(-) diff --git a/src/handlers/harness/create/create.screen.test.tsx b/src/handlers/harness/create/create.screen.test.tsx index e4e07a3283..66062d9247 100644 --- a/src/handlers/harness/create/create.screen.test.tsx +++ b/src/handlers/harness/create/create.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { CreateHarnessResponse } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -38,7 +39,10 @@ function coreForCreate(): TestCoreClient { describe("harness create wizard", () => { test("walks name → model → memory → tools → prompt → review and creates", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // Step: name. await waitForText(r.lastFrame, "the name of your harness"); @@ -120,7 +124,10 @@ describe("harness create wizard", () => { }); test("reveals model fields only after enter and hides them again on escape", async () => { - const r = renderImperativeScreen("/agentcore/harness/create", { core: coreForCreate() }); + const r = renderScreen("/agentcore/harness/create", { + core: coreForCreate(), + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -142,7 +149,10 @@ describe("harness create wizard", () => { test("selecting gemini collects the model id and api key arn", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -185,7 +195,10 @@ describe("harness create wizard", () => { test("openai requires the model id and api key arn and sends them", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -233,7 +246,10 @@ describe("harness create wizard", () => { test("litellm omits the optional fields left empty", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -273,7 +289,10 @@ describe("harness create wizard", () => { test("service default sends no model", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -304,7 +323,10 @@ describe("harness create wizard", () => { }); test("rejects an invalid name and stays on the name step", async () => { - const r = renderImperativeScreen("/agentcore/harness/create", { core: coreForCreate() }); + const r = renderScreen("/agentcore/harness/create", { + core: coreForCreate(), + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("9bad name"); @@ -318,7 +340,10 @@ describe("harness create wizard", () => { test("bring-your-own memory requires an ARN", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -364,7 +389,10 @@ describe("harness create wizard", () => { core.harness.createHarness = async () => { throw new Error("name already exists"); }; - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "the name of your harness"); await r.write("my_agent"); @@ -397,7 +425,10 @@ describe("harness create wizard", () => { status: "READY", }, } as never); - const r = renderImperativeScreen("/agentcore/harness/create", { core }); + const r = renderScreen("/agentcore/harness/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // Fastest path through the wizard: defaults everywhere. await waitForText(r.lastFrame, "the name of your harness"); @@ -431,7 +462,7 @@ describe("harness create wizard", () => { const core = coreForCreate(); core.harness.setListResponse({ harnesses: [] }); // Arrive from the harness menu so esc has somewhere to pop back to. - const r = renderImperativeScreen("/agentcore/harness", { core }); + const r = renderScreen("/agentcore/harness", { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); // `create` is the first menu item, so it is already selected. await waitForText(r.lastFrame, "❯ create"); await r.press("return"); diff --git a/src/handlers/harness/delete/delete.screen.test.tsx b/src/handlers/harness/delete/delete.screen.test.tsx index dc8b04daa4..0354aa63f1 100644 --- a/src/handlers/harness/delete/delete.screen.test.tsx +++ b/src/handlers/harness/delete/delete.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { GetHarnessResponse } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -50,7 +51,10 @@ function coreWithHarness(): TestCoreClient { describe("harness delete screen", () => { test("without a harness id, picking a harness opens its confirmation", async () => { const core = coreWithHarness(); - const r = renderImperativeScreen("/agentcore/harness/delete", { core }); + const r = renderScreen("/agentcore/harness/delete", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); expect(r.lastFrame()).toContain("choose a harness to delete"); @@ -62,7 +66,10 @@ describe("harness delete screen", () => { test("shows the harness summary and a default-No confirmation", async () => { const core = coreWithHarness(); - const r = renderImperativeScreen("/agentcore/harness/delete/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/delete/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Delete harness MyHarness?"); const frame = r.lastFrame()!; @@ -74,7 +81,10 @@ describe("harness delete screen", () => { test("`y` calls DeleteHarness and shows the result", async () => { const core = coreWithHarness(); - const r = renderImperativeScreen("/agentcore/harness/delete/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/delete/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Delete harness MyHarness?"); await r.write("y"); @@ -88,7 +98,10 @@ describe("harness delete screen", () => { test("enter after success returns to the harness list", async () => { const core = coreWithHarness(); - const r = renderImperativeScreen("/agentcore/harness/delete/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/delete/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Delete harness MyHarness?"); await r.write("y"); @@ -100,7 +113,10 @@ describe("harness delete screen", () => { test("`n` cancels without calling DeleteHarness", async () => { const core = coreWithHarness(); - const r = renderImperativeScreen("/agentcore/harness/delete/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/delete/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Delete harness MyHarness?"); await r.write("n"); @@ -115,7 +131,10 @@ describe("harness delete screen", () => { core.harness.deleteHarness = async () => { throw new Error("delete conflict"); }; - const r = renderImperativeScreen("/agentcore/harness/delete/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/delete/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Delete harness MyHarness?"); await r.write("y"); diff --git a/src/handlers/harness/endpoint/create/create.screen.test.tsx b/src/handlers/harness/endpoint/create/create.screen.test.tsx index c6b8eb35ea..ff0d7fe8cf 100644 --- a/src/handlers/harness/endpoint/create/create.screen.test.tsx +++ b/src/handlers/harness/endpoint/create/create.screen.test.tsx @@ -4,11 +4,12 @@ import type { HarnessVersionSummary, } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../../testing"; afterEach(cleanupScreens); @@ -62,7 +63,10 @@ function coreForCreate(): TestCoreClient { describe("harness endpoint create wizard", () => { test("without a harness id, picking a harness opens the wizard", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/create", { core }); + const r = renderScreen("/agentcore/harness/endpoint/create", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); expect(r.lastFrame()).toContain("choose a harness to create an endpoint for"); @@ -74,8 +78,10 @@ describe("harness endpoint create wizard", () => { test("walks name → version → review and creates", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/create/MyHarness-abc123", { + const r = renderScreen("/agentcore/harness/endpoint/create/MyHarness-abc123", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "what should this endpoint be called?"); @@ -123,8 +129,10 @@ describe("harness endpoint create wizard", () => { test("keeping `latest` omits targetVersion from the request", async () => { const core = coreForCreate(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/create/MyHarness-abc123", { + const r = renderScreen("/agentcore/harness/endpoint/create/MyHarness-abc123", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "what should this endpoint be called?"); diff --git a/src/handlers/harness/endpoint/delete/delete.screen.test.tsx b/src/handlers/harness/endpoint/delete/delete.screen.test.tsx index c700d79e6d..344c178439 100644 --- a/src/handlers/harness/endpoint/delete/delete.screen.test.tsx +++ b/src/handlers/harness/endpoint/delete/delete.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { HarnessEndpoint } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../../testing"; afterEach(cleanupScreens); @@ -53,7 +54,10 @@ function coreWithEndpoint(): TestCoreClient { describe("harness endpoint delete screen", () => { test("walks from harness picker to endpoint picker to confirmation", async () => { const core = coreWithEndpoint(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/delete", { core }); + const r = renderScreen("/agentcore/harness/endpoint/delete", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); await r.press("return"); @@ -66,8 +70,10 @@ describe("harness endpoint delete screen", () => { test("`y` calls DeleteHarnessEndpoint and shows the result", async () => { const core = coreWithEndpoint(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/delete/MyHarness-abc123/prod", { + const r = renderScreen("/agentcore/harness/endpoint/delete/MyHarness-abc123/prod", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "Delete endpoint prod?"); @@ -82,8 +88,10 @@ describe("harness endpoint delete screen", () => { test("`n` cancels without calling DeleteHarnessEndpoint", async () => { const core = coreWithEndpoint(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/delete/MyHarness-abc123/prod", { + const r = renderScreen("/agentcore/harness/endpoint/delete/MyHarness-abc123/prod", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "Delete endpoint prod?"); diff --git a/src/handlers/harness/endpoint/list/list.screen.test.tsx b/src/handlers/harness/endpoint/list/list.screen.test.tsx index 2fd5744b7d..b02badc5e3 100644 --- a/src/handlers/harness/endpoint/list/list.screen.test.tsx +++ b/src/handlers/harness/endpoint/list/list.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { HarnessEndpoint } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../../testing"; afterEach(cleanupScreens); @@ -50,7 +51,10 @@ function coreWithEndpoints(endpoints: HarnessEndpoint[]): TestCoreClient { describe("harness endpoint list screen", () => { test("without a harness id, picking a harness lists its endpoints", async () => { const core = coreWithEndpoints([endpoint()]); - const r = renderImperativeScreen("/agentcore/harness/endpoint/list", { core }); + const r = renderScreen("/agentcore/harness/endpoint/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // Harness picker first. await waitForText(r.lastFrame, "MyHarness"); @@ -65,7 +69,10 @@ describe("harness endpoint list screen", () => { test("makes one exact scoped endpoint list call", async () => { const core = coreWithEndpoints([endpoint()]); - const r = renderImperativeScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitFor(() => core.harness.calls.some((call) => call.method === "listHarnessEndpoints")); expect(core.harness.calls.filter((call) => call.method === "listHarnessEndpoints")).toEqual([ @@ -95,7 +102,10 @@ describe("harness endpoint list screen", () => { updatedAt: new Date("2026-07-18T02:00:00.000Z"), }), ]); - const r = renderImperativeScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "visible-endpoint"); const frame = r.lastFrame()!; @@ -111,7 +121,10 @@ describe("harness endpoint list screen", () => { test("uses harness-specific first-page wording", async () => { const core = coreWithEndpoints([]); - const r = renderImperativeScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "This harness has no endpoints."); expect(r.lastFrame()).not.toContain("No endpoints on this page"); @@ -121,7 +134,10 @@ describe("harness endpoint list screen", () => { test("enter on a row opens the endpoint's JSON detail", async () => { const core = coreWithEndpoints([endpoint()]); core.harness.setGetEndpointResponse({ endpoint: endpoint() }); - const r = renderImperativeScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/endpoint/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "prod"); await r.press("return"); @@ -136,8 +152,10 @@ describe("harness endpoint list screen", () => { test("retries a failed endpoint detail without losing its selectors", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("endpoint unavailable")); - const r = renderImperativeScreen("/agentcore/harness/endpoint/get/MyHarness-abc123/prod", { + const r = renderScreen("/agentcore/harness/endpoint/get/MyHarness-abc123/prod", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "endpoint unavailable"); expect(r.lastFrame()).toContain("[r] retry"); diff --git a/src/handlers/harness/endpoint/update/update.screen.test.tsx b/src/handlers/harness/endpoint/update/update.screen.test.tsx index 9fcde20105..5b43e48b8d 100644 --- a/src/handlers/harness/endpoint/update/update.screen.test.tsx +++ b/src/handlers/harness/endpoint/update/update.screen.test.tsx @@ -4,11 +4,12 @@ import type { HarnessVersionSummary, } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../../testing"; afterEach(cleanupScreens); @@ -72,7 +73,10 @@ function coreForUpdate(): TestCoreClient { describe("harness endpoint update wizard", () => { test("walks harness picker → endpoint picker → wizard", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/update", { core }); + const r = renderScreen("/agentcore/harness/endpoint/update", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); await r.press("return"); @@ -85,8 +89,10 @@ describe("harness endpoint update wizard", () => { test("repointing at a new version submits only targetVersion", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/update/MyHarness-abc123/prod", { + const r = renderScreen("/agentcore/harness/endpoint/update/MyHarness-abc123/prod", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); // The endpoint's current target (version 1) is preselected; no "latest" @@ -113,8 +119,10 @@ describe("harness endpoint update wizard", () => { test("keeping the version unchanged submits only the endpoint identity", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/endpoint/update/MyHarness-abc123/prod", { + const r = renderScreen("/agentcore/harness/endpoint/update/MyHarness-abc123/prod", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "● version 1"); diff --git a/src/handlers/harness/exec/exec.screen.test.tsx b/src/handlers/harness/exec/exec.screen.test.tsx index 94bed2947c..42844cc7b8 100644 --- a/src/handlers/harness/exec/exec.screen.test.tsx +++ b/src/handlers/harness/exec/exec.screen.test.tsx @@ -6,12 +6,13 @@ import type { } from "@aws-sdk/client-bedrock-agentcore"; import type { GetHarnessResponse, HarnessSummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, cleanupScreens, StreamController, TestCoreClient, waitFor, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -57,7 +58,7 @@ function execCore(): TestCoreClient { return core; } -async function type(r: ReturnType, text: string) { +async function type(r: ReturnType, text: string) { await r.write(text); await r.press("return"); } @@ -66,7 +67,10 @@ describe("exec screen", () => { test("the exec route opens a picker, and selection lands in exec mode", async () => { const core = execCore(); core.harness.setListResponse({ harnesses: [summary()] }); - const r = renderImperativeScreen("/agentcore/harness/exec", { core }); + const r = renderScreen("/agentcore/harness/exec", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "choose a harness to exec into"); await waitForText(r.lastFrame, "MyHarness"); @@ -79,7 +83,7 @@ describe("exec screen", () => { test("enter runs the command in the chat session's container and shows output inline", async () => { const core = execCore(); - const r = renderImperativeScreen(EXEC_PATH, { core }); + const r = renderScreen(EXEC_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "run a command…"); await type(r, "ls /"); @@ -103,7 +107,10 @@ describe("exec screen", () => { test("a session id in the route resumes that session", async () => { const resumed = "resumed-session-0123456789abcdefghijklmn"; // 33+ chars const core = execCore(); - const r = renderImperativeScreen(`${EXEC_PATH}/${resumed}`, { core }); + const r = renderScreen(`${EXEC_PATH}/${resumed}`, { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, `session: ${resumed}`); await type(r, "pwd"); @@ -120,7 +127,7 @@ describe("exec screen", () => { { chunk: { contentDelta: { stderr: "ls: cannot access '/nope'\n" } } }, { chunk: { contentStop: { exitCode: 2, status: "COMPLETED" } } }, ); - const r = renderImperativeScreen(EXEC_PATH, { core }); + const r = renderScreen(EXEC_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "run a command…"); await type(r, "ls /nope"); @@ -131,7 +138,7 @@ describe("exec screen", () => { }); test("ctrl+e flips between exec and chat mode", async () => { - const r = renderImperativeScreen(EXEC_PATH, { core: execCore() }); + const r = renderScreen(EXEC_PATH, { core: execCore(), globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "run a command…"); expect(r.lastFrame()).toContain("[ctrl+e] chat mode"); @@ -148,7 +155,10 @@ describe("exec screen", () => { test("chat turns and exec commands share one session and one transcript", async () => { const core = execCore(); // Start on the invoke route (chat mode), then toggle into exec mode. - const r = renderImperativeScreen("/agentcore/harness/invoke/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/invoke/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "send a message…"); await type(r, "hi agent"); @@ -177,7 +187,7 @@ describe("exec screen", () => { const core = execCore(); const stream = new StreamController(); core.harness.queueExecStream(stream); - const r = renderImperativeScreen(EXEC_PATH, { core }); + const r = renderScreen(EXEC_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "run a command…"); await type(r, "sleep 999"); @@ -194,7 +204,7 @@ describe("exec screen", () => { test("an exec failure renders a ✗ error item and recovers to idle", async () => { const core = execCore(); - const r = renderImperativeScreen(EXEC_PATH, { core }); + const r = renderScreen(EXEC_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "run a command…"); core.harness.setError(new Error("runtime unreachable")); @@ -207,7 +217,7 @@ describe("exec screen", () => { test("empty input in exec mode does not run anything", async () => { const core = execCore(); - const r = renderImperativeScreen(EXEC_PATH, { core }); + const r = renderScreen(EXEC_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "run a command…"); await r.press("return"); diff --git a/src/handlers/harness/get/get.screen.test.tsx b/src/handlers/harness/get/get.screen.test.tsx index 58479cab8f..0f167344fc 100644 --- a/src/handlers/harness/get/get.screen.test.tsx +++ b/src/handlers/harness/get/get.screen.test.tsx @@ -9,12 +9,13 @@ import type { Harness, } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, flatFrame, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; import { buildHarnessLinkNodes } from "./screen"; @@ -45,7 +46,13 @@ function getResponse(): GetHarnessResponse { function hubScreen() { const core = new TestCoreClient(); core.harness.setGetResponse(getResponse()); - return { core, r: renderImperativeScreen("/agentcore/harness/get/MyHarness-abc123", { core }) }; + return { + core, + r: renderScreen("/agentcore/harness/get/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }), + }; } describe("harness hub screen", () => { @@ -73,7 +80,10 @@ describe("harness hub screen", () => { failureReason: "Execution role is unavailable", }, }); - const r = renderImperativeScreen("/agentcore/harness/get/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/get/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "show the full JSON definition"); expect(r.lastFrame()).toMatch(/failureReason\s+Execution role is unavailable/); }); @@ -103,7 +113,10 @@ describe("harness hub screen", () => { test("shows the error message when the get call fails", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("harness not found")); - const r = renderImperativeScreen("/agentcore/harness/get/does-not-exist", { core }); + const r = renderScreen("/agentcore/harness/get/does-not-exist", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Error:"); expect(r.lastFrame()).toContain("harness not found"); @@ -184,7 +197,10 @@ describe("harness hub screen", () => { }, ], }); - const r = renderImperativeScreen("/agentcore/harness/get", { core }); + const r = renderScreen("/agentcore/harness/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // The redirect lands on the list, which fetches harnesses. await waitForText(r.lastFrame, "MyHarness"); @@ -274,7 +290,7 @@ function linkedHubScreen( name: "github-oauth", credentialProviderArn: OAUTH2_ARN, } as GetOauth2CredentialProviderResponse); - return { core, r: renderImperativeScreen(path, { core }) }; + return { core, r: renderScreen(path, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }) }; } // markedLines returns the lines carrying the ❯ focus marker. @@ -284,7 +300,7 @@ function markedLines(frame: string | undefined): string[] { // The action list has six entries, so five downs reach `update` and the sixth // crosses into the tree. -async function focusTree(r: ReturnType, row = 0) { +async function focusTree(r: ReturnType, row = 0) { for (let press = 0; press < 6 + row; press++) await r.press("down"); } @@ -727,7 +743,10 @@ describe("harness JSON detail screen", () => { const core = new TestCoreClient(); core.harness.setGetResponse(response); - const r = renderImperativeScreen("/agentcore/harness/get/MyHarness-abc123/json", { core }); + const r = renderScreen("/agentcore/harness/get/MyHarness-abc123/json", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "WRAP_SENTINEL"); r.unmount(); @@ -736,7 +755,10 @@ describe("harness JSON detail screen", () => { test("renders the harness JSON and scrolls without crashing", async () => { const core = new TestCoreClient(); core.harness.setGetResponse(getResponse()); - const r = renderImperativeScreen("/agentcore/harness/get/MyHarness-abc123/json", { core }); + const r = renderScreen("/agentcore/harness/get/MyHarness-abc123/json", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, '"harnessName"'); await r.press("down"); diff --git a/src/handlers/harness/invoke/invoke.screen.test.tsx b/src/handlers/harness/invoke/invoke.screen.test.tsx index e3714cc435..e2a2cb4471 100644 --- a/src/handlers/harness/invoke/invoke.screen.test.tsx +++ b/src/handlers/harness/invoke/invoke.screen.test.tsx @@ -5,12 +5,13 @@ import type { } from "@aws-sdk/client-bedrock-agentcore"; import type { GetHarnessResponse, HarnessSummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, StreamController, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -57,7 +58,7 @@ function chatCore(): TestCoreClient { } // sendMessage types `text` into the prompt and presses enter. -async function sendMessage(r: ReturnType, text: string) { +async function sendMessage(r: ReturnType, text: string) { await r.write(text); await r.press("return"); } @@ -71,7 +72,10 @@ describe("invoke picker screen", () => { summary({ harnessName: "beta", harnessId: "beta-2" }), ], }); - const r = renderImperativeScreen("/agentcore/harness/invoke", { core }); + const r = renderScreen("/agentcore/harness/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "alpha"); expect(r.lastFrame()).toContain("beta"); @@ -82,7 +86,10 @@ describe("invoke picker screen", () => { test("selecting a harness opens its chat", async () => { const core = chatCore(); core.harness.setListResponse({ harnesses: [summary()] }); - const r = renderImperativeScreen("/agentcore/harness/invoke", { core }); + const r = renderScreen("/agentcore/harness/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); await r.press("return"); @@ -95,7 +102,10 @@ describe("invoke picker screen", () => { test("shows the error message when the list call fails", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("access denied")); - const r = renderImperativeScreen("/agentcore/harness/invoke", { core }); + const r = renderScreen("/agentcore/harness/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Error:"); expect(r.lastFrame()).toContain("access denied"); @@ -105,7 +115,10 @@ describe("invoke picker screen", () => { test("esc returns to the harness menu", async () => { const core = new TestCoreClient(); core.harness.setListResponse({ harnesses: [summary()] }); - const r = renderImperativeScreen("/agentcore/harness/invoke", { core }); + const r = renderScreen("/agentcore/harness/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); await r.press("escape"); @@ -116,7 +129,7 @@ describe("invoke picker screen", () => { describe("invoke chat screen", () => { test("sending a message streams the reply and appends a turn summary", async () => { - const r = renderImperativeScreen(CHAT_PATH, { core: chatCore() }); + const r = renderScreen(CHAT_PATH, { core: chatCore(), globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "hi agent"); @@ -131,7 +144,7 @@ describe("invoke chat screen", () => { test("the session id is stable across sends and each send carries only the new message", async () => { const core = chatCore(); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "first"); @@ -155,7 +168,10 @@ describe("invoke chat screen", () => { test("a session id in the route resumes that session", async () => { const resumed = "resumed-session-0123456789abcdefghijklmn"; // 33+ chars const core = chatCore(); - const r = renderImperativeScreen(`${CHAT_PATH}/${resumed}`, { core }); + const r = renderScreen(`${CHAT_PATH}/${resumed}`, { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // The bottom bar shows the resumed session immediately. await waitForText(r.lastFrame, `session: ${resumed}`); @@ -194,7 +210,7 @@ describe("invoke chat screen", () => { }, ], }); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); expect(r.lastFrame()).toContain("qualifier: DEFAULT"); @@ -227,7 +243,7 @@ describe("invoke chat screen", () => { }, ], }); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await r.write("\x14"); // ctrl+t @@ -240,7 +256,10 @@ describe("invoke chat screen", () => { test("a qualifier in the route targets that endpoint", async () => { const core = chatCore(); - const r = renderImperativeScreen(`${CHAT_PATH}?qualifier=canary`, { core }); + const r = renderScreen(`${CHAT_PATH}?qualifier=canary`, { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "qualifier: canary"); await sendMessage(r, "hi"); @@ -313,7 +332,7 @@ describe("invoke chat screen", () => { { contentBlockStop: { contentBlockIndex: 0 } }, { messageStop: { stopReason: "end_turn" } }, ); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "weather?"); @@ -334,7 +353,7 @@ describe("invoke chat screen", () => { const core = chatCore(); const stream = new StreamController(); core.harness.queueInvokeStream(stream); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "take your time"); @@ -356,7 +375,7 @@ describe("invoke chat screen", () => { const core = chatCore(); const stream = new StreamController(); core.harness.queueInvokeStream(stream); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "hi"); @@ -376,7 +395,7 @@ describe("invoke chat screen", () => { test("an invoke failure renders a ✗ error item and recovers to idle", async () => { const core = chatCore(); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); // The harness detail is already fetched; only the upcoming invoke fails. @@ -391,7 +410,7 @@ describe("invoke chat screen", () => { test("shows the error screen when the harness detail fails to load", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("harness not found")); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "Error:"); expect(r.lastFrame()).toContain("harness not found"); @@ -401,7 +420,10 @@ describe("invoke chat screen", () => { test("esc while idle pops back to the picker", async () => { const core = chatCore(); core.harness.setListResponse({ harnesses: [summary()] }); - const r = renderImperativeScreen("/agentcore/harness/invoke", { core }); + const r = renderScreen("/agentcore/harness/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); await r.press("return"); @@ -414,7 +436,7 @@ describe("invoke chat screen", () => { test("submitting an empty prompt does not invoke", async () => { const core = chatCore(); - const r = renderImperativeScreen(CHAT_PATH, { core }); + const r = renderScreen(CHAT_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await r.press("return"); @@ -429,7 +451,7 @@ describe("invoke chat screen", () => { // Regression: sending clears the input from outside TextInput, which used // to leave its cursor stranded past the end of the (now shorter) value — // backspace then deleted nothing. - const r = renderImperativeScreen(CHAT_PATH, { core: chatCore() }); + const r = renderScreen(CHAT_PATH, { core: chatCore(), globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "hi agent"); @@ -445,7 +467,7 @@ describe("invoke chat screen", () => { }); test("arrow keys scroll the transcript without crashing", async () => { - const r = renderImperativeScreen(CHAT_PATH, { core: chatCore() }); + const r = renderScreen(CHAT_PATH, { core: chatCore(), globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "send a message…"); await sendMessage(r, "hi agent"); diff --git a/src/handlers/harness/list/list.screen.test.tsx b/src/handlers/harness/list/list.screen.test.tsx index dd3216afed..11d9c29d22 100644 --- a/src/handlers/harness/list/list.screen.test.tsx +++ b/src/handlers/harness/list/list.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { HarnessSummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -39,7 +40,10 @@ describe("harness list screen", () => { harness({ harnessName: "alpha", harnessId: "alpha-1", harnessVersion: "99999" }), harness({ harnessName: "beta", harnessId: "beta-2" }), ]); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "alpha"); const frame = r.lastFrame()!; @@ -55,7 +59,10 @@ describe("harness list screen", () => { test("makes one initial list request with context options", async () => { const core = coreWith([harness()]); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitFor(() => core.harness.calls.some((call) => call.method === "listHarnesses")); expect(core.harness.calls.filter((call) => call.method === "listHarnesses")).toEqual([ diff --git a/src/handlers/harness/update/update.screen.test.tsx b/src/handlers/harness/update/update.screen.test.tsx index bae16f9fe6..8c34f3686b 100644 --- a/src/handlers/harness/update/update.screen.test.tsx +++ b/src/handlers/harness/update/update.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { GetHarnessResponse } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -66,7 +67,10 @@ function coreForUpdate(): TestCoreClient { describe("harness update wizard", () => { test("without a harness id, picking a harness opens its wizard", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/update", { core }); + const r = renderScreen("/agentcore/harness/update", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); expect(r.lastFrame()).toContain("choose a harness to update"); @@ -77,7 +81,10 @@ describe("harness update wizard", () => { test("starts on model (no rename) with values prefilled from the harness", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // The harness has no bedrock model configured, so keep-current is // preselected; enter leaves the model untouched. @@ -103,7 +110,10 @@ describe("harness update wizard", () => { bedrockModelConfig: { modelId: "us.anthropic.claude-opus-4-8" }, }; core.harness.setGetResponse(current); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); // The harness's bedrock provider is preselected. Its persisted model id is // revealed after confirming the provider. @@ -139,7 +149,10 @@ describe("harness update wizard", () => { agentCoreMemoryConfiguration: { arn: memoryArn }, }; core.harness.setGetResponse(current); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "● keep current"); await r.press("return"); @@ -163,7 +176,10 @@ describe("harness update wizard", () => { test("changing the model submits a request with just that field", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "● keep current"); await r.press("down"); // bedrock @@ -191,7 +207,10 @@ describe("harness update wizard", () => { test("changing only the prompt submits a request with just that field", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "● keep current"); await r.press("return"); // model unchanged @@ -223,7 +242,10 @@ describe("harness update wizard", () => { test("disabling memory sends the wrapped disabled configuration", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "● keep current"); await r.press("return"); // model unchanged @@ -250,7 +272,10 @@ describe("harness update wizard", () => { test("toggling a tool off keeps unmodeled tools in the replacement list", async () => { const core = coreForUpdate(); - const r = renderImperativeScreen("/agentcore/harness/update/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/update/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "● keep current"); await r.press("return"); // model unchanged diff --git a/src/handlers/harness/version/list/list.screen.test.tsx b/src/handlers/harness/version/list/list.screen.test.tsx index f74621794c..e19bc5479b 100644 --- a/src/handlers/harness/version/list/list.screen.test.tsx +++ b/src/handlers/harness/version/list/list.screen.test.tsx @@ -1,11 +1,12 @@ import { test, expect, describe, afterEach } from "bun:test"; import type { HarnessVersionSummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { - renderImperativeScreen, + renderScreen, waitForText, waitFor, cleanupScreens, TestCoreClient, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../../testing"; afterEach(cleanupScreens); @@ -48,7 +49,10 @@ function coreWithVersions(versions: HarnessVersionSummary[]): TestCoreClient { describe("harness version list screen", () => { test("without a harness id, picking a harness lists its versions", async () => { const core = coreWithVersions([version({ harnessVersion: "42" })]); - const r = renderImperativeScreen("/agentcore/harness/version/list", { core }); + const r = renderScreen("/agentcore/harness/version/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "MyHarness"); expect(r.lastFrame()).toContain("choose a harness to list versions for"); @@ -61,7 +65,10 @@ describe("harness version list screen", () => { test("makes one exact scoped version list call", async () => { const core = coreWithVersions([version()]); - const r = renderImperativeScreen("/agentcore/harness/version/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/version/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitFor(() => core.harness.calls.some((call) => call.method === "listHarnessVersions")); expect(core.harness.calls.filter((call) => call.method === "listHarnessVersions")).toEqual([ @@ -86,7 +93,10 @@ describe("harness version list screen", () => { version({ harnessVersion: "2", status: "UPDATE_FAILED" }), version({ harnessVersion: "10", status: "READY" }), ]); - const r = renderImperativeScreen("/agentcore/harness/version/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/version/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "UPDATE_FAILED"); const frame = r.lastFrame()!; @@ -109,7 +119,10 @@ describe("harness version list screen", () => { createdAt: new Date("2026-07-18T02:00:00.000Z"), }), ]); - const r = renderImperativeScreen("/agentcore/harness/version/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/version/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "UPDATE_FAILED"); const frame = r.lastFrame()!; @@ -123,7 +136,9 @@ describe("harness version list screen", () => { }); test("uses harness-version wording for empty pages", async () => { - const firstPage = renderImperativeScreen("/agentcore/harness/version/list/MyHarness-abc123"); + const firstPage = renderScreen("/agentcore/harness/version/list/MyHarness-abc123", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(firstPage.lastFrame, "No versions found."); firstPage.unmount(); @@ -133,8 +148,10 @@ describe("harness version list screen", () => { nextToken: "v2", }); core.harness.setListVersionsResponse({ harnessVersions: [] }, "v2"); - const laterPage = renderImperativeScreen("/agentcore/harness/version/list/MyHarness-abc123", { + const laterPage = renderScreen("/agentcore/harness/version/list/MyHarness-abc123", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(laterPage.lastFrame, "page 1 · more →"); @@ -157,7 +174,10 @@ describe("harness version list screen", () => { status: "READY", }, } as Awaited>); - const r = renderImperativeScreen("/agentcore/harness/version/list/MyHarness-abc123", { core }); + const r = renderScreen("/agentcore/harness/version/list/MyHarness-abc123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "READY"); await r.press("return"); @@ -172,8 +192,10 @@ describe("harness version list screen", () => { test("retries a failed version detail without losing its selectors", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("version unavailable")); - const r = renderImperativeScreen("/agentcore/harness/version/get/MyHarness-abc123/42", { + const r = renderScreen("/agentcore/harness/version/get/MyHarness-abc123/42", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "version unavailable"); expect(r.lastFrame()).toContain("[r] retry"); From ea3104f978ecee4c2a2be2fa90620a69fb96dad1 Mon Sep 17 00:00:00 2001 From: Aidan Daly Date: Thu, 24 Sep 2026 21:18:15 +0000 Subject: [PATCH 2/5] test(gateway): inline imperative screen configuration --- .../gateway/gateway.mutations.screen.test.tsx | 22 ++- src/handlers/gateway/gateway.screen.test.tsx | 149 +++++++++++------- .../gateway/invoke/invoke.screen.test.tsx | 80 ++++++---- .../gateway/policy/generate.screen.test.tsx | 27 +++- 4 files changed, 181 insertions(+), 97 deletions(-) diff --git a/src/handlers/gateway/gateway.mutations.screen.test.tsx b/src/handlers/gateway/gateway.mutations.screen.test.tsx index 342c352f21..3f9f83fdd6 100644 --- a/src/handlers/gateway/gateway.mutations.screen.test.tsx +++ b/src/handlers/gateway/gateway.mutations.screen.test.tsx @@ -1,5 +1,11 @@ import { afterEach, describe, expect, test } from "bun:test"; -import { cleanupScreens, menuEntries, renderImperativeScreen, waitForText } from "../../testing"; +import { + cleanupScreens, + menuEntries, + renderScreen, + waitForText, + IMPERATIVE_GLOBAL_CONFIG, +} from "../../testing"; import { DEFAULT_GLOBAL_CONFIG } from "../../globalConfig"; afterEach(cleanupScreens); @@ -7,7 +13,7 @@ const GROUPS = ["gateway", "gateway/target", "gateway/connector", "gateway/rule" describe("Gateway mutation menus", () => { test.each(GROUPS)("%s omits disabled CLI-only mutations", async (group) => { - const screen = renderImperativeScreen(`/agentcore/${group}`); + const screen = renderScreen(`/agentcore/${group}`, { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "type to choose a command"); const entries = menuEntries(screen.lastFrame()!); expect(entries.cliOnly).toEqual([]); @@ -19,7 +25,7 @@ describe("Gateway mutation menus", () => { }); test.each(GROUPS)("%s preserves enabled CLI-only mutations", async (group) => { - const screen = renderImperativeScreen(`/agentcore/${group}`, { + const screen = renderScreen(`/agentcore/${group}`, { globalConfig: { ...DEFAULT_GLOBAL_CONFIG, "imperative-mutation-commands": true, @@ -34,7 +40,7 @@ describe("Gateway mutation menus", () => { }); test("disabled create opens project guidance and returns to the Gateway menu", async () => { - const screen = renderImperativeScreen("/agentcore/gateway"); + const screen = renderScreen("/agentcore/gateway", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "type to choose a command"); expect(menuEntries(screen.lastFrame()!).screens[0]).toBe("create"); await screen.press("return"); @@ -53,7 +59,7 @@ describe("Gateway mutation menus", () => { }); test.each([false, true])("direct create route matches flag %s", async (enabled) => { - const screen = renderImperativeScreen("/agentcore/gateway/create", { + const screen = renderScreen("/agentcore/gateway/create", { globalConfig: { ...DEFAULT_GLOBAL_CONFIG, "imperative-mutation-commands": enabled, @@ -80,14 +86,16 @@ describe("Gateway mutation menus", () => { .map((mutation) => `${group}/${mutation}`), ), )("disabled direct route %s cannot expose mutation help", async (path) => { - const screen = renderImperativeScreen(`/agentcore/${path}`); + const screen = renderScreen(`/agentcore/${path}`, { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(() => screen.frames.join("\n"), "Usage:"); expect(screen.frames.join("\n")).not.toContain("this command runs from the command line"); expect(screen.core.gateway.calls).toEqual([]); }); test("project guidance remains scrollable after resizing a small terminal", async () => { - const screen = renderImperativeScreen("/agentcore/gateway/create"); + const screen = renderScreen("/agentcore/gateway/create", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "Create an AgentCore Gateway"); await screen.resize(50, 12); await screen.write("\u001b[6~"); diff --git a/src/handlers/gateway/gateway.screen.test.tsx b/src/handlers/gateway/gateway.screen.test.tsx index e1b0a4afc2..d3cba006d0 100644 --- a/src/handlers/gateway/gateway.screen.test.tsx +++ b/src/handlers/gateway/gateway.screen.test.tsx @@ -11,10 +11,11 @@ import { } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitForText, menuEntries, + IMPERATIVE_GLOBAL_CONFIG, } from "../../testing"; afterEach(cleanupScreens); @@ -112,7 +113,7 @@ function coreWithGateways(items: GatewaySummary[]): TestCoreClient { describe("Gateway menu and list", () => { test("renders the Gateway command menu without calling Core", async () => { - const screen = renderImperativeScreen("/agentcore/gateway"); + const screen = renderScreen("/agentcore/gateway", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "manage AgentCore Gateways"); expect(menuEntries(screen.lastFrame()!)).toEqual({ @@ -124,9 +125,11 @@ describe("Gateway menu and list", () => { test("renders Gateway identity and calls list with exact Core options", async () => { const core = coreWithGateways([gateway()]); - const screen = renderImperativeScreen("/agentcore/gateway/list", { + const screen = renderScreen("/agentcore/gateway/list", { core, endpointUrl: ENDPOINT, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "checkout-gateway"); @@ -148,20 +151,28 @@ describe("Gateway menu and list", () => { const loadingCore = new TestCoreClient(); const pending = Promise.withResolvers(); loadingCore.gateway.listGateways = async () => pending.promise; - const loading = renderImperativeScreen("/agentcore/gateway/list", { core: loadingCore }); + const loading = renderScreen("/agentcore/gateway/list", { + core: loadingCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(loading.lastFrame, "loading Gateways"); await loading.press("escape"); await waitForText(loading.lastFrame, "manage AgentCore Gateways"); loading.unmount(); - const empty = renderImperativeScreen("/agentcore/gateway/list"); + const empty = renderScreen("/agentcore/gateway/list", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No Gateways found in this Region."); empty.unmount(); const errorCore = new TestCoreClient(); errorCore.gateway.setError(new Error("gateway unavailable")); - const error = renderImperativeScreen("/agentcore/gateway/list", { core: errorCore }); + const error = renderScreen("/agentcore/gateway/list", { + core: errorCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(error.lastFrame, "gateway unavailable"); expect(error.lastFrame()).toContain("[r] retry"); @@ -174,9 +185,11 @@ describe("Gateway menu and list", () => { test("selects a Gateway and renders only read-only hub actions", async () => { const core = coreWithGateways([gateway()]); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen("/agentcore/gateway/list", { + const screen = renderScreen("/agentcore/gateway/list", { core, endpointUrl: ENDPOINT, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "checkout-gateway"); @@ -203,23 +216,21 @@ describe("Gateway menu and list", () => { core.gateway.setGetResponse( gatewayDetail({ status: "FAILED", statusReasons: ["Role is unavailable", "Target failed"] }), ); - const screen = renderImperativeScreen( - `/agentcore/gateway/get/${encodeURIComponent(GATEWAY_ID)}`, - { - core, - }, - ); + const screen = renderScreen(`/agentcore/gateway/get/${encodeURIComponent(GATEWAY_ID)}`, { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); expect(screen.lastFrame()).toMatch(/statusReasons\s+Role is unavailable; Target failed/); screen.unmount(); core.gateway.setGetResponse(gatewayDetail({ statusReasons: [] })); - const ready = renderImperativeScreen( - `/agentcore/gateway/get/${encodeURIComponent(GATEWAY_ID)}`, - { - core, - }, - ); + const ready = renderScreen(`/agentcore/gateway/get/${encodeURIComponent(GATEWAY_ID)}`, { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(ready.lastFrame, "show the full JSON definition"); expect(ready.lastFrame()).not.toContain("statusReasons"); }); @@ -227,12 +238,11 @@ describe("Gateway menu and list", () => { test("opens complete Gateway JSON from the detail action", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen( - `/agentcore/gateway/get/${encodeURIComponent(GATEWAY_ID)}`, - { - core, - }, - ); + const screen = renderScreen(`/agentcore/gateway/get/${encodeURIComponent(GATEWAY_ID)}`, { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); await screen.press("return"); @@ -244,7 +254,10 @@ describe("Gateway menu and list", () => { test("bare Gateway get redirects to the Gateway picker", async () => { const core = coreWithGateways([gateway({ name: "redirected-gateway" })]); - const screen = renderImperativeScreen("/agentcore/gateway/get", { core }); + const screen = renderScreen("/agentcore/gateway/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "redirected-gateway"); expect(core.gateway.calls[0]?.method).toBe("listGateways"); @@ -253,7 +266,9 @@ describe("Gateway menu and list", () => { describe("Gateway Target flow", () => { test("renders the Target command menu without calling Core", async () => { - const screen = renderImperativeScreen("/agentcore/gateway/target"); + const screen = renderScreen("/agentcore/gateway/target", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "manage Targets for an AgentCore Gateway"); expect(menuEntries(screen.lastFrame()!)).toEqual({ @@ -268,7 +283,10 @@ describe("Gateway Target flow", () => { core.gateway.setListTargetsResponse({ items: [target(TARGET_ID, "orders-target", TargetType.PASSTHROUGH)], }); - const screen = renderImperativeScreen("/agentcore/gateway/target/list", { core }); + const screen = renderScreen("/agentcore/gateway/target/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "checkout-gateway"); await screen.press("return"); @@ -292,11 +310,13 @@ describe("Gateway Target flow", () => { items: [target(TARGET_ID, "orders-target", TargetType.PASSTHROUGH)], }) .setGetTargetResponse(targetDetail(TARGET_ID)); - const screen = renderImperativeScreen( + const screen = renderScreen( `/agentcore/gateway/target/list/${encodeURIComponent(GATEWAY_ID)}`, { core, endpointUrl: ENDPOINT, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }, ); @@ -324,7 +344,10 @@ describe("Gateway Target flow", () => { test("bare Target get redirects to Gateway selection", async () => { const core = coreWithGateways([gateway({ name: "target-parent" })]); - const screen = renderImperativeScreen("/agentcore/gateway/target/get", { core }); + const screen = renderScreen("/agentcore/gateway/target/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "target-parent"); expect(core.gateway.calls[0]?.method).toBe("listGateways"); @@ -337,7 +360,10 @@ describe("Gateway Target flow", () => { items: [target(TARGET_ID, "orders-target", TargetType.PASSTHROUGH)], }) .setGetTargetResponse(targetDetail(TARGET_ID)); - const screen = renderImperativeScreen("/agentcore/gateway/target/list", { core }); + const screen = renderScreen("/agentcore/gateway/target/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "checkout-gateway"); await screen.press("return"); @@ -356,7 +382,9 @@ describe("Gateway Target flow", () => { describe("Gateway Connector flow", () => { test("renders the separate Connector command menu without calling Core", async () => { - const screen = renderImperativeScreen("/agentcore/gateway/connector"); + const screen = renderScreen("/agentcore/gateway/connector", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "manage connectors configured for an AgentCore Gateway"); expect(menuEntries(screen.lastFrame()!)).toEqual({ @@ -371,7 +399,10 @@ describe("Gateway Connector flow", () => { core.gateway.setListConnectorsResponse({ items: [target(CONNECTOR_ID, "search-connector", TargetType.CONNECTOR)], }); - const screen = renderImperativeScreen("/agentcore/gateway/connector/list", { core }); + const screen = renderScreen("/agentcore/gateway/connector/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "checkout-gateway"); await screen.press("return"); @@ -390,9 +421,9 @@ describe("Gateway Connector flow", () => { items: [target(CONNECTOR_ID, "search-connector", TargetType.CONNECTOR)], }) .setGetConnectorResponse(targetDetail(CONNECTOR_ID, true)); - const screen = renderImperativeScreen( + const screen = renderScreen( `/agentcore/gateway/connector/list/${encodeURIComponent(GATEWAY_ID)}`, - { core }, + { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }, ); await waitForText(screen.lastFrame, "search-connector"); @@ -413,9 +444,9 @@ describe("Gateway Connector flow", () => { test("rejects a non-Connector Target opened through the Connector route", async () => { const core = new TestCoreClient(); core.gateway.setError(new Error(`Gateway Target "${TARGET_ID}" is not connector-backed`)); - const screen = renderImperativeScreen( + const screen = renderScreen( `/agentcore/gateway/connector/get/${encodeURIComponent(GATEWAY_ID)}/${encodeURIComponent(TARGET_ID)}`, - { core }, + { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }, ); await waitForText(screen.lastFrame, `Gateway Target "${TARGET_ID}" is not connector-backed`); @@ -423,8 +454,9 @@ describe("Gateway Connector flow", () => { }); test("shows the Gateway-level empty state when no Connectors exist", async () => { - const screen = renderImperativeScreen( + const screen = renderScreen( `/agentcore/gateway/connector/list/${encodeURIComponent(GATEWAY_ID)}`, + { globalConfig: IMPERATIVE_GLOBAL_CONFIG }, ); await waitForText(screen.lastFrame, "This Gateway has no connectors."); @@ -433,7 +465,10 @@ describe("Gateway Connector flow", () => { test("bare Connector get redirects to Gateway selection", async () => { const core = coreWithGateways([gateway({ name: "connector-parent" })]); - const screen = renderImperativeScreen("/agentcore/gateway/connector/get", { core }); + const screen = renderScreen("/agentcore/gateway/connector/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "connector-parent"); expect(core.gateway.calls[0]?.method).toBe("listGateways"); @@ -442,7 +477,9 @@ describe("Gateway Connector flow", () => { describe("Gateway Rule flow", () => { test("renders the Rule command menu without calling Core", async () => { - const screen = renderImperativeScreen("/agentcore/gateway/rule"); + const screen = renderScreen("/agentcore/gateway/rule", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "manage Rules for an AgentCore Gateway"); expect(menuEntries(screen.lastFrame()!)).toEqual({ @@ -455,7 +492,10 @@ describe("Gateway Rule flow", () => { test("selects a Gateway before listing Rules", async () => { const core = coreWithGateways([gateway()]); core.gateway.setListRulesResponse({ gatewayRules: [rule()] }); - const screen = renderImperativeScreen("/agentcore/gateway/rule/list", { core }); + const screen = renderScreen("/agentcore/gateway/rule/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "checkout-gateway"); await screen.press("return"); @@ -475,12 +515,11 @@ describe("Gateway Rule flow", () => { test("opens the selected Rule JSON with exact selectors", async () => { const core = new TestCoreClient(); core.gateway.setListRulesResponse({ gatewayRules: [rule()] }).setGetRuleResponse(ruleDetail()); - const screen = renderImperativeScreen( - `/agentcore/gateway/rule/list/${encodeURIComponent(GATEWAY_ID)}`, - { - core, - }, - ); + const screen = renderScreen(`/agentcore/gateway/rule/list/${encodeURIComponent(GATEWAY_ID)}`, { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "Route orders"); await screen.press("return"); @@ -498,12 +537,11 @@ describe("Gateway Rule flow", () => { test("keeps scoped lists empty and retryable", async () => { const core = new TestCoreClient(); core.gateway.setError(new Error("rules unavailable")); - const screen = renderImperativeScreen( - `/agentcore/gateway/rule/list/${encodeURIComponent(GATEWAY_ID)}`, - { - core, - }, - ); + const screen = renderScreen(`/agentcore/gateway/rule/list/${encodeURIComponent(GATEWAY_ID)}`, { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "rules unavailable"); expect(screen.lastFrame()).toContain("[r] retry"); @@ -515,7 +553,10 @@ describe("Gateway Rule flow", () => { test("bare Rule get redirects to Gateway selection", async () => { const core = coreWithGateways([gateway({ name: "rule-parent" })]); - const screen = renderImperativeScreen("/agentcore/gateway/rule/get", { core }); + const screen = renderScreen("/agentcore/gateway/rule/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "rule-parent"); expect(core.gateway.calls[0]?.method).toBe("listGateways"); diff --git a/src/handlers/gateway/invoke/invoke.screen.test.tsx b/src/handlers/gateway/invoke/invoke.screen.test.tsx index 6065e4c9e2..d54b023766 100644 --- a/src/handlers/gateway/invoke/invoke.screen.test.tsx +++ b/src/handlers/gateway/invoke/invoke.screen.test.tsx @@ -2,10 +2,11 @@ import { afterEach, describe, expect, test } from "bun:test"; import type { GatewaySummary, GetGatewayResponse } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; import type { GatewayInvokeRequest } from "../types"; import { GatewayInvokeLaunchContextKey } from "./launchContext"; @@ -62,7 +63,10 @@ describe("Gateway invoke routing", () => { test("selects a Gateway before opening the JSON console", async () => { const core = new TestCoreClient(); core.gateway.setListResponse({ items: [gatewaySummary()] }).setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen("/agentcore/gateway/invoke", { core }); + const screen = renderScreen("/agentcore/gateway/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "checkout-gateway"); await screen.press("return"); @@ -82,7 +86,10 @@ describe("Gateway invoke routing", () => { name: "AccessDeniedException", }); }; - const errorScreen = renderImperativeScreen(CONSOLE_PATH, { core }); + const errorScreen = renderScreen(CONSOLE_PATH, { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(errorScreen.lastFrame, "AccessDeniedException"); await waitForText(errorScreen.lastFrame, "not authorized for this Gateway"); @@ -94,7 +101,10 @@ describe("Gateway invoke routing", () => { signal = nextSignal; return new Promise(() => {}); }; - const pendingScreen = renderImperativeScreen(CONSOLE_PATH, { core: pendingCore }); + const pendingScreen = renderScreen(CONSOLE_PATH, { + core: pendingCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitFor(() => signal !== undefined && !signal.aborted); pendingScreen.unmount(); await waitFor(() => signal!.aborted); @@ -103,7 +113,7 @@ describe("Gateway invoke routing", () => { test("idle Escape returns through the invoke picker to the Gateway menu", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()).setListResponse({ items: [gatewaySummary()] }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.press("escape"); @@ -124,7 +134,7 @@ describe("Gateway invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Enter JSON payload"); const sessionId = displayedSessionId(screen.lastFrame()); @@ -155,7 +165,7 @@ describe("Gateway invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, `Auth: ${authorizerType}`); await screen.write("{}"); @@ -170,7 +180,7 @@ describe("Gateway invoke JSON console", () => { test("rejects invalid JSON without clearing the editor or invoking", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write('{"prompt":'); @@ -184,13 +194,15 @@ describe("Gateway invoke JSON console", () => { test("keeps the draft out of history when request normalization fails", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(GatewayInvokeLaunchContextKey, { gatewayId: GATEWAY_ID, path: "https://evil.example/path", }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Ready"); @@ -211,7 +223,7 @@ describe("Gateway invoke JSON console", () => { contentType: "application/json", body: responseBody(Buffer.from('{"ok":true}')), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(GatewayInvokeLaunchContextKey, { @@ -223,6 +235,8 @@ describe("Gateway invoke JSON console", () => { applicationHeaders: [["X-Tenant", "retail"]], bearerToken: token, }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Path: runtime/invocations"); @@ -247,7 +261,7 @@ describe("Gateway invoke JSON console", () => { test("proactively blocks CUSTOM_JWT submission without a bearer token", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail({ authorizerType: "CUSTOM_JWT" })); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "CUSTOM_JWT Gateway requires --bearer-token"); await screen.write("{}"); @@ -262,7 +276,7 @@ describe("Gateway invoke JSON console", () => { test("blocks a non-READY Gateway with its current status", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail({ status: "FAILED" })); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Gateway is FAILED; invocation requires READY"); await screen.write("{}"); @@ -278,7 +292,7 @@ describe("Gateway invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); const initialSession = displayedSessionId(screen.lastFrame()); @@ -300,7 +314,7 @@ describe("Gateway invoke JSON console", () => { const seededPath = "runtime/invocations"; const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(GatewayInvokeLaunchContextKey, { @@ -308,6 +322,8 @@ describe("Gateway invoke JSON console", () => { path: seededPath, runtimeSessionId: "seeded-session", }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, `Path: ${seededPath}`); @@ -333,7 +349,7 @@ describe("Gateway invoke JSON console", () => { mcpProtocolVersion: "2025-06-18", body: responseBody(Buffer.from("old response")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(GatewayInvokeLaunchContextKey, { @@ -341,6 +357,8 @@ describe("Gateway invoke JSON console", () => { bearerToken: "secret-token", applicationHeaders: [["X-Tenant", "retail"]], }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Ready"); @@ -383,7 +401,7 @@ describe("Gateway invoke JSON console", () => { mcpSessionId: "returned-mcp", body: responseBody(Buffer.from("old response")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(GatewayInvokeLaunchContextKey, { @@ -392,6 +410,8 @@ describe("Gateway invoke JSON console", () => { bearerToken: "secret-token", applicationHeaders: [["X-Tenant", "retail"]], }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Ready"); @@ -427,7 +447,7 @@ describe("Gateway invoke JSON console", () => { core.gateway .setGetResponse(gatewayDetail({ authorizerType: "CUSTOM_JWT" })) .setListResponse({ items: [gatewaySummary()] }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(GatewayInvokeLaunchContextKey, { @@ -437,6 +457,8 @@ describe("Gateway invoke JSON console", () => { bearerToken: "secret-token", applicationHeaders: [["X-Tenant", "retail"]], }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Ready"); @@ -466,7 +488,7 @@ describe("Gateway invoke JSON console", () => { yield Buffer.from("data: second\n"); })(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); const initialSession = displayedSessionId(screen.lastFrame()); @@ -509,7 +531,7 @@ describe("Gateway invoke JSON console", () => { mcpProtocolVersion: "2025-06-18", body: responseBody(Buffer.from('{"message":"invalid"}')), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -543,7 +565,7 @@ describe("Gateway invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("Temporary Redirect")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -564,7 +586,7 @@ describe("Gateway invoke JSON console", () => { contentType: "application/json", body: responseBody(Buffer.from(raw)), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -596,7 +618,7 @@ describe("Gateway invoke JSON console", () => { contentType, body: responseBody(bytes), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -623,7 +645,7 @@ describe("Gateway invoke JSON console", () => { }); })(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -644,7 +666,7 @@ describe("Gateway invoke JSON console", () => { contentType: "", body: responseBody(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -667,7 +689,7 @@ describe("Gateway invoke JSON console", () => { yield Buffer.from([0, 255]); })(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -708,7 +730,7 @@ describe("Gateway invoke JSON console", () => { })(), }; }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); const initialSession = displayedSessionId(screen.lastFrame()); @@ -731,7 +753,7 @@ describe("Gateway invoke JSON console", () => { test("keeps status and shortcuts stable at narrow terminal widths", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.resize(80, 24); @@ -746,7 +768,7 @@ describe("Gateway invoke JSON console", () => { test("horizontally windows long single-line JSON without corrupting status rows", async () => { const core = new TestCoreClient(); core.gateway.setGetResponse(gatewayDetail()); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await screen.resize(100, 24); await waitForText(screen.lastFrame, "Ready"); @@ -772,7 +794,7 @@ describe("Gateway invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from(response)), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await screen.resize(80, 16); await waitForText(screen.lastFrame, "Ready"); diff --git a/src/handlers/gateway/policy/generate.screen.test.tsx b/src/handlers/gateway/policy/generate.screen.test.tsx index d3562df762..600dd59bf0 100644 --- a/src/handlers/gateway/policy/generate.screen.test.tsx +++ b/src/handlers/gateway/policy/generate.screen.test.tsx @@ -2,9 +2,10 @@ import { afterEach, describe, expect, test } from "bun:test"; import type { GatewaySummary, GetGatewayResponse } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -38,8 +39,10 @@ function coreWith(engineArn: string | undefined): TestCoreClient { describe("gateway policy generate screen", () => { test("picks a gateway, then shows its engine and the prompt", async () => { - const screen = renderImperativeScreen("/agentcore/gateway/policy/generate", { + const screen = renderScreen("/agentcore/gateway/policy/generate", { core: coreWith(ENGINE_ARN), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "checkout-gateway"); @@ -53,8 +56,10 @@ describe("gateway policy generate screen", () => { }); test("escape returns the form through the picker to the Gateway menu", async () => { - const screen = renderImperativeScreen("/agentcore/gateway/policy/generate", { + const screen = renderScreen("/agentcore/gateway/policy/generate", { core: coreWith(ENGINE_ARN), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "checkout-gateway"); @@ -69,8 +74,10 @@ describe("gateway policy generate screen", () => { }); test("explains when the gateway has no engine and offers no prompt", async () => { - const screen = renderImperativeScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { + const screen = renderScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { core: coreWith(undefined), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "no Policy Engine attached"); @@ -91,8 +98,10 @@ describe("gateway policy generate screen", () => { { statement: PERMIT, findings: [] }, ], }; - const screen = renderImperativeScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { + const screen = renderScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, PLACEHOLDER); @@ -120,8 +129,10 @@ describe("gateway policy generate screen", () => { test("aborts the run and returns to the picker on esc while generating", async () => { const core = coreWith(ENGINE_ARN); core.policy.hang = true; - const screen = renderImperativeScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { + const screen = renderScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, PLACEHOLDER); @@ -137,8 +148,10 @@ describe("gateway policy generate screen", () => { test("shows the error and returns to the form on esc", async () => { const core = coreWith(ENGINE_ARN); core.policy.error = new Error("policy generation 'gen-1' failed: bad prompt"); - const screen = renderImperativeScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { + const screen = renderScreen(`/agentcore/gateway/policy/generate/${GATEWAY_ID}`, { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, PLACEHOLDER); From 08e2a16e15ef92e97e57cb8ad85c3c26ead27bf4 Mon Sep 17 00:00:00 2001 From: Aidan Daly Date: Thu, 24 Sep 2026 21:18:51 +0000 Subject: [PATCH 3/5] test(identity): inline imperative screen configuration --- .../apikey.screen.test.tsx | 83 +++++++------ .../oauth2.screen.test.tsx | 116 ++++++++++-------- 2 files changed, 111 insertions(+), 88 deletions(-) diff --git a/src/handlers/identity/api-key-credential-provider/apikey.screen.test.tsx b/src/handlers/identity/api-key-credential-provider/apikey.screen.test.tsx index 93f6026eb6..b1226ba42c 100644 --- a/src/handlers/identity/api-key-credential-provider/apikey.screen.test.tsx +++ b/src/handlers/identity/api-key-credential-provider/apikey.screen.test.tsx @@ -6,12 +6,13 @@ import type { import { QueryClient } from "@tanstack/react-query"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, tick, waitFor, waitForText, menuEntries, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -57,7 +58,9 @@ function coreWithProviders(providers: ApiKeyCredentialProviderItem[]): TestCoreC describe("API key credential provider menu", () => { test("lists the read-only commands, then the rest as command line only", async () => { - const screen = renderImperativeScreen("/agentcore/identity/api-key-credential-provider"); + const screen = renderScreen("/agentcore/identity/api-key-credential-provider", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "get an API key credential provider"); expect(menuEntries(screen.lastFrame()!)).toEqual({ @@ -76,8 +79,10 @@ describe("API key credential provider picker", () => { lastUpdatedTime: new Date("2026-07-21T02:03:04.000Z"), }), ]); - const screen = renderImperativeScreen("/agentcore/identity/api-key-credential-provider/list", { + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "visible-provider"); @@ -90,9 +95,11 @@ describe("API key credential provider picker", () => { test("calls listApiKeyCredentialProviders with exact Core options", async () => { const core = coreWithProviders([providerItem()]); - renderImperativeScreen("/agentcore/identity/api-key-credential-provider/list", { + renderScreen("/agentcore/identity/api-key-credential-provider/list", { core, endpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitFor(() => @@ -110,8 +117,10 @@ describe("API key credential provider picker", () => { test("caps maxResults at the service limit of 20 on a tall terminal", async () => { const core = coreWithProviders([providerItem()]); - const screen = renderImperativeScreen("/agentcore/identity/api-key-credential-provider/list", { + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); // Terminal taller than the 20-row service cap: page size must still clamp. await screen.resize(120, 60); @@ -126,7 +135,9 @@ describe("API key credential provider picker", () => { }); test("shows first-page and later-page empty states", async () => { - const empty = renderImperativeScreen("/agentcore/identity/api-key-credential-provider/list"); + const empty = renderScreen("/agentcore/identity/api-key-credential-provider/list", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No API key credential providers found in this Region."); empty.unmount(); @@ -136,8 +147,10 @@ describe("API key credential provider picker", () => { nextToken: "page-2", }); core.identity.setListApiKeyResponse({ credentialProviders: [] }, "page-2"); - const paged = renderImperativeScreen("/agentcore/identity/api-key-credential-provider/list", { + const paged = renderScreen("/agentcore/identity/api-key-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(paged.lastFrame, "page 1 · more →"); @@ -150,8 +163,10 @@ describe("API key credential provider picker", () => { test("bare get redirects to the picker", async () => { const core = coreWithProviders([providerItem({ name: "redirected" })]); - const screen = renderImperativeScreen("/agentcore/identity/api-key-credential-provider/get", { + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/get", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "redirected"); @@ -162,8 +177,10 @@ describe("API key credential provider picker", () => { const name = "api key blue"; const core = coreWithProviders([providerItem({ name })]); core.identity.setGetApiKeyResponse(getResponse({ name })); - const screen = renderImperativeScreen("/agentcore/identity/api-key-credential-provider/list", { + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, name); @@ -184,13 +201,12 @@ describe("API key credential provider detail", () => { test("renders a resource summary with only the detail action", async () => { const core = new TestCoreClient(); core.identity.setGetApiKeyResponse(getResponse()); - const screen = renderImperativeScreen( - "/agentcore/identity/api-key-credential-provider/get/api-key-1", - { - core, - endpointUrl, - }, - ); + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/get/api-key-1", { + core, + endpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); const frame = screen.lastFrame()!; @@ -210,12 +226,11 @@ describe("API key credential provider detail", () => { test("opens the complete provider JSON", async () => { const core = new TestCoreClient(); core.identity.setGetApiKeyResponse(getResponse()); - const screen = renderImperativeScreen( - "/agentcore/identity/api-key-credential-provider/get/api-key-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/get/api-key-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); await screen.press("return"); @@ -229,12 +244,11 @@ describe("API key credential provider detail", () => { test("retries a failed detail query", async () => { const core = new TestCoreClient(); core.identity.setError(new Error("provider unavailable")); - const screen = renderImperativeScreen( - "/agentcore/identity/api-key-credential-provider/get/api-key-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/get/api-key-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "provider unavailable"); expect(screen.lastFrame()).toContain("[r] retry"); @@ -251,13 +265,12 @@ describe("API key credential provider detail", () => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: Infinity, staleTime: 0 } }, }); - const screen = renderImperativeScreen( - "/agentcore/identity/api-key-credential-provider/get/api-key-1", - { - core, - queryClient, - }, - ); + const screen = renderScreen("/agentcore/identity/api-key-credential-provider/get/api-key-1", { + core, + queryClient, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); core.identity.setError(new Error("background refresh failed")); diff --git a/src/handlers/identity/oauth2-credential-provider/oauth2.screen.test.tsx b/src/handlers/identity/oauth2-credential-provider/oauth2.screen.test.tsx index 4eaf2bb42d..a79e0f2852 100644 --- a/src/handlers/identity/oauth2-credential-provider/oauth2.screen.test.tsx +++ b/src/handlers/identity/oauth2-credential-provider/oauth2.screen.test.tsx @@ -6,12 +6,13 @@ import type { import { QueryClient } from "@tanstack/react-query"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, tick, waitFor, waitForText, menuEntries, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -60,7 +61,9 @@ function coreWithProviders(providers: Oauth2CredentialProviderItem[]): TestCoreC describe("OAuth2 credential provider menu", () => { test("lists the read-only commands, then the rest as command line only", async () => { - const screen = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider"); + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "get an OAuth2 credential provider"); expect(menuEntries(screen.lastFrame()!)).toEqual({ @@ -79,8 +82,10 @@ describe("OAuth2 credential provider picker", () => { lastUpdatedTime: new Date("2026-07-21T02:03:04.000Z"), }), ]); - const screen = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/list", { + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "visible-provider"); @@ -93,9 +98,11 @@ describe("OAuth2 credential provider picker", () => { test("calls listOauth2CredentialProviders with exact Core options", async () => { const core = coreWithProviders([providerItem()]); - renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/list", { + renderScreen("/agentcore/identity/oauth2-credential-provider/list", { core, endpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitFor(() => @@ -113,8 +120,10 @@ describe("OAuth2 credential provider picker", () => { test("caps maxResults at the service limit of 20 on a tall terminal", async () => { const core = coreWithProviders([providerItem()]); - const screen = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/list", { + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); // Terminal taller than the 20-row service cap: page size must still clamp. await screen.resize(120, 60); @@ -129,7 +138,9 @@ describe("OAuth2 credential provider picker", () => { }); test("shows first-page and later-page empty states", async () => { - const empty = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/list"); + const empty = renderScreen("/agentcore/identity/oauth2-credential-provider/list", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No OAuth2 credential providers found in this Region."); empty.unmount(); @@ -139,8 +150,10 @@ describe("OAuth2 credential provider picker", () => { nextToken: "page-2", }); core.identity.setListOauth2Response({ credentialProviders: [] }, "page-2"); - const paged = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/list", { + const paged = renderScreen("/agentcore/identity/oauth2-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(paged.lastFrame, "page 1 · more →"); @@ -151,8 +164,10 @@ describe("OAuth2 credential provider picker", () => { test("bare get redirects to the picker", async () => { const core = coreWithProviders([providerItem({ name: "redirected" })]); - const screen = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/get", { + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/get", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "redirected"); @@ -163,8 +178,10 @@ describe("OAuth2 credential provider picker", () => { const name = "oauth2 blue"; const core = coreWithProviders([providerItem({ name })]); core.identity.setGetOauth2Response(getResponse({ name })); - const screen = renderImperativeScreen("/agentcore/identity/oauth2-credential-provider/list", { + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/list", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, name); @@ -185,13 +202,12 @@ describe("OAuth2 credential provider detail", () => { test("renders a resource summary with only the detail action", async () => { const core = new TestCoreClient(); core.identity.setGetOauth2Response(getResponse()); - const screen = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core, - endpointUrl, - }, - ); + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core, + endpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); const frame = screen.lastFrame()!; @@ -212,24 +228,22 @@ describe("OAuth2 credential provider detail", () => { test("shows a callback URL only when the service provides one", async () => { const withCallback = new TestCoreClient(); withCallback.identity.setGetOauth2Response(getResponse()); - const shown = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core: withCallback, - }, - ); + const shown = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core: withCallback, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(shown.lastFrame, "show the full JSON definition"); expect(shown.lastFrame()).toContain("callbackUrl"); shown.unmount(); const noCallback = new TestCoreClient(); noCallback.identity.setGetOauth2Response(getResponse({ callbackUrl: undefined })); - const hidden = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core: noCallback, - }, - ); + const hidden = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core: noCallback, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(hidden.lastFrame, "show the full JSON definition"); expect(hidden.lastFrame()).not.toContain("callbackUrl"); }); @@ -242,12 +256,11 @@ describe("OAuth2 credential provider detail", () => { failureReason: "authorization server metadata could not be loaded", }), ); - const screen = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "authorization server metadata could not be loaded"); const frame = screen.lastFrame()!; @@ -258,12 +271,11 @@ describe("OAuth2 credential provider detail", () => { test("opens the complete provider JSON", async () => { const core = new TestCoreClient(); core.identity.setGetOauth2Response(getResponse()); - const screen = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); await screen.press("return"); @@ -277,12 +289,11 @@ describe("OAuth2 credential provider detail", () => { test("retries a failed detail query", async () => { const core = new TestCoreClient(); core.identity.setError(new Error("provider unavailable")); - const screen = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "provider unavailable"); expect(screen.lastFrame()).toContain("[r] retry"); @@ -299,13 +310,12 @@ describe("OAuth2 credential provider detail", () => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: Infinity, staleTime: 0 } }, }); - const screen = renderImperativeScreen( - "/agentcore/identity/oauth2-credential-provider/get/oauth2-1", - { - core, - queryClient, - }, - ); + const screen = renderScreen("/agentcore/identity/oauth2-credential-provider/get/oauth2-1", { + core, + queryClient, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); core.identity.setError(new Error("background refresh failed")); From 326fcbeee9d89b7977dda0c36702ad27db44a671 Mon Sep 17 00:00:00 2001 From: Aidan Daly Date: Thu, 24 Sep 2026 21:19:38 +0000 Subject: [PATCH 4/5] test(cli): inline runtime and memory screen configuration --- .../memory/actor/actor.screen.test.tsx | 17 ++- .../memory/event/event.screen.test.tsx | 49 ++++---- src/handlers/memory/memory.screen.test.tsx | 80 ++++++++++--- .../memory/record/record.screen.test.tsx | 79 ++++++++----- .../memory/session/session.screen.test.tsx | 15 ++- .../runtime/endpoint/endpoint.screen.test.tsx | 67 ++++++++--- .../runtime/invoke/invoke.screen.test.tsx | 81 ++++++++----- src/handlers/runtime/runtime.screen.test.tsx | 106 ++++++++++++++---- .../runtime/shell/shell.screen.test.tsx | 7 +- .../runtime/version/version.screen.test.tsx | 49 ++++++-- 10 files changed, 392 insertions(+), 158 deletions(-) diff --git a/src/handlers/memory/actor/actor.screen.test.tsx b/src/handlers/memory/actor/actor.screen.test.tsx index 233a487062..23fe2bcfc0 100644 --- a/src/handlers/memory/actor/actor.screen.test.tsx +++ b/src/handlers/memory/actor/actor.screen.test.tsx @@ -3,10 +3,11 @@ import type { ActorSummary, SessionSummary } from "@aws-sdk/client-bedrock-agent import type { MemorySummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -48,7 +49,10 @@ describe("Memory actor list flow", () => { core.memory.setListSessionsResponse({ sessionSummaries: [session({ actorId })], }); - const screen = renderImperativeScreen("/agentcore/memory/actor/list", { core }); + const screen = renderScreen("/agentcore/memory/actor/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, memoryId); await screen.press("return"); @@ -87,13 +91,18 @@ describe("Memory actor list flow", () => { }); test("shows empty and retry states for actor lists", async () => { - const empty = renderImperativeScreen("/agentcore/memory/actor/list/memory-1"); + const empty = renderScreen("/agentcore/memory/actor/list/memory-1", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No actors found for Memory memory-1."); empty.unmount(); const core = new TestCoreClient(); core.memory.setError(new Error("actors unavailable")); - const failed = renderImperativeScreen("/agentcore/memory/actor/list/memory-1", { core }); + const failed = renderScreen("/agentcore/memory/actor/list/memory-1", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(failed.lastFrame, "actors unavailable"); core.memory.setError(undefined); diff --git a/src/handlers/memory/event/event.screen.test.tsx b/src/handlers/memory/event/event.screen.test.tsx index ee29f6942e..06a2dcf797 100644 --- a/src/handlers/memory/event/event.screen.test.tsx +++ b/src/handlers/memory/event/event.screen.test.tsx @@ -3,10 +3,11 @@ import type { ActorSummary, Event, SessionSummary } from "@aws-sdk/client-bedroc import type { MemorySummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -67,7 +68,10 @@ describe("Memory event list flow", () => { core.memory.setListEventsResponse({ events: [event({ memoryId, actorId, sessionId })], }); - const screen = renderImperativeScreen("/agentcore/memory/event/list", { core }); + const screen = renderScreen("/agentcore/memory/event/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, memoryId); await screen.press("return"); @@ -112,9 +116,11 @@ describe("Memory event list flow", () => { test("calls listEvents with the exact route scope and Core options", async () => { const core = new TestCoreClient(); core.memory.setListEventsResponse({ events: [event()] }); - renderImperativeScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1", { + renderScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1", { core, endpointUrl: memoryEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitFor(() => core.memory.calls.some((call) => call.method === "listEvents")); @@ -149,12 +155,11 @@ describe("Memory event list flow", () => { metadata: { tenant: { stringValue: "acme" } }, }), }); - const screen = renderImperativeScreen( - "/agentcore/memory/event/list/memory-1/actor-1/session-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "event blue"); const frame = screen.lastFrame()!; @@ -187,12 +192,11 @@ describe("Memory event list flow", () => { nextToken: "page-2", }); core.memory.setListEventsResponse({ events: [] }, "page-2"); - const screen = renderImperativeScreen( - "/agentcore/memory/event/list/memory-1/actor-1/session-1", - { - core, - }, - ); + const screen = renderScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "page 1 · more →"); await screen.write("l"); @@ -200,18 +204,19 @@ describe("Memory event list flow", () => { }); test("shows scoped empty and retry states", async () => { - const empty = renderImperativeScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1"); + const empty = renderScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No events found for session session-1."); empty.unmount(); const core = new TestCoreClient(); core.memory.setError(new Error("events unavailable")); - const failed = renderImperativeScreen( - "/agentcore/memory/event/list/memory-1/actor-1/session-1", - { - core, - }, - ); + const failed = renderScreen("/agentcore/memory/event/list/memory-1/actor-1/session-1", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(failed.lastFrame, "events unavailable"); expect(failed.lastFrame()).toContain("[r] retry"); diff --git a/src/handlers/memory/memory.screen.test.tsx b/src/handlers/memory/memory.screen.test.tsx index ff2b69efb7..cd2087c89a 100644 --- a/src/handlers/memory/memory.screen.test.tsx +++ b/src/handlers/memory/memory.screen.test.tsx @@ -8,11 +8,12 @@ import { QueryClient } from "@tanstack/react-query"; import stringWidth from "string-width"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, tick, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../testing"; afterEach(cleanupScreens); @@ -67,7 +68,7 @@ function coreWithMemories(memories: MemorySummary[]): TestCoreClient { describe("Memory picker", () => { test("shows event, record, actor, and session commands in the Memory TUI menu", async () => { - const screen = renderImperativeScreen("/agentcore/memory"); + const screen = renderScreen("/agentcore/memory", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "inspect AgentCore Memories"); const frame = screen.lastFrame()!; @@ -87,7 +88,10 @@ describe("Memory picker", () => { updatedAt: new Date("2026-07-21T02:03:04.000Z"), }), ]); - const screen = renderImperativeScreen("/agentcore/memory/list", { core }); + const screen = renderScreen("/agentcore/memory/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "memory-visible-id"); const frame = screen.lastFrame()!; @@ -101,7 +105,10 @@ describe("Memory picker", () => { test("keeps long Memory IDs separate from adjacent columns", async () => { const memoryId = `memory-${"x".repeat(70)}`; const core = coreWithMemories([memorySummary({ id: memoryId })]); - const screen = renderImperativeScreen("/agentcore/memory/list", { core }); + const screen = renderScreen("/agentcore/memory/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "memory-"); await screen.resize(80, 24); @@ -117,7 +124,11 @@ describe("Memory picker", () => { test("calls listMemories with exact Core options", async () => { const core = coreWithMemories([memorySummary()]); - renderImperativeScreen("/agentcore/memory/list", { core, endpointUrl: memoryEndpointUrl }); + renderScreen("/agentcore/memory/list", { + core, + endpointUrl: memoryEndpointUrl, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitFor(() => core.memory.calls.some((call) => call.method === "listMemories")); expect(core.memory.calls.filter((call) => call.method === "listMemories")).toEqual([ @@ -136,7 +147,9 @@ describe("Memory picker", () => { }); test("shows first-page and later-page empty states", async () => { - const empty = renderImperativeScreen("/agentcore/memory/list"); + const empty = renderScreen("/agentcore/memory/list", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No Memories found in this Region."); empty.unmount(); @@ -146,7 +159,10 @@ describe("Memory picker", () => { nextToken: "page-2", }); core.memory.setListResponse({ memories: [] }, "page-2"); - const paged = renderImperativeScreen("/agentcore/memory/list", { core }); + const paged = renderScreen("/agentcore/memory/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(paged.lastFrame, "page 1 · more →"); await paged.write("l"); @@ -156,7 +172,10 @@ describe("Memory picker", () => { test("bare Memory get redirects to the picker", async () => { const core = coreWithMemories([memorySummary({ id: "redirected-memory" })]); - const screen = renderImperativeScreen("/agentcore/memory/get", { core }); + const screen = renderScreen("/agentcore/memory/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "redirected-memory"); expect(core.memory.calls[0]?.method).toBe("listMemories"); @@ -166,7 +185,10 @@ describe("Memory picker", () => { const memoryId = "memory blue"; const core = coreWithMemories([memorySummary({ id: memoryId })]); core.memory.setGetResponse(getMemoryOutput({ id: memoryId })); - const screen = renderImperativeScreen("/agentcore/memory/list", { core }); + const screen = renderScreen("/agentcore/memory/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, memoryId); await screen.press("return"); @@ -181,9 +203,11 @@ describe("Memory detail", () => { test("loads the full view and renders a resource summary", async () => { const core = new TestCoreClient(); core.memory.setGetResponse(getMemoryOutput()); - const screen = renderImperativeScreen("/agentcore/memory/get/memory-1", { + const screen = renderScreen("/agentcore/memory/get/memory-1", { core, endpointUrl: memoryEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "show the full JSON definition"); @@ -210,7 +234,10 @@ describe("Memory detail", () => { test("shows a failure reason only when the service provides one", async () => { const healthyCore = new TestCoreClient(); healthyCore.memory.setGetResponse(getMemoryOutput()); - const healthy = renderImperativeScreen("/agentcore/memory/get/memory-1", { core: healthyCore }); + const healthy = renderScreen("/agentcore/memory/get/memory-1", { + core: healthyCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(healthy.lastFrame, "show the full JSON definition"); expect(healthy.lastFrame()).not.toContain("failureReason"); @@ -220,7 +247,10 @@ describe("Memory detail", () => { failedCore.memory.setGetResponse( getMemoryOutput({ status: "FAILED", failureReason: "Strategy setup failed" }), ); - const failed = renderImperativeScreen("/agentcore/memory/get/memory-1", { core: failedCore }); + const failed = renderScreen("/agentcore/memory/get/memory-1", { + core: failedCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(failed.lastFrame, "Strategy setup failed"); expect(failed.lastFrame()).toContain("failureReason"); @@ -229,7 +259,10 @@ describe("Memory detail", () => { test("opens the complete Memory JSON", async () => { const core = new TestCoreClient(); core.memory.setGetResponse(getMemoryOutput()); - const screen = renderImperativeScreen("/agentcore/memory/get/memory-1", { core }); + const screen = renderScreen("/agentcore/memory/get/memory-1", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); await screen.press("return"); @@ -244,7 +277,10 @@ describe("Memory detail", () => { core.memory.setListResponse({ memories: [memorySummary()] }); core.memory.setGetResponse(getMemoryOutput()); core.memory.setListActorsResponse({ actorSummaries: [] }); - const screen = renderImperativeScreen("/agentcore/memory/list", { core }); + const screen = renderScreen("/agentcore/memory/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "memory-1"); await screen.press("return"); @@ -269,7 +305,10 @@ describe("Memory detail", () => { const core = new TestCoreClient(); core.memory.setListResponse({ memories: [memorySummary()] }); core.memory.setGetResponse(getMemoryOutput()); - const screen = renderImperativeScreen("/agentcore/memory/list", { core }); + const screen = renderScreen("/agentcore/memory/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "memory-1"); await screen.press("return"); @@ -289,7 +328,10 @@ describe("Memory detail", () => { test("retries a failed detail query", async () => { const core = new TestCoreClient(); core.memory.setError(new Error("memory unavailable")); - const screen = renderImperativeScreen("/agentcore/memory/get/memory-1", { core }); + const screen = renderScreen("/agentcore/memory/get/memory-1", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "memory unavailable"); expect(screen.lastFrame()).toContain("[r] retry"); @@ -308,7 +350,11 @@ describe("Memory detail", () => { queries: { retry: false, gcTime: Infinity, staleTime: 0 }, }, }); - const screen = renderImperativeScreen("/agentcore/memory/get/memory-1", { core, queryClient }); + const screen = renderScreen("/agentcore/memory/get/memory-1", { + core, + queryClient, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "show the full JSON definition"); core.memory.setError(new Error("background refresh failed")); diff --git a/src/handlers/memory/record/record.screen.test.tsx b/src/handlers/memory/record/record.screen.test.tsx index 512c02c89e..8a95dd301a 100644 --- a/src/handlers/memory/record/record.screen.test.tsx +++ b/src/handlers/memory/record/record.screen.test.tsx @@ -7,10 +7,11 @@ import type { import type { MemorySummary } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; import stringWidth from "string-width"; @@ -46,7 +47,9 @@ function recordSummary(overrides: Partial = {}): MemoryReco describe("Memory record list flow", () => { test("renders the record command menu", async () => { - const screen = renderImperativeScreen("/agentcore/memory/record"); + const screen = renderScreen("/agentcore/memory/record", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "inspect AgentCore Memory records"); expect(screen.lastFrame()).toContain("list"); @@ -58,7 +61,10 @@ describe("Memory record list flow", () => { core.memory.setListResponse({ memories: [memorySummary({ id: memoryId })], }); - const screen = renderImperativeScreen("/agentcore/memory/record/list", { core }); + const screen = renderScreen("/agentcore/memory/record/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, memoryId); await screen.press("return"); @@ -72,7 +78,9 @@ describe("Memory record list flow", () => { }); test("reveals the scope input only after enter and hides it again on escape", async () => { - const screen = renderImperativeScreen("/agentcore/memory/record/list/memory-1"); + const screen = renderScreen("/agentcore/memory/record/list/memory-1", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); const fieldHelp = "the namespace value used to scope this request"; await waitForText(screen.lastFrame, "scope type"); @@ -95,7 +103,10 @@ describe("Memory record list flow", () => { core.memory.setListMemoryRecordsResponse({ memoryRecordSummaries: [recordSummary()], }); - const screen = renderImperativeScreen("/agentcore/memory/record/list", { core }); + const screen = renderScreen("/agentcore/memory/record/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, memoryId); await screen.press("return"); @@ -116,7 +127,10 @@ describe("Memory record list flow", () => { core.memory.setListMemoryRecordsResponse({ memoryRecordSummaries: [recordSummary()], }); - const screen = renderImperativeScreen("/agentcore/memory/record/list/memory-1", { core }); + const screen = renderScreen("/agentcore/memory/record/list/memory-1", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "scope type"); await screen.press("down"); @@ -139,9 +153,11 @@ describe("Memory record list flow", () => { core.memory.setListMemoryRecordsResponse({ memoryRecordSummaries: [recordSummary()], }); - const screen = renderImperativeScreen("/agentcore/memory/record/list/memory-1", { + const screen = renderScreen("/agentcore/memory/record/list/memory-1", { core, endpointUrl: memoryEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "scope type"); @@ -181,9 +197,9 @@ describe("Memory record list flow", () => { }), ], }); - const screen = renderImperativeScreen( + const screen = renderScreen( "/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers%2Facme", - { core }, + { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }, ); await waitForText(screen.lastFrame, "no-text"); @@ -195,7 +211,10 @@ describe("Memory record list flow", () => { core.memory.setListMemoryRecordsResponse({ memoryRecordSummaries: [recordSummary()], }); - const screen = renderImperativeScreen("/agentcore/memory/record/list/memory-1", { core }); + const screen = renderScreen("/agentcore/memory/record/list/memory-1", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "scope type"); await screen.press("down"); @@ -233,9 +252,9 @@ describe("Memory record list flow", () => { ], }); core.memory.setGetMemoryRecordResponse(response); - const screen = renderImperativeScreen( + const screen = renderScreen( "/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers%2Facme", - { core }, + { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }, ); await waitForText(screen.lastFrame, "record blue"); @@ -275,9 +294,9 @@ describe("Memory record list flow", () => { }), ], }); - const screen = renderImperativeScreen( + const screen = renderScreen( "/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers%2Facme", - { core }, + { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }, ); await waitForText(screen.lastFrame, "total-market ETFs"); @@ -301,12 +320,11 @@ describe("Memory record list flow", () => { nextToken: "page-2", }); core.memory.setListMemoryRecordsResponse({ memoryRecordSummaries: [] }, "page-2"); - const screen = renderImperativeScreen( - "/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers", - { - core, - }, - ); + const screen = renderScreen("/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "page 1 · more →"); await screen.write("l"); @@ -314,20 +332,19 @@ describe("Memory record list flow", () => { }); test("shows the scoped empty state and retries list failures", async () => { - const empty = renderImperativeScreen( - "/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers", - ); + const empty = renderScreen("/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No Memory records found for namespace /customers."); empty.unmount(); const core = new TestCoreClient(); core.memory.setError(new Error("records unavailable")); - const failed = renderImperativeScreen( - "/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers", - { - core, - }, - ); + const failed = renderScreen("/agentcore/memory/record/list/memory-1/namespace/%2Fcustomers", { + core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(failed.lastFrame, "records unavailable"); expect(failed.lastFrame()).toContain("[r] retry"); @@ -341,7 +358,9 @@ describe("Memory record list flow", () => { }); test("requires a non-empty namespace value", async () => { - const screen = renderImperativeScreen("/agentcore/memory/record/list/memory-1"); + const screen = renderScreen("/agentcore/memory/record/list/memory-1", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, "scope type"); await screen.press("return"); // focus the namespace input diff --git a/src/handlers/memory/session/session.screen.test.tsx b/src/handlers/memory/session/session.screen.test.tsx index 3c995d2695..4e41ded180 100644 --- a/src/handlers/memory/session/session.screen.test.tsx +++ b/src/handlers/memory/session/session.screen.test.tsx @@ -2,9 +2,10 @@ import { afterEach, describe, expect, test } from "bun:test"; import type { Event, SessionSummary } from "@aws-sdk/client-bedrock-agentcore"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -42,8 +43,10 @@ describe("Memory session list flow", () => { core.memory.setListEventsResponse({ events: [event({ memoryId, actorId, sessionId })], }); - const screen = renderImperativeScreen(`/agentcore/memory/session/list/${memoryId}/${actorId}`, { + const screen = renderScreen(`/agentcore/memory/session/list/${memoryId}/${actorId}`, { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, sessionId); @@ -59,14 +62,18 @@ describe("Memory session list flow", () => { }); test("shows empty and retry states for session lists", async () => { - const empty = renderImperativeScreen("/agentcore/memory/session/list/memory-1/actor-1"); + const empty = renderScreen("/agentcore/memory/session/list/memory-1/actor-1", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No sessions found for actor actor-1."); empty.unmount(); const core = new TestCoreClient(); core.memory.setError(new Error("sessions unavailable")); - const failed = renderImperativeScreen("/agentcore/memory/session/list/memory-1/actor-1", { + const failed = renderScreen("/agentcore/memory/session/list/memory-1/actor-1", { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(failed.lastFrame, "sessions unavailable"); diff --git a/src/handlers/runtime/endpoint/endpoint.screen.test.tsx b/src/handlers/runtime/endpoint/endpoint.screen.test.tsx index b7ff3e9421..c3a58e0c5a 100644 --- a/src/handlers/runtime/endpoint/endpoint.screen.test.tsx +++ b/src/handlers/runtime/endpoint/endpoint.screen.test.tsx @@ -7,10 +7,11 @@ import type { } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -106,7 +107,10 @@ describe("Runtime endpoint flow", () => { core.runtime.setListEndpointsResponse({ runtimeEndpoints: [endpoint()], }); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, runtimeId); await r.press("return"); @@ -124,9 +128,11 @@ describe("Runtime endpoint flow", () => { core.runtime.setListEndpointsResponse({ runtimeEndpoints: [endpoint()], }); - renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123", { + renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { core, endpointUrl: runtimeEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitFor(() => core.runtime.calls.some((call) => call.method === "listRuntimeEndpoints")); @@ -160,7 +166,10 @@ describe("Runtime endpoint flow", () => { }), ], }); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "production"); const frame = r.lastFrame()!; @@ -177,7 +186,9 @@ describe("Runtime endpoint flow", () => { }); test("shows the Runtime-scoped empty state", async () => { - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123"); + const r = renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "This Runtime has no endpoints."); expect(r.lastFrame()).toContain("runtime-123"); @@ -190,7 +201,10 @@ describe("Runtime endpoint flow", () => { nextToken: "page-2", }); core.runtime.setListEndpointsResponse({ runtimeEndpoints: [] }, "page-2"); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); await r.write("l"); @@ -201,7 +215,10 @@ describe("Runtime endpoint flow", () => { test("names the selected Runtime in the error state", async () => { const core = new TestCoreClient(); core.runtime.setError(new Error("endpoint access denied")); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "Error loading endpoints for Runtime runtime-123"); expect(r.lastFrame()).toContain("endpoint access denied"); @@ -214,9 +231,11 @@ describe("Runtime endpoint flow", () => { runtimeEndpoints: [endpoint({ name: qualifier, id: qualifier })], }); core.runtime.setGetEndpointResponse(getEndpointResponse({ name: qualifier, id: qualifier })); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123", { + const r = renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { core, endpointUrl: runtimeEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, qualifier); @@ -246,8 +265,10 @@ describe("Runtime endpoint flow", () => { test("shows the endpoint failure reason only when the service provides one", async () => { const healthyCore = new TestCoreClient(); healthyCore.runtime.setGetEndpointResponse(getEndpointResponse()); - const healthy = renderImperativeScreen("/agentcore/runtime/endpoint/get/runtime-123/prod", { + const healthy = renderScreen("/agentcore/runtime/endpoint/get/runtime-123/prod", { core: healthyCore, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(healthy.lastFrame, "invoke this Runtime endpoint"); @@ -261,8 +282,10 @@ describe("Runtime endpoint flow", () => { failureReason: "Endpoint failed its health check", }), ); - const failed = renderImperativeScreen("/agentcore/runtime/endpoint/get/runtime-123/prod", { + const failed = renderScreen("/agentcore/runtime/endpoint/get/runtime-123/prod", { core: failedCore, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(failed.lastFrame, "Endpoint failed its health check"); @@ -272,7 +295,10 @@ describe("Runtime endpoint flow", () => { test("opens complete endpoint JSON from the detail action and returns to the summary", async () => { const core = new TestCoreClient(); core.runtime.setGetEndpointResponse(getEndpointResponse()); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/get/runtime-123/prod", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/get/runtime-123/prod", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "invoke this Runtime endpoint"); await r.press("down"); @@ -300,7 +326,10 @@ describe("Runtime endpoint flow", () => { .setListEndpointsResponse({ runtimeEndpoints: [endpoint()] }) .setGetEndpointResponse(getEndpointResponse()) .setGetResponse(getRuntimeResponse()); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/list/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "prod"); await r.press("return"); @@ -321,8 +350,10 @@ describe("Runtime endpoint flow", () => { parentCore.runtime.setListResponse({ agentRuntimes: [runtime()], }); - const parent = renderImperativeScreen("/agentcore/runtime/endpoint/list", { + const parent = renderScreen("/agentcore/runtime/endpoint/list", { core: parentCore, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(parent.lastFrame, "runtime-123"); await parent.press("escape"); @@ -340,7 +371,10 @@ describe("Runtime endpoint flow", () => { runtimeEndpoints: [endpoint()], }); listCore.runtime.setGetEndpointResponse(getEndpointResponse()); - const list = renderImperativeScreen("/agentcore/runtime/endpoint/list", { core: listCore }); + const list = renderScreen("/agentcore/runtime/endpoint/list", { + core: listCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(list.lastFrame, "runtime-123"); await list.press("return"); await waitForText(list.lastFrame, "prod"); @@ -360,7 +394,10 @@ describe("Runtime endpoint flow", () => { core.runtime.setListResponse({ agentRuntimes: [runtime({ agentRuntimeId: "redirect-parent" })], }); - const r = renderImperativeScreen("/agentcore/runtime/endpoint/get", { core }); + const r = renderScreen("/agentcore/runtime/endpoint/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "redirect-parent"); expect(core.runtime.calls.some((call) => call.method === "listRuntimes")).toBe(true); diff --git a/src/handlers/runtime/invoke/invoke.screen.test.tsx b/src/handlers/runtime/invoke/invoke.screen.test.tsx index 840d02e02e..1b30d5e1bf 100644 --- a/src/handlers/runtime/invoke/invoke.screen.test.tsx +++ b/src/handlers/runtime/invoke/invoke.screen.test.tsx @@ -8,10 +8,11 @@ import type { import type { RuntimeInvokeRequest } from "../types"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; import { RuntimeInvokeLaunchContextKey } from "./launchContext"; @@ -90,7 +91,10 @@ describe("Runtime invoke routing", () => { .setGetResponse({ agentRuntimeArn: `arn:aws:bedrock-agentcore:${REGION}:123456789012:runtime/${runtimeId}`, } as GetAgentRuntimeResponse); - const screen = renderImperativeScreen("/agentcore/runtime/invoke", { core }); + const screen = renderScreen("/agentcore/runtime/invoke", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, runtimeId); await screen.press("return"); @@ -109,7 +113,10 @@ describe("Runtime invoke routing", () => { core.runtime.setListEndpointsResponse({ runtimeEndpoints: [endpoint()] }).setListResponse({ agentRuntimes: [runtime({ agentRuntimeId: "back-to-runtime-picker" })], }); - const screen = renderImperativeScreen(`/agentcore/runtime/invoke/${RUNTIME_ID}`, { core }); + const screen = renderScreen(`/agentcore/runtime/invoke/${RUNTIME_ID}`, { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(screen.lastFrame, QUALIFIER); await screen.press("escape"); @@ -124,13 +131,15 @@ describe("Runtime invoke routing", () => { core.runtime .setListEndpointsResponse({ runtimeEndpoints: [endpoint()] }) .setGetResponse({ agentRuntimeArn: RUNTIME_ARN } as GetAgentRuntimeResponse); - const screen = renderImperativeScreen(`/agentcore/runtime/invoke/${RUNTIME_ID}`, { + const screen = renderScreen(`/agentcore/runtime/invoke/${RUNTIME_ID}`, { core, withContext: (ctx) => ctx.withValue(RuntimeInvokeLaunchContextKey, { runtimeId: RUNTIME_ID, runtimeSessionId: sessionId, }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, QUALIFIER); @@ -153,13 +162,15 @@ describe("Runtime invoke routing", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(RuntimeInvokeLaunchContextKey, { runtimeId: RUNTIME_ID, runtimeSessionId: "cli-selected-session", }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Session ID: cli-selected-session"); @@ -187,7 +198,7 @@ describe("Runtime invoke routing", () => { name: "AccessDeniedException", }); }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "AccessDeniedException"); await waitForText(screen.lastFrame, "not authorized for this Runtime"); @@ -200,7 +211,7 @@ describe("Runtime invoke routing", () => { lookupSignal = signal; return new Promise(() => {}); }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitFor(() => lookupSignal !== undefined); screen.unmount(); @@ -219,7 +230,7 @@ describe("Runtime invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Enter JSON payload"); expect(screen.lastFrame()!.split("\n")).not.toContain("JSON payload"); @@ -242,7 +253,7 @@ describe("Runtime invoke JSON console", () => { test("rejects invalid JSON locally without clearing the editor or invoking", async () => { const core = new TestCoreClient(); core.runtime.setGetResponse({ agentRuntimeArn: RUNTIME_ARN } as GetAgentRuntimeResponse); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write('{"prompt":'); @@ -262,7 +273,7 @@ describe("Runtime invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{"); @@ -289,7 +300,7 @@ describe("Runtime invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write('{"a":1}'); @@ -310,7 +321,7 @@ describe("Runtime invoke JSON console", () => { test("keeps blank multiline rows inside the four-line editor", async () => { const core = new TestCoreClient(); core.runtime.setGetResponse({ agentRuntimeArn: RUNTIME_ARN } as GetAgentRuntimeResponse); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); const initialStatusLine = screen @@ -338,8 +349,10 @@ describe("Runtime invoke JSON console", () => { core.runtime.setGetResponse({ agentRuntimeArn: `arn:aws:bedrock-agentcore:${REGION}:123456789012:runtime/${runtimeId}`, } as GetAgentRuntimeResponse); - const screen = renderImperativeScreen(`/agentcore/runtime/invoke/${runtimeId}/${QUALIFIER}`, { + const screen = renderScreen(`/agentcore/runtime/invoke/${runtimeId}/${QUALIFIER}`, { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Ready"); @@ -373,7 +386,7 @@ describe("Runtime invoke JSON console", () => { : responseBody(Buffer.from("done")), }; }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write('{"turn":1}'); @@ -405,7 +418,7 @@ describe("Runtime invoke JSON console", () => { yield Buffer.from(" response"); })(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -437,7 +450,7 @@ describe("Runtime invoke JSON console", () => { runtimeSessionId: "returned-runtime", body: responseBody(Buffer.from("data: one\n\ndata: two\n\n")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -472,7 +485,7 @@ describe("Runtime invoke JSON console", () => { contentType, body: responseBody(body), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -488,7 +501,7 @@ describe("Runtime invoke JSON console", () => { core.runtime.invokeRuntime = async () => { throw Object.assign(new Error("connection failed"), { name: "NetworkError" }); }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -510,7 +523,7 @@ describe("Runtime invoke JSON console", () => { core.runtime.invokeRuntime = async () => { throw error; }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -530,7 +543,7 @@ describe("Runtime invoke JSON console", () => { core.runtime.invokeRuntime = async () => { throw failure; }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -552,7 +565,7 @@ describe("Runtime invoke JSON console", () => { throw Object.assign(new Error("stream failed"), { name: "StreamReadError" }); })(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -574,7 +587,7 @@ describe("Runtime invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from(response)), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await screen.resize(80, 16); await waitForText(screen.lastFrame, "Ready"); @@ -607,13 +620,15 @@ describe("Runtime invoke JSON console", () => { }; }; const initialSession = "cli-selected-session"; - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(RuntimeInvokeLaunchContextKey, { runtimeId: RUNTIME_ID, runtimeSessionId: initialSession, }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, `Session ID: ${initialSession}`); @@ -653,7 +668,7 @@ describe("Runtime invoke JSON console", () => { body: responseBody(Buffer.from('{"ok":true}')), }; }; - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(RuntimeInvokeLaunchContextKey, { @@ -662,6 +677,8 @@ describe("Runtime invoke JSON console", () => { applicationHeaders: [["X-Tenant", "retail"]], bearerToken: token, }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Context user/JWT/1h"); @@ -706,7 +723,7 @@ describe("Runtime invoke JSON console", () => { mcpProtocolVersion: "2025-06-18", body: responseBody(Buffer.from("old response")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(RuntimeInvokeLaunchContextKey, { @@ -714,6 +731,8 @@ describe("Runtime invoke JSON console", () => { runtimeUserId: "user-123", applicationHeaders: [["X-Tenant", "retail"]], }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Ready"); @@ -782,7 +801,7 @@ describe("Runtime invoke JSON console", () => { contentType: "text/plain", body: responseBody(Buffer.from("ok")), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { + const screen = renderScreen(CONSOLE_PATH, { core, withContext: (ctx) => ctx.withValue(RuntimeInvokeLaunchContextKey, { @@ -791,6 +810,8 @@ describe("Runtime invoke JSON console", () => { applicationHeaders: [["X-Tenant", "retail"]], bearerToken: "secret-token", }), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "Context user/JWT/1h"); @@ -826,7 +847,7 @@ describe("Runtime invoke JSON console", () => { contentType: "application/json", body: responseBody(Buffer.from(raw)), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -853,7 +874,7 @@ describe("Runtime invoke JSON console", () => { yield Buffer.from([0, 255]); })(), }); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -872,7 +893,7 @@ describe("Runtime invoke JSON console", () => { agentRuntimeArn: RUNTIME_ARN, authorizerConfiguration: { customJWTAuthorizer: {} }, } as GetAgentRuntimeResponse); - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(screen.lastFrame, "Ready"); await screen.write("{}"); @@ -900,7 +921,7 @@ describe("Runtime invoke JSON console", () => { })(), }; }; - const screen = renderImperativeScreen(CONSOLE_PATH, { core }); + const screen = renderScreen(CONSOLE_PATH, { core, globalConfig: IMPERATIVE_GLOBAL_CONFIG }); try { await waitForText(screen.lastFrame, "Ready"); diff --git a/src/handlers/runtime/runtime.screen.test.tsx b/src/handlers/runtime/runtime.screen.test.tsx index 44d538881d..169106adf0 100644 --- a/src/handlers/runtime/runtime.screen.test.tsx +++ b/src/handlers/runtime/runtime.screen.test.tsx @@ -6,11 +6,12 @@ import type { import { QueryClient } from "@tanstack/react-query"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, tick, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../testing"; afterEach(cleanupScreens); @@ -80,7 +81,10 @@ describe("runtime picker", () => { lastUpdatedAt: new Date("2026-07-19T01:02:03.000Z"), }), ]); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "orders"); const frame = r.lastFrame()!; @@ -98,7 +102,11 @@ describe("runtime picker", () => { test("calls listRuntimes once with exact Core options", async () => { const core = coreWithRuntimes([runtime()]); - renderImperativeScreen("/agentcore/runtime/list", { core, endpointUrl: runtimeEndpointUrl }); + renderScreen("/agentcore/runtime/list", { + core, + endpointUrl: runtimeEndpointUrl, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitFor(() => core.runtime.calls.some((call) => call.method === "listRuntimes")); expect(core.runtime.calls.filter((call) => call.method === "listRuntimes")).toEqual([ @@ -117,7 +125,7 @@ describe("runtime picker", () => { }); test("shows the first-page empty state", async () => { - const r = renderImperativeScreen("/agentcore/runtime/list"); + const r = renderScreen("/agentcore/runtime/list", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "No Runtimes found in this Region."); }); @@ -129,7 +137,10 @@ describe("runtime picker", () => { nextToken: "page-2", }); core.runtime.setListResponse({ agentRuntimes: [] }, "page-2"); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); await r.write("l"); @@ -139,7 +150,10 @@ describe("runtime picker", () => { test("Esc returns to the Runtime menu from a successful direct entry", async () => { const core = coreWithRuntimes([runtime()]); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "checkout"); await r.press("escape"); @@ -151,7 +165,10 @@ describe("runtime picker", () => { const core = coreWithRuntimes([ runtime({ agentRuntimeId: "redirected-Ab12Cd34Ef", agentRuntimeName: "redirected" }), ]); - const r = renderImperativeScreen("/agentcore/runtime/get", { core }); + const r = renderScreen("/agentcore/runtime/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "redirected"); expect(core.runtime.calls[0]?.method).toBe("listRuntimes"); @@ -162,9 +179,11 @@ describe("runtime hub", () => { test("fetches the route ID with exact Core options and renders its summary", async () => { const core = new TestCoreClient(); core.runtime.setGetResponse(getRuntimeResponse()); - const r = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { + const r = renderScreen("/agentcore/runtime/get/runtime-123", { core, endpointUrl: runtimeEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "arn:aws:bedrock-agentcore:us-east-1"); @@ -190,8 +209,10 @@ describe("runtime hub", () => { test("shows the Runtime failure reason only when the service provides one", async () => { const healthyCore = new TestCoreClient(); healthyCore.runtime.setGetResponse(getRuntimeResponse()); - const healthy = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { + const healthy = renderScreen("/agentcore/runtime/get/runtime-123", { core: healthyCore, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(healthy.lastFrame, "show the full JSON definition"); @@ -205,8 +226,10 @@ describe("runtime hub", () => { failureReason: "Image could not be pulled", }), ); - const failed = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { + const failed = renderScreen("/agentcore/runtime/get/runtime-123", { core: failedCore, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(failed.lastFrame, "Image could not be pulled"); @@ -216,7 +239,10 @@ describe("runtime hub", () => { test("renders invoke first with endpoint, version, and detail actions", async () => { const core = new TestCoreClient(); core.runtime.setGetResponse(getRuntimeResponse()); - const r = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/get/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "show the full JSON definition"); const frame = r.lastFrame()!; @@ -240,7 +266,10 @@ describe("runtime hub", () => { agentRuntimeName: "encoded-runtime", }), ); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, runtimeId); await r.press("return"); @@ -280,8 +309,10 @@ describe("runtime hub", () => { ], }); } - const r = renderImperativeScreen(`/agentcore/runtime/get/${encodeURIComponent(runtimeId)}`, { + const r = renderScreen(`/agentcore/runtime/get/${encodeURIComponent(runtimeId)}`, { core, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "show the full JSON definition"); @@ -310,7 +341,10 @@ describe("runtime hub", () => { ), }), ); - const r = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/get/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "show the full JSON definition"); for (let index = 0; index < 4; index += 1) await r.press("down"); @@ -333,7 +367,10 @@ describe("runtime hub", () => { test("retries a failed hub query without leaving the route", async () => { const core = new TestCoreClient(); core.runtime.setError(new Error("runtime unavailable")); - const r = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/get/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "runtime unavailable"); expect(r.lastFrame()).toContain("agentcore → runtime → get → runtime-123"); @@ -355,9 +392,11 @@ describe("runtime hub", () => { queries: { retry: false, gcTime: Infinity, staleTime: 0 }, }, }); - const r = renderImperativeScreen("/agentcore/runtime/get/runtime-123", { + const r = renderScreen("/agentcore/runtime/get/runtime-123", { core, queryClient, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "show the full JSON definition"); @@ -377,7 +416,10 @@ describe("runtime hub", () => { test("retries a failed JSON query without leaving the route", async () => { const core = new TestCoreClient(); core.runtime.setError(new Error("detail unavailable")); - const r = renderImperativeScreen("/agentcore/runtime/get/runtime-123/json", { core }); + const r = renderScreen("/agentcore/runtime/get/runtime-123/json", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "detail unavailable"); expect(r.lastFrame()).toContain("[r] retry"); @@ -393,7 +435,10 @@ describe("runtime hub", () => { test("Esc from the hub returns through history to the Runtime picker", async () => { const core = coreWithRuntimes([runtime({ agentRuntimeId: "runtime-123" })]); core.runtime.setGetResponse(getRuntimeResponse()); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "runtime-123"); await r.press("return"); @@ -405,7 +450,10 @@ describe("runtime hub", () => { test("Esc from Runtime JSON returns through history to the Runtime hub", async () => { const core = coreWithRuntimes([runtime({ agentRuntimeId: "runtime-123" })]); core.runtime.setGetResponse(getRuntimeResponse()); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "runtime-123"); await r.press("return"); @@ -438,7 +486,10 @@ describe("runtime hub", () => { }, ], }); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "runtime-123"); await r.press("return"); @@ -464,7 +515,10 @@ describe("runtime hub", () => { const hubCore = coreWithRuntimes([runtime({ agentRuntimeId: "runtime-123" })]); const hubPending = Promise.withResolvers(); hubCore.runtime.getRuntime = async () => hubPending.promise; - const hub = renderImperativeScreen("/agentcore/runtime/list", { core: hubCore }); + const hub = renderScreen("/agentcore/runtime/list", { + core: hubCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(hub.lastFrame, "runtime-123"); await hub.press("return"); @@ -478,7 +532,10 @@ describe("runtime hub", () => { hubCore.runtime.getRuntime = async () => { throw new Error("hub failed"); }; - const hub = renderImperativeScreen("/agentcore/runtime/list", { core: hubCore }); + const hub = renderScreen("/agentcore/runtime/list", { + core: hubCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(hub.lastFrame, "runtime-123"); await hub.press("return"); @@ -489,7 +546,10 @@ describe("runtime hub", () => { const jsonCore = coreWithRuntimes([runtime({ agentRuntimeId: "runtime-123" })]); jsonCore.runtime.setGetResponse(getRuntimeResponse()); - const json = renderImperativeScreen("/agentcore/runtime/list", { core: jsonCore }); + const json = renderScreen("/agentcore/runtime/list", { + core: jsonCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(json.lastFrame, "runtime-123"); await json.press("return"); diff --git a/src/handlers/runtime/shell/shell.screen.test.tsx b/src/handlers/runtime/shell/shell.screen.test.tsx index fce8071780..8f9eee94ce 100644 --- a/src/handlers/runtime/shell/shell.screen.test.tsx +++ b/src/handlers/runtime/shell/shell.screen.test.tsx @@ -5,13 +5,14 @@ import { ValueContext } from "../../../router"; import type { RuntimeShellSession } from "../types"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, tick, type TtyInput, ttyTestIO, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -80,8 +81,10 @@ async function interruptUntilExit(rendering: Promise, stdin: TtyInput): Pr describe("RuntimeShellScreen", () => { test("a direct Runtime route skips the Runtime picker", async () => { - const screen = renderImperativeScreen("/agentcore/runtime/shell/checkout-AbCdEf1234", { + const screen = renderScreen("/agentcore/runtime/shell/checkout-AbCdEf1234", { core: core(), + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(screen.lastFrame, "prod"); diff --git a/src/handlers/runtime/version/version.screen.test.tsx b/src/handlers/runtime/version/version.screen.test.tsx index c189f1686a..04e6d91221 100644 --- a/src/handlers/runtime/version/version.screen.test.tsx +++ b/src/handlers/runtime/version/version.screen.test.tsx @@ -5,10 +5,11 @@ import type { } from "@aws-sdk/client-bedrock-agentcore-control"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../../../testing"; afterEach(cleanupScreens); @@ -72,7 +73,10 @@ describe("Runtime version flow", () => { core.runtime.setListVersionsResponse({ agentRuntimes: [runtime({ agentRuntimeId: runtimeId, agentRuntimeVersion: "9" })], }); - const r = renderImperativeScreen("/agentcore/runtime/version/list", { core }); + const r = renderScreen("/agentcore/runtime/version/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, runtimeId); await r.press("return"); @@ -90,9 +94,11 @@ describe("Runtime version flow", () => { core.runtime.setListVersionsResponse({ agentRuntimes: [runtime()], }); - renderImperativeScreen("/agentcore/runtime/version/list/runtime-123", { + renderScreen("/agentcore/runtime/version/list/runtime-123", { core, endpointUrl: runtimeEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitFor(() => core.runtime.calls.some((call) => call.method === "listRuntimeVersions")); @@ -133,7 +139,10 @@ describe("Runtime version flow", () => { }), ], }); - const r = renderImperativeScreen("/agentcore/runtime/version/list/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/version/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "UPDATE_FAILED"); const frame = r.lastFrame()!; @@ -162,7 +171,10 @@ describe("Runtime version flow", () => { nextToken: "page-2", }); core.runtime.setListVersionsResponse({ agentRuntimes: [] }, "page-2"); - const r = renderImperativeScreen("/agentcore/runtime/version/list/runtime-123", { core }); + const r = renderScreen("/agentcore/runtime/version/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); await r.write("l"); @@ -171,13 +183,18 @@ describe("Runtime version flow", () => { }); test("names the selected Runtime in empty and error states", async () => { - const empty = renderImperativeScreen("/agentcore/runtime/version/list/runtime-123"); + const empty = renderScreen("/agentcore/runtime/version/list/runtime-123", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(empty.lastFrame, "No versions found for Runtime runtime-123."); empty.unmount(); const core = new TestCoreClient(); core.runtime.setError(new Error("version access denied")); - const error = renderImperativeScreen("/agentcore/runtime/version/list/runtime-123", { core }); + const error = renderScreen("/agentcore/runtime/version/list/runtime-123", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(error.lastFrame, "Error loading versions for Runtime runtime-123"); expect(error.lastFrame()).toContain("version access denied"); expect(error.lastFrame()).toContain("[r] retry"); @@ -189,9 +206,11 @@ describe("Runtime version flow", () => { agentRuntimes: [runtime({ agentRuntimeVersion: "9" })], }); core.runtime.setGetVersionResponse(getVersionResponse({ agentRuntimeVersion: "9" })); - const r = renderImperativeScreen("/agentcore/runtime/version/list/runtime-123", { + const r = renderScreen("/agentcore/runtime/version/list/runtime-123", { core, endpointUrl: runtimeEndpointUrl, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(r.lastFrame, "9"); @@ -217,8 +236,10 @@ describe("Runtime version flow", () => { parentCore.runtime.setListResponse({ agentRuntimes: [runtime()], }); - const parent = renderImperativeScreen("/agentcore/runtime/version/list", { + const parent = renderScreen("/agentcore/runtime/version/list", { core: parentCore, + + globalConfig: IMPERATIVE_GLOBAL_CONFIG, }); await waitForText(parent.lastFrame, "runtime-123"); await parent.press("escape"); @@ -236,7 +257,10 @@ describe("Runtime version flow", () => { agentRuntimes: [runtime()], }); listCore.runtime.setGetVersionResponse(getVersionResponse()); - const list = renderImperativeScreen("/agentcore/runtime/version/list", { core: listCore }); + const list = renderScreen("/agentcore/runtime/version/list", { + core: listCore, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(list.lastFrame, "runtime-123"); await list.press("return"); await waitForText(list.lastFrame, "agentcore → runtime → version → list → runtime-123"); @@ -260,7 +284,10 @@ describe("Runtime version flow", () => { core.runtime.setListResponse({ agentRuntimes: [runtime({ agentRuntimeId: "redirect-parent" })], }); - const r = renderImperativeScreen("/agentcore/runtime/version/get", { core }); + const r = renderScreen("/agentcore/runtime/version/get", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "redirect-parent"); expect(core.runtime.calls.some((call) => call.method === "listRuntimes")).toBe(true); From 84699274e18ed77a45e282bd022a24e7382eba38 Mon Sep 17 00:00:00 2001 From: Aidan Daly Date: Thu, 24 Sep 2026 21:20:28 +0000 Subject: [PATCH 5/5] test(tui): remove the imperative screen wrapper --- src/components/CliOnlyScreen.test.tsx | 7 +- src/components/PaginatedTablePicker.test.tsx | 83 +++++++++++++++---- .../ProjectResourceCreateScreen.test.tsx | 6 +- src/components/Root.test.tsx | 4 +- src/components/RouterScreen.test.tsx | 14 ++-- src/testing/index.tsx | 1 - src/testing/renderScreen.tsx | 12 +-- 7 files changed, 83 insertions(+), 44 deletions(-) diff --git a/src/components/CliOnlyScreen.test.tsx b/src/components/CliOnlyScreen.test.tsx index 66e0ecff06..cec09b56c7 100644 --- a/src/components/CliOnlyScreen.test.tsx +++ b/src/components/CliOnlyScreen.test.tsx @@ -5,7 +5,6 @@ import { compiledRootCommand, menuEntries, renderScreen, - renderImperativeScreen, IMPERATIVE_GLOBAL_CONFIG, waitForText, } from "../testing"; @@ -66,7 +65,7 @@ describe("menus list command-line-only subcommands below a divider", () => { }); test("the harness menu", async () => { - const r = renderImperativeScreen("/agentcore/harness"); + const r = renderScreen("/agentcore/harness", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "command line only"); expect(menuEntries(r.lastFrame()!)).toEqual({ @@ -87,7 +86,9 @@ describe("menus list command-line-only subcommands below a divider", () => { }); test("the divider is omitted when nothing is command line only", async () => { - const r = renderImperativeScreen("/agentcore/harness/endpoint"); + const r = renderScreen("/agentcore/harness/endpoint", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "manage harness endpoints"); expect(r.lastFrame()).not.toContain("command line only"); diff --git a/src/components/PaginatedTablePicker.test.tsx b/src/components/PaginatedTablePicker.test.tsx index 256b1c7dde..440631a461 100644 --- a/src/components/PaginatedTablePicker.test.tsx +++ b/src/components/PaginatedTablePicker.test.tsx @@ -8,10 +8,11 @@ import { QueryClient } from "@tanstack/react-query"; import stringWidth from "string-width"; import { cleanupScreens, - renderImperativeScreen, + renderScreen, TestCoreClient, waitFor, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../testing"; afterEach(cleanupScreens); @@ -56,7 +57,10 @@ describe("paginated table picker contract", () => { test("retries a failed query", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("access denied")); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "access denied"); expect(r.lastFrame()).toContain("[r] retry"); @@ -80,7 +84,10 @@ describe("paginated table picker contract", () => { if (args[0] === "t2") throw new Error("page unavailable"); return listHarnesses(...args); }; - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); await r.write("l"); @@ -96,7 +103,10 @@ describe("paginated table picker contract", () => { const core = new TestCoreClient(); const pending = Promise.withResolvers(); core.harness.listHarnesses = async () => pending.promise; - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "loading harnesses"); await r.press("escape"); @@ -106,7 +116,10 @@ describe("paginated table picker contract", () => { test("keeps Escape active after a query fails", async () => { const core = new TestCoreClient(); core.harness.setError(new Error("access denied")); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "access denied"); await r.press("escape"); @@ -114,7 +127,9 @@ describe("paginated table picker contract", () => { }); test("distinguishes first-page and later-page empty states", async () => { - const firstPage = renderImperativeScreen("/agentcore/harness/list"); + const firstPage = renderScreen("/agentcore/harness/list", { + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(firstPage.lastFrame, "No harnesses found in this Region."); expect(firstPage.lastFrame()).not.toContain("page 1"); await firstPage.press("escape"); @@ -127,7 +142,10 @@ describe("paginated table picker contract", () => { nextToken: "t2", }); core.harness.setListResponse({ harnesses: [] }, "t2"); - const laterPage = renderImperativeScreen("/agentcore/harness/list", { core }); + const laterPage = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(laterPage.lastFrame, "page 1 · more →"); await laterPage.write("l"); @@ -153,7 +171,10 @@ describe("paginated table picker contract", () => { "t2", ); core.harness.setGetResponse(getResponse(first)); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); expect(r.lastFrame()).toContain("[←→/hl] page"); @@ -211,7 +232,11 @@ describe("paginated table picker contract", () => { queries: { retry: false, gcTime: Infinity, staleTime: 0 }, }, }); - const r = renderImperativeScreen("/agentcore/harness/list", { core, queryClient }); + const r = renderScreen("/agentcore/harness/list", { + core, + queryClient, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); await r.write("l"); @@ -261,7 +286,10 @@ describe("paginated table picker contract", () => { "t2", ); core.harness.setGetResponse(getResponse(first)); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); await r.write("l"); @@ -286,7 +314,10 @@ describe("paginated table picker contract", () => { const core = coreWith([alpha, beta]); core.harness.setListResponse({ harnesses: [alpha, beta], nextToken: "t2" }); core.harness.setGetResponse(getResponse(alpha)); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "beta"); await r.press("down"); @@ -323,7 +354,10 @@ describe("paginated table picker contract", () => { }), ], }); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "orders-beta"); await r.write("/"); @@ -379,7 +413,10 @@ describe("paginated table picker contract", () => { }, "t2", ); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "matching-page-one"); await r.write("/"); @@ -406,7 +443,10 @@ describe("paginated table picker contract", () => { ), nextToken: "t2", }); - const r = renderImperativeScreen("/agentcore/harness/list", { core }); + const r = renderScreen("/agentcore/harness/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "page 1 · more →"); let lines = (r.lastFrame() ?? "").split("\n"); @@ -437,7 +477,10 @@ describe("paginated table picker contract", () => { }), nextToken: "t2", }); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await r.resize(60, 24); await waitFor(() => { @@ -465,7 +508,10 @@ describe("paginated table picker contract", () => { }), ), }); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, suffixes[0]!); for (const width of [100, 80, 60]) { @@ -492,7 +538,10 @@ describe("paginated table picker contract", () => { test("filters against rendered timestamps and raw identifiers", async () => { const core = new TestCoreClient(); core.runtime.setListResponse({ agentRuntimes: [runtime()] }); - const r = renderImperativeScreen("/agentcore/runtime/list", { core }); + const r = renderScreen("/agentcore/runtime/list", { + core, + globalConfig: IMPERATIVE_GLOBAL_CONFIG, + }); await waitForText(r.lastFrame, "AbCdEf1234"); await r.write("/"); diff --git a/src/components/ProjectResourceCreateScreen.test.tsx b/src/components/ProjectResourceCreateScreen.test.tsx index a32294ad19..d744a1252a 100644 --- a/src/components/ProjectResourceCreateScreen.test.tsx +++ b/src/components/ProjectResourceCreateScreen.test.tsx @@ -3,7 +3,7 @@ import { cleanupScreens, compiledRootCommand, menuEntries, - renderImperativeScreen, + renderScreen, IMPERATIVE_GLOBAL_CONFIG, waitForText, } from "../testing"; @@ -43,7 +43,7 @@ describe("project resource creation guidance", () => { test.each(RESOURCES)( "$resource lists create in its TUI menu and opens project instructions", async ({ resource, label, parentDescription, addCommand }) => { - const r = renderImperativeScreen(`/agentcore/${resource}`); + const r = renderScreen(`/agentcore/${resource}`, { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "❯ create"); expect(menuEntries(r.lastFrame()!).screens[0]).toBe("create"); @@ -75,7 +75,7 @@ describe("project resource creation guidance", () => { test.each(RESOURCES.filter(({ resource }) => resource !== "gateway"))( "$resource keeps project guidance when Gateway mutations are enabled", async ({ resource, label, addCommand }) => { - const r = renderImperativeScreen(`/agentcore/${resource}`, { globalConfig: MUTATION_CONFIG }); + const r = renderScreen(`/agentcore/${resource}`, { globalConfig: MUTATION_CONFIG }); await waitForText(r.lastFrame, "type to choose a command"); const entries = menuEntries(r.lastFrame()!); expect(entries.screens[0]).toBe("create"); diff --git a/src/components/Root.test.tsx b/src/components/Root.test.tsx index ced018f34b..d52fc3c3b3 100644 --- a/src/components/Root.test.tsx +++ b/src/components/Root.test.tsx @@ -5,7 +5,7 @@ import { cleanupScreens, compiledRootCommand, IMPERATIVE_GLOBAL_CONFIG, - renderImperativeScreen, + renderScreen, waitFor, } from "../testing"; @@ -62,7 +62,7 @@ describe("every command with a screen", () => { test.each(SCREENS.map(([path, command]) => [path.join(" "), path, command] as const))( "%s opens, and esc returns to a menu above it", async (_label, path, command) => { - const r = renderImperativeScreen("/" + path.join("/")); + const r = renderScreen("/" + path.join("/"), { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); // Wide and tall enough that the header never wraps. await r.resize(220, 200); const menus = ancestorMenuHeaders(path, command); diff --git a/src/components/RouterScreen.test.tsx b/src/components/RouterScreen.test.tsx index 3dd9893295..03f67b6059 100644 --- a/src/components/RouterScreen.test.tsx +++ b/src/components/RouterScreen.test.tsx @@ -3,9 +3,9 @@ import { cleanupScreens, menuEntries, renderScreen, - renderImperativeScreen, tick, waitForText, + IMPERATIVE_GLOBAL_CONFIG, } from "../testing"; afterEach(cleanupScreens); @@ -32,7 +32,7 @@ describe("menu rendering", () => { }); test("lists standalone commands in the root menu when enabled", async () => { - const r = renderImperativeScreen("/agentcore"); + const r = renderScreen("/agentcore", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "type to choose a command"); const entries = menuEntries(r.lastFrame()!); @@ -50,7 +50,7 @@ describe("menu rendering", () => { }); test("renders the harness subcommands when mounted at the harness path", async () => { - const r = renderImperativeScreen("/agentcore/harness"); + const r = renderScreen("/agentcore/harness", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "list"); const frame = r.lastFrame()!; @@ -71,7 +71,7 @@ describe("menu rendering", () => { describe("filtering", () => { test("typing narrows the options to matches", async () => { - const r = renderImperativeScreen("/agentcore/harness"); + const r = renderScreen("/agentcore/harness", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "list"); await r.write("cr"); // matches "create" only @@ -85,7 +85,7 @@ describe("filtering", () => { }); test("filtering is case-insensitive", async () => { - const r = renderImperativeScreen("/agentcore/harness"); + const r = renderScreen("/agentcore/harness", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "list"); await r.write("LIST"); @@ -94,7 +94,7 @@ describe("filtering", () => { }); test("shows a no-matches message when nothing matches", async () => { - const r = renderImperativeScreen("/agentcore/harness"); + const r = renderScreen("/agentcore/harness", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "list"); await r.write("zzz"); @@ -151,7 +151,7 @@ describe("navigation", () => { }); test("esc from a nested menu returns to the parent menu", async () => { - const r = renderImperativeScreen("/agentcore/harness"); + const r = renderScreen("/agentcore/harness", { globalConfig: IMPERATIVE_GLOBAL_CONFIG }); await waitForText(r.lastFrame, "agentcore → harness"); await r.press("escape"); diff --git a/src/testing/index.tsx b/src/testing/index.tsx index ce915bf9ab..30735c2f8e 100644 --- a/src/testing/index.tsx +++ b/src/testing/index.tsx @@ -23,7 +23,6 @@ export { StreamController } from "./StreamController"; export { compiledRootCommand, renderScreen, - renderImperativeScreen, cleanupScreens, keys, waitForText, diff --git a/src/testing/renderScreen.tsx b/src/testing/renderScreen.tsx index 1817757937..e99c823e11 100644 --- a/src/testing/renderScreen.tsx +++ b/src/testing/renderScreen.tsx @@ -10,7 +10,7 @@ import { TestCoreClient } from "./TestCoreClient"; import { testIO } from "./testIO"; import { tick, waitFor } from "./timing"; import { createSilentLogger } from "./logging"; -import { IMPERATIVE_GLOBAL_CONFIG, TestGlobalConfigAccessor } from "./globalConfig"; +import { TestGlobalConfigAccessor } from "./globalConfig"; import { DEFAULT_GLOBAL_CONFIG, type GlobalConfig } from "../globalConfig"; // TUI test harness. @@ -183,16 +183,6 @@ export function renderScreen(path: string, options: RenderScreenOptions = {}): R }; } -export function renderImperativeScreen( - path: string, - options: RenderScreenOptions = {}, -): RenderScreenResult { - return renderScreen(path, { - ...options, - globalConfig: options.globalConfig ?? IMPERATIVE_GLOBAL_CONFIG, - }); -} - // waitForText resolves once `text` appears in the latest frame. export function waitForText( lastFrame: () => string | undefined,