From f58f031ebd1a1e1c8d7a43f1eba6fd722b30bb78 Mon Sep 17 00:00:00 2001 From: notgitika Date: Mon, 19 Oct 2026 14:37:08 -0400 Subject: [PATCH] fix(e2e): stabilize runtime template tests --- .github/workflows/e2e-test.yml | 3 +++ e2eTest/project/templates.test.ts | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 11bd502c3..674882677 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -105,6 +105,9 @@ jobs: with: node-version: "24" - uses: astral-sh/setup-uv@v6 + with: + # Keep template installs on the newest Python supported by AgentCore CodeZip. + python-version: "3.14" - run: bun install --frozen-lockfile - name: Fetch E2E role from Secrets Manager uses: aws/agentcore-devx-devtools/.github/actions/fetch-secrets@75989f65f7f193deaf83c237c36572d1a8f800b2 diff --git a/e2eTest/project/templates.test.ts b/e2eTest/project/templates.test.ts index 4b3da2d3c..3845570fc 100644 --- a/e2eTest/project/templates.test.ts +++ b/e2eTest/project/templates.test.ts @@ -146,6 +146,8 @@ const A2aResponseSchema = z.object({ /** The runtime `agentcore create --template` scaffolds (DEFAULT_CREATE_RUNTIME_NAME). */ const CREATED_RUNTIME_NAME = "agent"; +/** Keep concurrent local-dev processes off protocol defaults and one another. */ +const LOCAL_DEV_PORT_BASE = 18080; // Each template gets its own project from `agentcore create --template`, the // command that scaffolds template code (`add runtime` only writes docs). The @@ -169,8 +171,14 @@ describe( }, async (runtime) => { const projectDir = await createTemplateProject(cli, runtime); + let scenarioCompleted = false; try { - await invokeLocally(cli, runtime, projectDir); + await invokeLocally( + cli, + runtime, + projectDir, + LOCAL_DEV_PORT_BASE + RUNTIME_TEMPLATES.indexOf(runtime), + ); const deployment = parseResult( DeployResponseSchema, @@ -208,10 +216,13 @@ describe( ), ); expect(removed.operation).toBe("remove"); + scenarioCompleted = true; } finally { // Tear the stack down even when a step above failed. await cli.run(["remove", "all", "--yes", "--json"], projectDir); - parseResult(JsonObjectSchema, await cli.run(["deploy", "--yes", "--json"], projectDir)); + const cleanup = await cli.run(["deploy", "--yes", "--json"], projectDir); + // A cleanup error must not replace the scenario's primary diagnostic. + if (scenarioCompleted) parseResult(JsonObjectSchema, cleanup); } }, ); @@ -242,6 +253,7 @@ async function invokeLocally( cli: CliRunner, runtime: RuntimeTemplateTestCase, projectDir: string, + devPort: number, ): Promise { let port: number | undefined; let pendingOutput = ""; @@ -259,7 +271,7 @@ async function invokeLocally( } }; - const dev = cli.start(["dev", "--mode", "headless"], projectDir); + const dev = cli.start(["dev", "--mode", "headless", "--port", String(devPort)], projectDir); dev.stdout?.on("data", captureDevOutput); dev.stderr?.on("data", captureDevOutput); dev.stdout?.resume();