From 27797301d63e74a037b3a40691ae83c971fd5a9b Mon Sep 17 00:00:00 2001 From: Cristian Greco Date: Tue, 26 May 2026 11:30:52 +0100 Subject: [PATCH] Add default wait strategy hook --- docs/features/containers.md | 18 ++++++++++++++++++ .../src/generic-container/generic-container.ts | 3 +++ .../utils/wait-strategy-selector.test.ts | 13 +++++++++++++ .../utils/wait-strategy-selector.ts | 4 +++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/features/containers.md b/docs/features/containers.md index 743444034..53415fa07 100644 --- a/docs/features/containers.md +++ b/docs/features/containers.md @@ -582,6 +582,24 @@ class CustomStartedContainer extends AbstractStartedContainer { } ``` +### Default wait strategy for custom containers + +Custom containers can define a fallback wait strategy by overriding `getDefaultWaitStrategy`. Testcontainers uses this when the user has not explicitly set a wait strategy and neither the container nor its image defines a health check: + +```ts +import { GenericContainer, Wait, WaitStrategy } from "testcontainers"; + +class CustomContainer extends GenericContainer { + constructor() { + super("custom/image:1.0.0"); + } + + protected override getDefaultWaitStrategy(): WaitStrategy { + return Wait.forLogMessage("ready"); + } +} +``` + ## Exposing container ports Specify which container ports you want accessible by the host: diff --git a/packages/testcontainers/src/generic-container/generic-container.ts b/packages/testcontainers/src/generic-container/generic-container.ts index d9699aea1..6334e7e13 100644 --- a/packages/testcontainers/src/generic-container/generic-container.ts +++ b/packages/testcontainers/src/generic-container/generic-container.ts @@ -87,6 +87,8 @@ export class GenericContainer implements TestContainer { protected containerStarting?(inspectResult: InspectResult, reused: boolean): Promise; + protected getDefaultWaitStrategy?(): WaitStrategy; + public async start(): Promise { const client = await getContainerRuntimeClient(); await client.image.pull(this.imageName, { @@ -132,6 +134,7 @@ export class GenericContainer implements TestContainer { waitStrategy, healthCheck: this.healthCheck, imageNames: [this.imageName.string], + defaultWaitStrategy: this.getDefaultWaitStrategy?.(), }); } diff --git a/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.test.ts b/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.test.ts index 8fe99894e..60552c271 100644 --- a/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.test.ts +++ b/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.test.ts @@ -136,6 +136,19 @@ describe("wait strategy selector", () => { ).resolves.toBeInstanceOf(HostPortWaitStrategy); }); + it("should select the default wait strategy when no healthcheck is configured", async () => { + const defaultWaitStrategy = Wait.forLogMessage("ready"); + + await expect( + selectWaitStrategy({ + client: client({} as ImageInspectInfo), + inspectResult: containerInspectResult(), + imageNames: ["image:latest"], + defaultWaitStrategy, + }) + ).resolves.toBe(defaultWaitStrategy); + }); + it("should select image healthcheck when container inspect omits healthcheck config", async () => { await expect( selectWaitStrategy({ diff --git a/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.ts b/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.ts index 20b97718f..57d74bff8 100644 --- a/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.ts +++ b/packages/testcontainers/src/wait-strategies/utils/wait-strategy-selector.ts @@ -17,6 +17,7 @@ type WaitStrategySelectorOptions = { waitStrategy?: WaitStrategy; healthCheck?: HealthCheck; imageNames?: string[]; + defaultWaitStrategy?: WaitStrategy; }; export const selectWaitStrategy = async ({ @@ -25,13 +26,14 @@ export const selectWaitStrategy = async ({ waitStrategy, healthCheck, imageNames = getImageNames(inspectResult), + defaultWaitStrategy = Wait.forListeningPorts(), }: WaitStrategySelectorOptions): Promise => { if (waitStrategy) return waitStrategy; if (hasHealthCheck(healthCheck)) return Wait.forHealthCheck(); if (hasDisabledHealthCheckConfig(inspectResult)) return Wait.forListeningPorts(); if (hasHealthCheckConfig(inspectResult) || hasHealthCheckStatus(inspectResult)) return Wait.forHealthCheck(); if (await imageHasHealthCheck(client, imageNames)) return Wait.forHealthCheck(); - return Wait.forListeningPorts(); + return defaultWaitStrategy; }; const getImageNames = (inspectResult: ContainerInspectInfo): string[] => {