Skip to content

Commit 20cdb6d

Browse files
Merge branch 'main' into release-11.0.0
2 parents 2297ff0 + 823950c commit 20cdb6d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2099
-1343
lines changed

docs/features/compose.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,11 @@ const environment = await new DockerComposeEnvironment(composeFilePath, composeF
140140
await environment.down();
141141
```
142142

143-
If you need to wait for the environment to be downed, you can provide a timeout:
143+
If you need to wait for the environment to be downed, you can provide a timeout. The unit of timeout here is **second**:
144144

145145
```javascript
146146
const environment = await new DockerComposeEnvironment(composeFilePath, composeFile).up();
147-
await environment.down({ timeout: 10000 }); // ms
147+
await environment.down({ timeout: 10 }); // timeout after 10 seconds
148148
```
149149

150150
Volumes created by the environment are removed when stopped. This is configurable:

docs/features/containers.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,11 @@ const container = await new GenericContainer("alpine").start();
334334
await container.stop();
335335
```
336336

337-
If you need to wait for the container to be stopped, you can provide a timeout:
337+
If you need to wait for the container to be stopped, you can provide a timeout. The unit of timeout option here is **second**:
338338

339339
```javascript
340340
const container = await new GenericContainer("alpine").start();
341-
await container.stop({ timeout: 10000 }); // ms
341+
await container.stop({ timeout: 10 }); // 10 seconds
342342
```
343343

344344
You can disable automatic removal of the container, which is useful for debugging, or if for example you want to copy content from the container once it has stopped:
@@ -583,6 +583,35 @@ const container = await new GenericContainer("alpine")
583583
.start();
584584
```
585585

586+
## SocatContainer as a TCP proxy
587+
588+
`SocatContainer` enables any TCP port of another container to be exposed publicly.
589+
590+
```javascript
591+
const network = await new Network().start();
592+
593+
const container = await new GenericContainer("testcontainers/helloworld:1.2.0")
594+
.withExposedPorts(8080)
595+
.withNetwork(network)
596+
.withNetworkAliases("helloworld")
597+
.start();
598+
599+
const socat = await new SocatContainer()
600+
.withNetwork(network)
601+
.withTarget(8081, "helloworld", 8080)
602+
.start();
603+
604+
const socatUrl = `http://${socat.getHost()}:${socat.getMappedPort(8081)}`;
605+
606+
const response = await fetch(`${socatUrl}/ping`);
607+
608+
expect(response.status).toBe(200);
609+
expect(await response.text()).toBe("PONG");
610+
```
611+
612+
The example above starts a `testcontainers/helloworld` container and a `socat` container.
613+
The `socat` container is configured to forward traffic from port `8081` to the `testcontainers/helloworld` container on port `8080`.
614+
586615
## Running commands
587616

588617
To run a command inside an already started container, use the exec method.
@@ -605,7 +634,6 @@ The following options can be provided to modify the command execution:
605634

606635
3. **`env`:** A map of environment variables to set inside the container.
607636

608-
609637
```javascript
610638
const container = await new GenericContainer("alpine")
611639
.withCommand(["sleep", "infinity"])
@@ -621,8 +649,6 @@ const { output, stdout, stderr, exitCode } = await container.exec(["echo", "hell
621649
});
622650
```
623651

624-
625-
626652
## Streaming logs
627653

628654
Logs can be consumed either from a started container:

docs/features/wait-strategies.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Wait Strategies
22

3-
Note that the startup timeout of all wait strategies is configurable:
3+
Note that the startup timeout of all wait strategies is configurable. The unit of timeout of wait strategies is **millisecond**:
44

55
```javascript
66
const { GenericContainer } = require("testcontainers");
77

88
const container = await new GenericContainer("alpine")
9-
.withStartupTimeout(120000) // wait 120s
9+
.withStartupTimeout(120000) // wait 120 seconds
1010
.start();
1111
```
1212

@@ -73,7 +73,7 @@ const { GenericContainer, Wait } = require("testcontainers");
7373
const container = await new GenericContainer("alpine").withWaitStrategy(Wait.forHealthCheck()).start();
7474
```
7575

76-
Define your own health check:
76+
Define your own health check. The unit of timeouts and intervals here is **millisecond**:
7777

7878
```javascript
7979
const { GenericContainer, Wait } = require("testcontainers");
@@ -148,21 +148,21 @@ const container = await new GenericContainer("redis")
148148
.withMethod("POST")
149149
.withHeaders({ X_CUSTOM_VALUE: "custom" })
150150
.withBasicCredentials("username", "password")
151-
.withReadTimeout(10000))
151+
.withReadTimeout(10000)) // timeout after 10 seconds
152152
```
153153

154154
### Use TLS
155155

156156
```javascript
157157
.withWaitStrategy(Wait.forHttp("/health", 8443)
158-
.useTls())
158+
.usingTls())
159159
```
160160

161161
#### Insecure TLS
162162

163163
```javascript
164164
.withWaitStrategy(Wait.forHttp("/health", 8443)
165-
.useTls()
165+
.usingTls()
166166
.insecureTls())
167167
```
168168

@@ -202,11 +202,11 @@ const container = await new GenericContainer("alpine")
202202
.start();
203203
```
204204

205-
The composite wait strategy by default will respect each individual wait strategy's startup timeout. For example:
205+
The composite wait strategy by default will respect each individual wait strategy's startup timeout. The unit of timeouts here is **millisecond**. For example:
206206

207207
```javascript
208-
const w1 = Wait.forListeningPorts().withStartupTimeout(1000);
209-
const w2 = Wait.forLogMessage("READY").withStartupTimeout(2000);
208+
const w1 = Wait.forListeningPorts().withStartupTimeout(1000); // wait 1 second
209+
const w2 = Wait.forLogMessage("READY").withStartupTimeout(2000); // wait 2 seconds
210210

211211
const composite = Wait.forAll([w1, w2]);
212212

@@ -217,21 +217,21 @@ expect(w2.getStartupTimeout()).toBe(2000);
217217
The startup timeout of inner wait strategies that have not defined their own startup timeout can be set by setting the startup timeout on the composite:
218218

219219
```javascript
220-
const w1 = Wait.forListeningPorts().withStartupTimeout(1000);
220+
const w1 = Wait.forListeningPorts().withStartupTimeout(1000); // wait 1 second
221221
const w2 = Wait.forLogMessage("READY");
222222

223-
const composite = Wait.forAll([w1, w2]).withStartupTimeout(2000);
223+
const composite = Wait.forAll([w1, w2]).withStartupTimeout(2000); // wait 2 seconds
224224

225225
expect(w1.getStartupTimeout()).toBe(1000);
226226
expect(w2.getStartupTimeout()).toBe(2000);
227227
```
228228

229-
The startup timeout of all wait strategies can be controlled by setting a deadline on the composite. In this case, the composite will throw unless all inner wait strategies have resolved before the deadline.
229+
The startup timeout of all wait strategies can be controlled by setting a deadline on the composite. In this case, the composite will throw unless all inner wait strategies have resolved before the deadline. The unit of deadline timeout is **millisecond**.
230230

231231
```javascript
232232
const w1 = Wait.forListeningPorts();
233233
const w2 = Wait.forLogMessage("READY");
234-
const composite = Wait.forAll([w1, w2]).withDeadline(2000);
234+
const composite = Wait.forAll([w1, w2]).withDeadline(2000); // wait 2 seconds
235235
```
236236

237237
## Other startup strategies
@@ -248,7 +248,7 @@ const {
248248

249249
class ReadyAfterDelayWaitStrategy extends StartupCheckStrategy {
250250
public checkStartupState(dockerClient: Dockerode, containerId: string): Promise<StartupStatus> {
251-
return new Promise((resolve) => setTimeout(() => resolve("SUCCESS"), 3000));
251+
return new Promise((resolve) => setTimeout(() => resolve("SUCCESS"), 3000)); // after 3 seconds
252252
}
253253
}
254254

docs/modules/postgresql.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,18 @@ npm install @testcontainers/postgresql --save-dev
2525
<!--codeinclude-->
2626
[Set username:](../../packages/modules/postgresql/src/postgresql-container.test.ts) inside_block:setUsername
2727
<!--/codeinclude-->
28+
29+
### Using Snapshots
30+
31+
This example shows the usage of the postgres module's Snapshot feature to give each test a clean database without having
32+
to recreate the database container on every test or run heavy scripts to clean your database. This makes the individual
33+
tests very modular, since they always run on a brand-new database.
34+
35+
!!!tip
36+
You should never pass the `"postgres"` system database as the container database name if you want to use snapshots.
37+
The Snapshot logic requires dropping the connected database and using the system database to run commands, which will
38+
not work if the database for the container is set to `"postgres"`.
39+
40+
<!--codeinclude-->
41+
[Test with a reusable Postgres container](../../packages/modules/postgresql/src/postgresql-container-snapshot.test.ts) inside_block:createAndRestoreFromSnapshot
42+
<!--/codeinclude-->

docs/quickstart.md

Lines changed: 0 additions & 61 deletions
This file was deleted.

docs/quickstart/global-setup.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Global setup
2+
3+
If you have a lot of tests that require the same container, you might not want to spin up one per test.
4+
5+
In this case a common pattern is to set the container up globally, and reuse it in your tests. Here's an example using Vitest:
6+
7+
```ts
8+
// setup.js
9+
10+
import { createClient, RedisClientType } from "redis";
11+
import { GenericContainer, StartedTestContainer } from "testcontainers";
12+
13+
export async function setup() {
14+
globalThis.redisContainer = await new GenericContainer("redis")
15+
.withExposedPorts(6379)
16+
.start();
17+
18+
globalThis.redisClient = createClient({
19+
url: `redis://${redisContainer.getHost()}:${redisContainer.getMappedPort(6379)}`
20+
});
21+
22+
await globalThis.redisClient.connect();
23+
}
24+
25+
export async function teardown() {
26+
await globalThis.redisClient.disconnect();
27+
await globalThis.redisContainer.stop();
28+
}
29+
```
30+
31+
```ts
32+
// vite.config.js
33+
34+
import { defineConfig } from "vite";
35+
36+
export default defineConfig({
37+
test: {
38+
setupFiles: "./setup.js",
39+
}
40+
});
41+
```
42+
43+
And to reference the container/client in your tests:
44+
45+
```ts
46+
it("should set and retrieve a value from Redis", async () => {
47+
await globalThis.redisClient.set("key", "test-value");
48+
const result = await globalThis.redisClient.get("key");
49+
50+
expect(result).toBe("test-value");
51+
});
52+
```

docs/quickstart/install.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Install
2+
3+
Install the Testcontainers dependency.
4+
5+
## NPM
6+
7+
```bash
8+
npm install testcontainers --save-dev
9+
```
10+
11+
## Yarn
12+
13+
```bash
14+
yarn add testcontainers --dev
15+
```
16+
17+
## PNPM
18+
19+
```bash
20+
pnpm add testcontainers --save-dev
21+
```

0 commit comments

Comments
 (0)