From 981d5fb5c3ec8702d33504120fd2156219327077 Mon Sep 17 00:00:00 2001 From: kenny-ish <114967656+kenny-ish@users.noreply.github.com> Date: Sat, 17 Oct 2026 09:17:11 +0000 Subject: [PATCH] Fix duplicate environment entries when withEnvironment sets a key twice withEnvironment merged the new variables into this.environment but appended them to createOpts.Env, so setting a key twice sent both entries to Docker. The last one won at runtime, but docker inspect showed the stale value, the reuse hash differed from a container configured with the final value once, and subclasses that need to change a variable had to edit createOpts.Env by hand. Build createOpts.Env from the merged environment so it holds one entry per key. Document that repeated withEnvironment calls add to the variables and that setting a key again replaces its value. Fixes #1519 --- docs/features/containers.md | 2 ++ .../generic-container.test.ts | 19 +++++++++++++++++++ .../generic-container/generic-container.ts | 5 +---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/features/containers.md b/docs/features/containers.md index 6310b872c..3bb68813c 100644 --- a/docs/features/containers.md +++ b/docs/features/containers.md @@ -83,6 +83,8 @@ const container = await new GenericContainer("alpine") .start(); ``` +Calling `withEnvironment` more than once adds to the variables set before. Setting a key again replaces its value. + ### With a platform ```js diff --git a/packages/testcontainers/src/generic-container/generic-container.test.ts b/packages/testcontainers/src/generic-container/generic-container.test.ts index 805de6c97..3e6cd113f 100644 --- a/packages/testcontainers/src/generic-container/generic-container.test.ts +++ b/packages/testcontainers/src/generic-container/generic-container.test.ts @@ -163,6 +163,25 @@ describe("GenericContainer", { timeout: 180_000 }, () => { expect(responseBody.customKey).toBe("customValue"); }); + it("should replace an environment variable that is set twice", async () => { + await using container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") + .withEnvironment({ customKey: "first", otherKey: "otherValue" }) + .withEnvironment({ customKey: "second" }) + .withExposedPorts(8080) + .start(); + + const client = await getContainerRuntimeClient(); + const dockerContainer = client.container.getById(container.getId()); + const containerInfo = await dockerContainer.inspect(); + expect(containerInfo.Config.Env.filter((env) => env.startsWith("customKey="))).toEqual(["customKey=second"]); + expect(containerInfo.Config.Env).toContain("otherKey=otherValue"); + + const url = `http://${container.getHost()}:${container.getMappedPort(8080)}`; + const response = await fetch(`${url}/env`); + const responseBody = (await response.json()) as { [key: string]: string }; + expect(responseBody.customKey).toBe("second"); + }); + it("should set command", async () => { await using container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") .withCommand(["node", "index.js", "one", "two", "three"]) diff --git a/packages/testcontainers/src/generic-container/generic-container.ts b/packages/testcontainers/src/generic-container/generic-container.ts index daa4a6357..fcb038bac 100644 --- a/packages/testcontainers/src/generic-container/generic-container.ts +++ b/packages/testcontainers/src/generic-container/generic-container.ts @@ -348,10 +348,7 @@ export class GenericContainer implements TestContainer { public withEnvironment(environment: Environment): this { this.environment = { ...this.environment, ...environment }; - this.createOpts.Env = [ - ...(this.createOpts.Env ?? []), - ...Object.entries(environment).map(([key, value]) => `${key}=${value}`), - ]; + this.createOpts.Env = Object.entries(this.environment).map(([key, value]) => `${key}=${value}`); return this; }