diff --git a/packages/testcontainers/src/container-runtime/auth/get-auth-config.test.ts b/packages/testcontainers/src/container-runtime/auth/get-auth-config.test.ts index 3ea88ffe1..bb9e8887d 100644 --- a/packages/testcontainers/src/container-runtime/auth/get-auth-config.test.ts +++ b/packages/testcontainers/src/container-runtime/auth/get-auth-config.test.ts @@ -14,20 +14,22 @@ describe("get auth config", () => { }); afterEach(() => { - delete process.env.DOCKER_AUTH_CONFIG; vi.resetModules(); }); it("should use DOCKER_AUTH_CONFIG environment variable as Docker config", async () => { - process.env.DOCKER_AUTH_CONFIG = JSON.stringify({ - auths: { - "https://registry.example.com": { - email: "user@example.com", - username: "user", - password: "pass", + vi.stubEnv( + "DOCKER_AUTH_CONFIG", + JSON.stringify({ + auths: { + "https://registry.example.com": { + email: "user@example.com", + username: "user", + password: "pass", + }, }, - }, - }); + }) + ); const { getAuthConfig } = await import("./get-auth-config"); expect(await getAuthConfig("https://registry.example.com")).toEqual({ username: "user", diff --git a/packages/testcontainers/src/container-runtime/image-name.test.ts b/packages/testcontainers/src/container-runtime/image-name.test.ts index fe919ae62..4f87519cc 100644 --- a/packages/testcontainers/src/container-runtime/image-name.test.ts +++ b/packages/testcontainers/src/container-runtime/image-name.test.ts @@ -57,21 +57,12 @@ describe("ContainerImage", () => { it.each(["custom.com/registry", "custom.com/registry/"])( "should substitute no registry with the one provided via TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX when provided registry is %s", (customRegistry: string) => { - const oldEnvValue = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX; - try { - process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = customRegistry; - const imageName = new ImageName(undefined, "image", "tag"); - expect(imageName.registry).toBe("custom.com"); - expect(imageName.image).toBe("registry/image"); - expect(imageName.tag).toBe("tag"); - expect(imageName.string).toBe("custom.com/registry/image:tag"); - } finally { - if (oldEnvValue === undefined) { - delete process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX; - } else { - process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = oldEnvValue; - } - } + vi.stubEnv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX", customRegistry); + const imageName = new ImageName(undefined, "image", "tag"); + expect(imageName.registry).toBe("custom.com"); + expect(imageName.image).toBe("registry/image"); + expect(imageName.tag).toBe("tag"); + expect(imageName.string).toBe("custom.com/registry/image:tag"); } ); }); @@ -176,18 +167,8 @@ describe("ContainerImage", () => { ])( "fromString with TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX set to $customRegistry", ({ customRegistry, expectedRegistry, expectedImagePrefix }) => { - let oldEnvValue: string | undefined; beforeEach(() => { - oldEnvValue = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX; - process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = customRegistry; - }); - - afterEach(() => { - if (oldEnvValue === undefined) { - delete process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX; - } else { - process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = oldEnvValue; - } + vi.stubEnv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX", customRegistry); }); it("should work", () => { diff --git a/packages/testcontainers/src/generic-container/generic-container-reuse.test.ts b/packages/testcontainers/src/generic-container/generic-container-reuse.test.ts index 6d53b7cbc..785d92733 100644 --- a/packages/testcontainers/src/generic-container/generic-container-reuse.test.ts +++ b/packages/testcontainers/src/generic-container/generic-container-reuse.test.ts @@ -3,10 +3,6 @@ import { checkContainerIsHealthy } from "../utils/test-helper"; import { GenericContainer } from "./generic-container"; describe("GenericContainer reuse", { timeout: 180_000 }, () => { - afterEach(() => { - process.env.TESTCONTAINERS_REUSE_ENABLE = undefined; - }); - it("should not reuse the container by default", async () => { const name = `there_can_only_be_one_${randomUuid()}`; const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") @@ -64,7 +60,7 @@ describe("GenericContainer reuse", { timeout: 180_000 }, () => { }); it("should not reuse the container when TESTCONTAINERS_REUSE_ENABLE is set to false", async () => { - process.env.TESTCONTAINERS_REUSE_ENABLE = "false"; + vi.stubEnv("TESTCONTAINERS_REUSE_ENABLE", "false"); const name = `there_can_only_be_one_${randomUuid()}`; const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") @@ -90,7 +86,7 @@ describe("GenericContainer reuse", { timeout: 180_000 }, () => { it.each(["true", undefined])( "should reuse the container when TESTCONTAINERS_REUSE_ENABLE is set to %s", async (reuseEnable: string | undefined) => { - process.env.TESTCONTAINERS_REUSE_ENABLE = reuseEnable; + vi.stubEnv("TESTCONTAINERS_REUSE_ENABLE", reuseEnable); const name = `there_can_only_be_one_${randomUuid()}`; const container1 = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") diff --git a/packages/testcontainers/src/reaper/reaper.test.ts b/packages/testcontainers/src/reaper/reaper.test.ts index 4421c4c56..593b06610 100644 --- a/packages/testcontainers/src/reaper/reaper.test.ts +++ b/packages/testcontainers/src/reaper/reaper.test.ts @@ -1,4 +1,5 @@ import { ContainerRuntimeClient, getContainerRuntimeClient } from "../container-runtime"; +import { RandomUniquePortGenerator } from "../utils/port-generator"; describe("Reaper", { timeout: 120_000 }, () => { let client: ContainerRuntimeClient; @@ -7,11 +8,45 @@ describe("Reaper", { timeout: 120_000 }, () => { beforeEach(async () => { vi.resetModules(); - vitest.unstubAllEnvs(); - client = await getContainerRuntimeClient(); }); + it("should create disabled reaper when TESTCONTAINERS_RYUK_DISABLED=true", async () => { + vi.stubEnv("TESTCONTAINERS_RYUK_DISABLED", "true"); + + vi.spyOn(client.container, "list").mockResolvedValue([]); + const reaper = await getReaper(); + + // DisabledReaper has an empty containerId + expect(reaper.containerId).toBe(""); + + // Should not throw exceptions when methods are called + expect(() => reaper.addSession("test-session")).not.toThrow(); + expect(() => reaper.addComposeProject("test-project")).not.toThrow(); + }); + + it("should use custom port when TESTCONTAINERS_RYUK_PORT is set", async () => { + const customPort = (await new RandomUniquePortGenerator().generatePort()).toString(); + vi.stubEnv("TESTCONTAINERS_RYUK_PORT", customPort); + + vi.spyOn(client.container, "list").mockResolvedValue([]); + const reaper = await getReaper(); + + const reaperContainer = client.container.getById(reaper.containerId); + const ports = (await reaperContainer.inspect()).HostConfig.PortBindings; + expect(ports["8080"][0].HostPort).toBe(customPort); + }); + + it("should reuse existing reaper container if one is already running", async () => { + const reaper = await getReaper(); + const reaperContainerInfo = (await client.container.list()).filter((c) => c.Id === reaper.containerId)[0]; + vi.spyOn(client.container, "list").mockResolvedValue([reaperContainerInfo]); + + const reaper2 = await getReaper(); + + expect(reaper2.containerId).toBe(reaper.containerId); + }); + it("should create Reaper container without RYUK_VERBOSE env var by default", async () => { vi.spyOn(client.container, "list").mockResolvedValue([]); const reaper = await getReaper(); @@ -23,7 +58,7 @@ describe("Reaper", { timeout: 120_000 }, () => { }); it("should propagate TESTCONTAINERS_RYUK_VERBOSE into Reaper container", async () => { - vitest.stubEnv("TESTCONTAINERS_RYUK_VERBOSE", "true"); + vi.stubEnv("TESTCONTAINERS_RYUK_VERBOSE", "true"); vi.spyOn(client.container, "list").mockResolvedValue([]); const reaper = await getReaper(); diff --git a/vitest.config.ts b/vitest.config.ts index 0c166ea7b..fb3d8d26d 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,6 +7,7 @@ export default defineConfig({ silent: "passed-only", mockReset: true, restoreMocks: true, + unstubEnvs: true, alias: { testcontainers: path.resolve(__dirname, "packages/testcontainers/src"), },