From 52a9050378f35be3860d481c60589dd822a57482 Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Tue, 22 Jul 2025 19:50:21 +0100 Subject: [PATCH 1/7] Wait for ports to be bound when container restarts --- .../generic-container/generic-container.ts | 12 +--- ...spect-container-util-ports-exposed.test.ts | 68 ++++++++----------- .../inspect-container-util-ports-exposed.ts | 25 ++----- .../started-generic-container.ts | 6 +- 4 files changed, 44 insertions(+), 67 deletions(-) diff --git a/packages/testcontainers/src/generic-container/generic-container.ts b/packages/testcontainers/src/generic-container/generic-container.ts index 7c2ec2358..93ae90792 100644 --- a/packages/testcontainers/src/generic-container/generic-container.ts +++ b/packages/testcontainers/src/generic-container/generic-container.ts @@ -142,13 +142,7 @@ export class GenericContainer implements TestContainer { if (!inspectResult.State.Running) { log.debug("Reused container is not running, attempting to start it"); await client.container.start(container); - inspectResult = ( - await inspectContainerUntilPortsExposed( - () => client.container.inspect(container), - this.exposedPorts, - container.id - ) - ).inspectResult; + inspectResult = await inspectContainerUntilPortsExposed(() => client.container.inspect(container), container.id); } const mappedInspectResult = mapInspectResult(inspectResult); @@ -202,11 +196,11 @@ export class GenericContainer implements TestContainer { await client.container.start(container); log.info(`Started container for image "${this.createOpts.Image}"`, { containerId: container.id }); - const { inspectResult, mappedInspectResult } = await inspectContainerUntilPortsExposed( + const inspectResult = await inspectContainerUntilPortsExposed( () => client.container.inspect(container), - this.exposedPorts, container.id ); + const mappedInspectResult = mapInspectResult(inspectResult); const boundPorts = BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult).filter( this.exposedPorts ); diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts index b198bb02d..f98e1443d 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts @@ -1,72 +1,64 @@ import { ContainerInspectInfo } from "dockerode"; -import { mapInspectResult } from "../utils/map-inspect-result"; import { inspectContainerUntilPortsExposed } from "./inspect-container-util-ports-exposed"; -function mockInspectResult(ports: ContainerInspectInfo["NetworkSettings"]["Ports"]) { - const date = new Date(); - - const inspectResult: ContainerInspectInfo = { - Name: "container-id", - Config: { - Hostname: "hostname", - Labels: {}, - }, - State: { - Health: { - Status: "healthy", - }, - Status: "running", - Running: true, - StartedAt: date.toISOString(), - FinishedAt: date.toISOString(), +function mockInspectResult( + portBindings: ContainerInspectInfo["HostConfig"]["PortBindings"], + ports: ContainerInspectInfo["NetworkSettings"]["Ports"] +): ContainerInspectInfo { + return { + HostConfig: { + PortBindings: portBindings, }, NetworkSettings: { Ports: ports, Networks: {}, }, } as unknown as ContainerInspectInfo; - - return { inspectResult, mappedInspectResult: mapInspectResult(inspectResult) }; } -test("returns the inspect results when all ports are exposed", async () => { - const data = mockInspectResult({ "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); - const inspectFn = vi.fn().mockResolvedValueOnce(data.inspectResult); +test("returns the inspect result when all ports are exposed", async () => { + const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + const inspectFn = vi.fn().mockResolvedValueOnce(data); + + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); + + expect(result).toEqual(data); +}); + +test("returns the inspect result when no ports are exposed", async () => { + const data = mockInspectResult({}, {}); + const inspectFn = vi.fn().mockResolvedValueOnce(data); - const result = await inspectContainerUntilPortsExposed(inspectFn, [8080], "container-id"); + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); expect(result).toEqual(data); }); test("retries the inspect if ports are not yet exposed", async () => { - const data1 = mockInspectResult({ "8080/tcp": [] }); - const data2 = mockInspectResult({ "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); - const inspectFn = vi - .fn() - .mockResolvedValueOnce(data1.inspectResult) - .mockResolvedValueOnce(data1.inspectResult) - .mockResolvedValueOnce(data2.inspectResult); + const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); + const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2); - const result = await inspectContainerUntilPortsExposed(inspectFn, [8080], "container-id"); + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); expect(result).toEqual(data2); expect(inspectFn).toHaveBeenCalledTimes(3); }); test("throws an error when host ports are not exposed within timeout", async () => { - const data = mockInspectResult({ "8080/tcp": [] }); - const inspectFn = vi.fn().mockResolvedValue(data.inspectResult); + const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); + const inspectFn = vi.fn().mockResolvedValue(data); - await expect(inspectContainerUntilPortsExposed(inspectFn, [8080], "container-id", 0)).rejects.toThrow( + await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( "Container did not expose all ports after starting" ); }); test("throws an error when container ports not exposed within timeout", async () => { - const data = mockInspectResult({}); - const inspectFn = vi.fn().mockResolvedValue(data.inspectResult); + const data = mockInspectResult({ "8080/tcp": [] }, {}); + const inspectFn = vi.fn().mockResolvedValue(data); - await expect(inspectContainerUntilPortsExposed(inspectFn, [8080], "container-id", 0)).rejects.toThrow( + await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( "Container did not expose all ports after starting" ); }); diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts index 762154633..a9f22ccfc 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts @@ -1,30 +1,17 @@ import { ContainerInspectInfo } from "dockerode"; import { IntervalRetry, log } from "../common"; -import { InspectResult } from "../types"; -import { mapInspectResult } from "../utils/map-inspect-result"; -import { getContainerPort, PortWithOptionalBinding } from "../utils/port"; - -type Result = { - inspectResult: ContainerInspectInfo; - mappedInspectResult: InspectResult; -}; export async function inspectContainerUntilPortsExposed( inspectFn: () => Promise, - ports: PortWithOptionalBinding[], containerId: string, timeout = 10_000 -): Promise { - const result = await new IntervalRetry(250).retryUntil( - async () => { - const inspectResult = await inspectFn(); - const mappedInspectResult = mapInspectResult(inspectResult); - return { inspectResult, mappedInspectResult }; +): Promise { + const result = await new IntervalRetry(250).retryUntil( + () => inspectFn(), + (inspectResult) => { + const exposedPorts = Object.keys(inspectResult.HostConfig.PortBindings); + return exposedPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0); }, - ({ mappedInspectResult }) => - ports - .map((exposedPort) => getContainerPort(exposedPort)) - .every((exposedPort) => mappedInspectResult.ports[exposedPort]?.length > 0), () => { const message = `Container did not expose all ports after starting`; log.error(message, { containerId }); diff --git a/packages/testcontainers/src/generic-container/started-generic-container.ts b/packages/testcontainers/src/generic-container/started-generic-container.ts index 895faead8..771b3bfb9 100644 --- a/packages/testcontainers/src/generic-container/started-generic-container.ts +++ b/packages/testcontainers/src/generic-container/started-generic-container.ts @@ -12,6 +12,7 @@ import { LABEL_TESTCONTAINERS_SESSION_ID } from "../utils/labels"; import { mapInspectResult } from "../utils/map-inspect-result"; import { waitForContainer } from "../wait-strategies/wait-for-container"; import { WaitStrategy } from "../wait-strategies/wait-strategy"; +import { inspectContainerUntilPortsExposed } from "./inspect-container-util-ports-exposed"; import { StoppedGenericContainer } from "./stopped-generic-container"; export class StartedGenericContainer implements StartedTestContainer { @@ -80,7 +81,10 @@ export class StartedGenericContainer implements StartedTestContainer { const resolvedOptions: RestartOptions = { timeout: 0, ...options }; await client.container.restart(this.container, resolvedOptions); - this.inspectResult = await client.container.inspect(this.container); + this.inspectResult = await inspectContainerUntilPortsExposed( + () => client.container.inspect(this.container), + this.container.id + ); const mappedInspectResult = mapInspectResult(this.inspectResult); const startTime = new Date(this.inspectResult.State.StartedAt); From 5134356fb9bf7c382005ca7ac0bad10a6be91774 Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Tue, 22 Jul 2025 20:42:40 +0100 Subject: [PATCH 2/7] Port bindings can be undefined --- ...spect-container-util-ports-exposed.test.ts | 82 +++++++++++-------- .../inspect-container-util-ports-exposed.ts | 6 +- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts index f98e1443d..509f3be9e 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts @@ -11,54 +11,66 @@ function mockInspectResult( }, NetworkSettings: { Ports: ports, - Networks: {}, }, - } as unknown as ContainerInspectInfo; + } as ContainerInspectInfo; } -test("returns the inspect result when all ports are exposed", async () => { - const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); - const inspectFn = vi.fn().mockResolvedValueOnce(data); +describe.sequential("inspectContainerUntilPortsExposed", () => { + it("returns the inspect result when all ports are exposed", async () => { + const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + const inspectFn = vi.fn().mockResolvedValueOnce(data); - const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); - expect(result).toEqual(data); -}); + expect(result).toEqual(data); + }); -test("returns the inspect result when no ports are exposed", async () => { - const data = mockInspectResult({}, {}); - const inspectFn = vi.fn().mockResolvedValueOnce(data); + it("returns the inspect result when no ports are exposed", async () => { + const data = mockInspectResult({}, {}); + const inspectFn = vi.fn().mockResolvedValueOnce(data); - const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); - expect(result).toEqual(data); -}); + expect(result).toEqual(data); + }); -test("retries the inspect if ports are not yet exposed", async () => { - const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); - const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); - const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2); + it("retries the inspect if ports are not yet exposed", async () => { + const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); + const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2); - const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); - expect(result).toEqual(data2); - expect(inspectFn).toHaveBeenCalledTimes(3); -}); + expect(result).toEqual(data2); + expect(inspectFn).toHaveBeenCalledTimes(3); + }); -test("throws an error when host ports are not exposed within timeout", async () => { - const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); - const inspectFn = vi.fn().mockResolvedValue(data); + it("retries the inspect if port bindings are undefined", async () => { + const data1 = mockInspectResult(undefined, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2); - await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( - "Container did not expose all ports after starting" - ); -}); + const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); + + expect(result).toEqual(data2); + expect(inspectFn).toHaveBeenCalledTimes(3); + }); + + it("throws an error when host ports are not exposed within timeout", async () => { + const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); + const inspectFn = vi.fn().mockResolvedValue(data); + + await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( + "Container did not expose all ports after starting" + ); + }); -test("throws an error when container ports not exposed within timeout", async () => { - const data = mockInspectResult({ "8080/tcp": [] }, {}); - const inspectFn = vi.fn().mockResolvedValue(data); + it("throws an error when container ports not exposed within timeout", async () => { + const data = mockInspectResult({ "8080/tcp": [] }, {}); + const inspectFn = vi.fn().mockResolvedValue(data); - await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( - "Container did not expose all ports after starting" - ); + await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( + "Container did not expose all ports after starting" + ); + }); }); diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts index a9f22ccfc..2981e6be2 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts @@ -9,8 +9,10 @@ export async function inspectContainerUntilPortsExposed( const result = await new IntervalRetry(250).retryUntil( () => inspectFn(), (inspectResult) => { - const exposedPorts = Object.keys(inspectResult.HostConfig.PortBindings); - return exposedPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0); + const portBindings = inspectResult?.HostConfig?.PortBindings; + if (!portBindings) return false; + const expectedlyBoundPorts = Object.keys(portBindings); + return expectedlyBoundPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0); }, () => { const message = `Container did not expose all ports after starting`; From c7019d88e3f508d5c2e01bc73a56af92ca751558 Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Wed, 23 Jul 2025 09:38:08 +0100 Subject: [PATCH 3/7] Run smoke tests with logs --- .github/workflows/checks.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 2e1d25818..bbe4c7c54 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -124,8 +124,12 @@ jobs: run: npm prune --omit=dev --workspace packages/testcontainers - name: Run CommonJS module smoke test run: node packages/testcontainers/smoke-test.js + env: + DEBUG: "testcontainers:*" - name: Run ES module smoke test run: node packages/testcontainers/smoke-test.mjs + env: + DEBUG: "testcontainers:*" test: if: ${{ needs.detect-modules.outputs.modules_count > 0 }} From 1081734250851477f06dbda4a1215a94b5980867 Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Wed, 23 Jul 2025 09:43:06 +0100 Subject: [PATCH 4/7] Add debug console.log --- .../generic-container/inspect-container-util-ports-exposed.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts index 2981e6be2..77922d441 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts @@ -10,6 +10,7 @@ export async function inspectContainerUntilPortsExposed( () => inspectFn(), (inspectResult) => { const portBindings = inspectResult?.HostConfig?.PortBindings; + console.log(new Date().toISOString(), JSON.stringify(inspectResult, null, 2)); if (!portBindings) return false; const expectedlyBoundPorts = Object.keys(portBindings); return expectedlyBoundPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0); From d38b052d8b587d8f139ce33eaf167d97cf1fed78 Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Wed, 23 Jul 2025 09:53:01 +0100 Subject: [PATCH 5/7] Add debug console.log --- .github/workflows/checks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index bbe4c7c54..563a15a11 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -125,11 +125,11 @@ jobs: - name: Run CommonJS module smoke test run: node packages/testcontainers/smoke-test.js env: - DEBUG: "testcontainers:*" + DEBUG: "testcontainers*" - name: Run ES module smoke test run: node packages/testcontainers/smoke-test.mjs env: - DEBUG: "testcontainers:*" + DEBUG: "testcontainers*" test: if: ${{ needs.detect-modules.outputs.modules_count > 0 }} From 9bbc1ce1ce831f6a79d9198769b7d5f26f2bd74b Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Wed, 23 Jul 2025 10:06:06 +0100 Subject: [PATCH 6/7] Bug fix --- .../inspect-container-util-ports-exposed.test.ts | 14 ++++++-------- .../inspect-container-util-ports-exposed.ts | 3 +-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts index 509f3be9e..81ed03a16 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts @@ -34,19 +34,17 @@ describe.sequential("inspectContainerUntilPortsExposed", () => { expect(result).toEqual(data); }); - it("retries the inspect if ports are not yet exposed", async () => { - const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); - const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); - const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2); + it("returns the inspect result if host config port bindings are null", async () => { + const data = mockInspectResult(null, {}); + const inspectFn = vi.fn().mockResolvedValueOnce(data); const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id"); - expect(result).toEqual(data2); - expect(inspectFn).toHaveBeenCalledTimes(3); + expect(result).toEqual(data); }); - it("retries the inspect if port bindings are undefined", async () => { - const data1 = mockInspectResult(undefined, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); + it("retries the inspect if ports are not yet exposed", async () => { + const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] }); const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] }); const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2); diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts index 77922d441..41c64750e 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts @@ -10,8 +10,7 @@ export async function inspectContainerUntilPortsExposed( () => inspectFn(), (inspectResult) => { const portBindings = inspectResult?.HostConfig?.PortBindings; - console.log(new Date().toISOString(), JSON.stringify(inspectResult, null, 2)); - if (!portBindings) return false; + if (!portBindings) return true; const expectedlyBoundPorts = Object.keys(portBindings); return expectedlyBoundPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0); }, From 9c51440d7d9c85423d00cdb15bc420e862cdd255 Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Wed, 23 Jul 2025 10:08:56 +0100 Subject: [PATCH 7/7] Better timeout message --- .../inspect-container-util-ports-exposed.test.ts | 4 ++-- .../generic-container/inspect-container-util-ports-exposed.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts index 81ed03a16..dea6280d3 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts @@ -59,7 +59,7 @@ describe.sequential("inspectContainerUntilPortsExposed", () => { const inspectFn = vi.fn().mockResolvedValue(data); await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( - "Container did not expose all ports after starting" + "Timed out after 0ms while waiting for container ports to be bound to the host" ); }); @@ -68,7 +68,7 @@ describe.sequential("inspectContainerUntilPortsExposed", () => { const inspectFn = vi.fn().mockResolvedValue(data); await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow( - "Container did not expose all ports after starting" + "Timed out after 0ms while waiting for container ports to be bound to the host" ); }); }); diff --git a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts index 41c64750e..8209144c7 100644 --- a/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts +++ b/packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts @@ -15,7 +15,7 @@ export async function inspectContainerUntilPortsExposed( return expectedlyBoundPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0); }, () => { - const message = `Container did not expose all ports after starting`; + const message = `Timed out after ${timeout}ms while waiting for container ports to be bound to the host`; log.error(message, { containerId }); return new Error(message); },