@hellaweb3/wiremock-testcontainers-nodejs 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -366
- package/dist/index.cjs +1 -194
- package/dist/index.d.cts +77 -66
- package/dist/index.d.ts +77 -66
- package/dist/index.js +1 -192
- package/dist/no-docker.cjs +1 -0
- package/dist/no-docker.d.cts +45 -0
- package/dist/no-docker.d.ts +45 -0
- package/dist/no-docker.js +1 -0
- package/dist/runtime-6blQsklJ.cjs +1 -0
- package/dist/runtime-ChyDTLYb.js +1 -0
- package/package.json +31 -14
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/src/index.ts +0 -210
- package/src/sources.ts +0 -143
package/README.md
CHANGED
|
@@ -1,405 +1,162 @@
|
|
|
1
|
-
|
|
2
|
-
<div align="center">
|
|
1
|
+
# WireMock Testcontainers for Node.js
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
[](https://github.com/hella-web3/wiremock-testcontainers-nodejs/actions/workflows/main.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@hellaweb3/wiremock-testcontainers-nodejs)
|
|
5
|
+
[](https://www.npmjs.com/package/@hellaweb3/wiremock-testcontainers-nodejs)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Run [WireMock](https://wiremock.org/) in [Testcontainers](https://node.testcontainers.org/) with a
|
|
8
|
+
fluent TypeScript API modelled on the official
|
|
9
|
+
[Java module](https://github.com/wiremock/wiremock-testcontainers-java): load stubs from
|
|
10
|
+
directories, files, npm packages or inline JSON; reset state between tests without restarting;
|
|
11
|
+
verify calls through WireMock's request journal.
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
<img alt="Build Status" src="https://github.com/hella-web3/wiremock-testcontainers-nodejs/actions/workflows/main.yml/badge.svg" />
|
|
10
|
-
</a>
|
|
11
|
-
|
|
12
|
-
<a href="https://www.npmjs.com/package/@hellaweb3/wiremock-testcontainers-nodejs">
|
|
13
|
-
<img alt="npm version" src="https://img.shields.io/npm/v/%40hellaweb3%2Fwiremock-testcontainers-nodejs" />
|
|
14
|
-
</a>
|
|
15
|
-
|
|
16
|
-
<a href="https://www.npmjs.com/package/@hellaweb3/wiremock-testcontainers-nodejs">
|
|
17
|
-
<img alt="npm downloads" src="https://img.shields.io/npm/dm/%40hellaweb3%2Fwiremock-testcontainers-nodejs" />
|
|
18
|
-
</a>
|
|
19
|
-
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
## Description
|
|
23
|
-
|
|
24
|
-
`wiremock-testcontainers-nodejs` is a Typescript nodejs library that spins up
|
|
25
|
-
a [WireMock](https://wiremock.org/)
|
|
26
|
-
instance with [Testcontainers](https://node.testcontainers.org/). It provides a
|
|
27
|
-
fluent API to configure and start WireMock
|
|
28
|
-
containers from recorded WireMock directories, individual named mappings
|
|
29
|
-
(local files, npm packages, module-relative files or inline JSON) and static
|
|
30
|
-
files – an API modelled on the official
|
|
31
|
-
[Java module](https://github.com/wiremock/wiremock-testcontainers-java).
|
|
32
|
-
|
|
33
|
-
## Installation
|
|
13
|
+
## Install
|
|
34
14
|
|
|
35
15
|
```bash
|
|
36
|
-
|
|
16
|
+
npm i -D @hellaweb3/wiremock-testcontainers-nodejs testcontainers
|
|
37
17
|
```
|
|
38
18
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
**What you get:** a ~17 kB package – dual ESM (`dist/index.js`) and CJS
|
|
44
|
-
(`dist/index.cjs`) builds with matching declarations, `sideEffects: false`
|
|
45
|
-
for tree-shaking, `testcontainers` as the single runtime dependency (never
|
|
46
|
-
bundled), and the TypeScript source for go-to-definition.
|
|
47
|
-
|
|
48
|
-
**pnpm users:** pnpm >= 10 may report `Ignored build scripts: ssh2, protobufjs,
|
|
49
|
-
cpu-features`. These are transitive dependencies of `testcontainers`; the
|
|
50
|
-
scripts only build an *optional* native crypto binding for `ssh2`, which falls
|
|
51
|
-
back to pure JavaScript. It is safe to leave them ignored.
|
|
52
|
-
|
|
53
|
-
## Usage
|
|
54
|
-
|
|
55
|
-
### Basic Example
|
|
56
|
-
|
|
57
|
-
1. Record or hand-write your stubs in the standard WireMock layout, e.g.
|
|
58
|
-
`test/__mocks__/wiremock/mappings/*.json` and
|
|
59
|
-
`test/__mocks__/wiremock/__files/*.json`.
|
|
60
|
-
2. Start a `WiremockContainer` once per suite, point it at that directory and
|
|
61
|
-
use `rpcUrl` as the base URL of the API under test.
|
|
62
|
-
3. Stop the container when the suite finishes.
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest"; // or jest
|
|
66
|
-
import {
|
|
67
|
-
StartedWiremockContainer,
|
|
68
|
-
WiremockContainer,
|
|
69
|
-
} from "@hellaweb3/wiremock-testcontainers-nodejs";
|
|
70
|
-
|
|
71
|
-
describe("Cards API", () => {
|
|
72
|
-
let container: StartedWiremockContainer;
|
|
73
|
-
|
|
74
|
-
beforeAll(async () => {
|
|
75
|
-
container = await new WiremockContainer() // wiremock/wiremock:latest
|
|
76
|
-
.withMappings("./test/__mocks__/wiremock") // mappings/ + __files/
|
|
77
|
-
.start(); // waits for port 8080
|
|
78
|
-
}, 60_000); // image pull can be slow
|
|
79
|
-
|
|
80
|
-
afterAll(async () => {
|
|
81
|
-
await container.stop();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("serves the recorded GET /cards stub", async () => {
|
|
85
|
-
const response = await fetch(`${container.rpcUrl}/cards`);
|
|
86
|
-
expect(response.status).toBe(200);
|
|
87
|
-
|
|
88
|
-
const body = await response.json();
|
|
89
|
-
expect(body.items).toHaveLength(6);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("exposes the WireMock admin API", async () => {
|
|
93
|
-
const response = await fetch(`${container.rpcUrl}/__admin/mappings`);
|
|
94
|
-
const { meta } = await response.json();
|
|
95
|
-
expect(meta.total).toBe(2);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
```
|
|
19
|
+
Node.js >= 22.22 and a [container runtime](https://node.testcontainers.org/supported-container-runtimes/).
|
|
20
|
+
ESM and CJS, fully typed, `testcontainers` is the only dependency. pnpm >= 10 may report
|
|
21
|
+
`Ignored build scripts: ssh2, …` – optional native bindings of `testcontainers`, safe to ignore.
|
|
99
22
|
|
|
100
|
-
|
|
101
|
-
builder method is available – for example to pin an image, name the container
|
|
102
|
-
or pass WireMock CLI flags:
|
|
23
|
+
## Quick start
|
|
103
24
|
|
|
104
25
|
```typescript
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
.withCommand(["--verbose", "--global-response-templating"])
|
|
108
|
-
.withMappings("./test/__mocks__/wiremock")
|
|
109
|
-
.start();
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### With Mappings and Files
|
|
113
|
-
|
|
114
|
-
WireMock uses a specific directory structure for mappings and static files. This
|
|
115
|
-
library makes it easy to mount these into the container.
|
|
116
|
-
|
|
117
|
-
**Project structure:**
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
test/
|
|
121
|
-
└── __mocks__/
|
|
122
|
-
└── wiremock/
|
|
123
|
-
├── mappings/
|
|
124
|
-
│ └── my-mapping.json
|
|
125
|
-
└── __files/
|
|
126
|
-
└── some-data.json
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
import { WiremockContainer } from "@hellaweb3/wiremock-testcontainers-nodejs";
|
|
131
|
-
|
|
132
|
-
const container = await new WiremockContainer()
|
|
133
|
-
.withMappings("./test/__mocks__/wiremock")
|
|
134
|
-
.start();
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Individual mappings and files
|
|
138
|
-
|
|
139
|
-
`withMapping(name, source)` registers one stub at `mappings/<name>.json` and
|
|
140
|
-
`withFiles(...files)` registers response bodies in `__files/` – no recorded
|
|
141
|
-
directory required. A mapping file holds one WireMock stub, or several under
|
|
142
|
-
`"mappings"`:
|
|
143
|
-
|
|
144
|
-
```json
|
|
145
|
-
{ "request": { "method": "GET", "url": "/health" }, "response": { "status": 200, "jsonBody": { "status": "UP" } } }
|
|
146
|
-
```
|
|
26
|
+
import { afterAll, afterEach, beforeAll, expect, it } from "vitest"; // or Jest
|
|
27
|
+
import { type StartedWiremockContainer, WiremockContainer } from "@hellaweb3/wiremock-testcontainers-nodejs";
|
|
147
28
|
|
|
148
|
-
|
|
29
|
+
let wiremock: StartedWiremockContainer;
|
|
149
30
|
|
|
150
|
-
|
|
31
|
+
beforeAll(async () => {
|
|
32
|
+
wiremock = await new WiremockContainer()
|
|
33
|
+
.withMappings("./test/__mocks__/wiremock") // mappings/ + __files/
|
|
34
|
+
.start();
|
|
35
|
+
await wiremock.waitUntilReady();
|
|
36
|
+
}, 60_000); // the first image pull can be slow
|
|
151
37
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
```
|
|
38
|
+
afterEach(() => wiremock.reset()); // pristine stubs, empty journal – no restart
|
|
39
|
+
afterAll(() => wiremock.stop());
|
|
155
40
|
|
|
156
|
-
|
|
41
|
+
it("serves GET /cards", async () => {
|
|
42
|
+
const response = await fetch(wiremock.getUrl("/cards"));
|
|
157
43
|
|
|
158
|
-
|
|
159
|
-
|
|
44
|
+
expect(response.status).toBe(200);
|
|
45
|
+
expect(await wiremock.countRequests({ method: "GET", url: "/cards" })).toBe(1);
|
|
46
|
+
});
|
|
160
47
|
```
|
|
161
48
|
|
|
162
|
-
|
|
49
|
+
## Registering stubs
|
|
163
50
|
|
|
164
51
|
```typescript
|
|
165
|
-
new WiremockContainer(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
fixtures.
|
|
170
|
-
|
|
52
|
+
new WiremockContainer("wiremock/wiremock:3.13.0") // default: wiremock/wiremock
|
|
53
|
+
.withMappings("./test/__mocks__/wiremock") // a recorded directory
|
|
54
|
+
.withMapping("health", "./fixtures/health.json")
|
|
55
|
+
.withMapping("ping", { json: { request: { url: "/ping" }, response: { status: 200, body: "pong" } } })
|
|
56
|
+
.withFiles("./fixtures/body.json", { file: "./logo.png", name: "img/logo.png" })
|
|
57
|
+
.withCommand(["--global-response-templating"]); // any Testcontainers builder method
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- **`withMappings(dir)`** copies `dir/mappings/` (required) and `dir/__files/` (optional).
|
|
61
|
+
- **`withMapping(name, source)`** registers one stub at `mappings/<name>.json`; `name` may
|
|
62
|
+
contain `/`. The file may hold one stub or `{ "mappings": [...] }`.
|
|
63
|
+
- **`withFiles(...sources)`** registers response bodies at `__files/<name>`, the base name unless
|
|
64
|
+
`name` is given. All or nothing.
|
|
65
|
+
|
|
66
|
+
| Source | Example |
|
|
67
|
+
|------------------------------------|----------------------------------------------------------------|
|
|
68
|
+
| Path (relative to cwd) or `file:` URL | `"./fixtures/a.json"`, `new URL("./a.json", import.meta.url)` |
|
|
69
|
+
| `{ file }` | `{ file: "./fixtures/a.json" }` |
|
|
70
|
+
| `{ package, file }` – any file of an installed package | `{ package: "@acme/fixtures", file: "wiremock/a.json" }` |
|
|
71
|
+
| `{ module, file }` – next to a module | `{ module: import.meta.url, file: "./a.json" }` (CJS: `__dirname`) |
|
|
72
|
+
| `{ json }` – mappings only | an object (serialised) or a string (copied verbatim) |
|
|
73
|
+
|
|
74
|
+
Registrations are validated before any image is pulled: sources must exist, mappings must be
|
|
75
|
+
WireMock stubs, and nothing may overwrite another registration or reuse a stub `id`.
|
|
76
|
+
|
|
77
|
+
## Test utilities
|
|
78
|
+
|
|
79
|
+
`start()` resolves to a `StartedWiremockContainer`:
|
|
80
|
+
|
|
81
|
+
| Member | Purpose |
|
|
82
|
+
|-------------------------------------------|-------------------------------------------------------------------------|
|
|
83
|
+
| `rpcUrl` | Base URL, e.g. `http://localhost:32768` |
|
|
84
|
+
| `getUrl(path?)` | `getUrl("cards?page=1")` → `<rpcUrl>/cards?page=1` |
|
|
85
|
+
| `getAdminUrl()` / `getMappingUrl()` | `<rpcUrl>/__admin` / `<rpcUrl>/__admin/mappings` (runtime stubs) |
|
|
86
|
+
| `isRunning()` | `true` if WireMock is healthy; never throws |
|
|
87
|
+
| `waitUntilReady({ timeout?, interval? })` | Polls until healthy (defaults: 30 s, every 250 ms) |
|
|
88
|
+
| `reset()` | Restore registered stubs and scenarios, clear the journal – no restart |
|
|
89
|
+
| `resetRequests()` | Clear the journal only |
|
|
90
|
+
| `countRequests(criteria)` | Number of matching requests since the last reset |
|
|
91
|
+
| `findRequests(criteria)` | The matching `RecordedRequest`s (url, method, headers, body, …) |
|
|
92
|
+
| `stop()`, `await using` | Stop the container |
|
|
93
|
+
|
|
94
|
+
`criteria` (`WiremockRequestCriteria`) uses WireMock's [request matching](https://wiremock.org/docs/request-matching/):
|
|
171
95
|
|
|
172
96
|
```typescript
|
|
173
|
-
|
|
97
|
+
const [request] = await wiremock.findRequests({
|
|
98
|
+
method: "POST",
|
|
99
|
+
urlPath: "/cards",
|
|
100
|
+
headers: { "Content-Type": { equalTo: "application/json" } },
|
|
101
|
+
});
|
|
102
|
+
expect(JSON.parse(request.body ?? "")).toMatchObject({ cardType: "virtual" });
|
|
174
103
|
```
|
|
175
104
|
|
|
176
|
-
|
|
177
|
-
|
|
105
|
+
Also exported: `WaitUntilReadyOptions`, and the source types `WiremockMappingSource`,
|
|
106
|
+
`WiremockStaticFile`, `WiremockFileSource`, `WiremockPath` and `WiremockStubMapping`.
|
|
178
107
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
```
|
|
108
|
+
**Tips:** start one container per suite and `reset()` between tests, which is far faster than
|
|
109
|
+
restarting; raise the `beforeAll` timeout for the first image pull; assert with
|
|
110
|
+
`countRequests()`/`findRequests()` – they verify what actually went over the wire.
|
|
183
111
|
|
|
184
|
-
|
|
112
|
+
## Without Docker (local development only)
|
|
185
113
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
});
|
|
190
|
-
```
|
|
114
|
+
No container runtime? With Java 11+, `@hellaweb3/wiremock-testcontainers-nodejs/no-docker`
|
|
115
|
+
serves every `WiremockContainer` from a local WireMock JVM. Tests stay unchanged: stubs, files
|
|
116
|
+
and `withCommand()` flags apply as in the container.
|
|
191
117
|
|
|
192
|
-
|
|
118
|
+
> [!WARNING]
|
|
119
|
+
> Never the default, never for CI/CD: it refuses to run when CI is detected (`CI`,
|
|
120
|
+
> `GITHUB_ACTIONS`, …) and warns on every start. Results can differ from the Docker image; run
|
|
121
|
+
> with Docker before merging.
|
|
193
122
|
|
|
194
|
-
```
|
|
195
|
-
|
|
123
|
+
```bash
|
|
124
|
+
npm i -D wiremock # bundles the WireMock JAR (optional peer dependency)
|
|
196
125
|
```
|
|
197
126
|
|
|
198
|
-
**Several stubs in one mapping** – any source may hold `{ "mappings": [...] }`:
|
|
199
|
-
|
|
200
127
|
```typescript
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
{ request: { url: "/hello" }, response: { status: 200, body: "Hello" } },
|
|
205
|
-
{ request: { url: "/bye" }, response: { status: 200, body: "Bye" } },
|
|
206
|
-
],
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
#### Static files
|
|
128
|
+
// test/no-docker.setup.ts
|
|
129
|
+
import { installNoDockerRuntime } from "@hellaweb3/wiremock-testcontainers-nodejs/no-docker";
|
|
130
|
+
installNoDockerRuntime();
|
|
212
131
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
`bodyFileName`:
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
new WiremockContainer().withFiles(
|
|
219
|
-
"./test/fixtures/body-cards.json", // → __files/body-cards.json
|
|
220
|
-
{ file: "./test/fixtures/logo.png", name: "images/logo.png" }, // → __files/images/logo.png
|
|
221
|
-
{ package: "@acme/api-fixtures", file: "wiremock/__files/user.json" }, // → __files/user.json
|
|
222
|
-
);
|
|
132
|
+
// vitest.config.ts – opt-in only
|
|
133
|
+
setupFiles: process.env.WIREMOCK_NO_DOCKER === "1" ? ["./test/no-docker.setup.ts"] : [],
|
|
223
134
|
```
|
|
224
135
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
136
|
+
Set `WIREMOCK_NO_DOCKER=1` from a `--no-docker` script flag – see
|
|
137
|
+
[`examples/scripts/test-e2e.mjs`](./examples/scripts/test-e2e.mjs), which supports
|
|
138
|
+
`npm test --no-docker`.
|
|
228
139
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
140
|
+
| Option (`installNoDockerRuntime`) | Environment | Default |
|
|
141
|
+
|-----------------------------------|------------------------------|------------------------------------|
|
|
142
|
+
| `jar` | `WIREMOCK_JAR` | the `wiremock` package's JAR |
|
|
143
|
+
| `java` | `WIREMOCK_JAVA`, `JAVA_HOME` | `java` |
|
|
144
|
+
| `startupTimeout` | – | `60_000` ms |
|
|
145
|
+
| `cacheDir` (`false` disables) | – | `<tmpdir>/wiremock-testcontainers` |
|
|
146
|
+
| `log` | – | `process.emitWarning` |
|
|
147
|
+
| `env` – for the CI check and defaults | – | `process.env` |
|
|
237
148
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
### `WiremockContainer`
|
|
247
|
-
|
|
248
|
-
- `constructor(image?: string)`: Create a new container. Defaults to
|
|
249
|
-
`wiremock/wiremock`.
|
|
250
|
-
- `withMappings(directory: string)`: Copies `mappings/` (required) and
|
|
251
|
-
`__files/` (optional) from the specified local directory into the container.
|
|
252
|
-
Throws immediately if `mappings/` does not exist, so a typo fails before any
|
|
253
|
-
image is pulled.
|
|
254
|
-
- `withMapping(name: string, source: WiremockMappingSource)`: Registers one stub
|
|
255
|
-
at `mappings/<name>.json` (`name` may contain `/`; `.json` is optional).
|
|
256
|
-
- `withFiles(...files: WiremockStaticFile[])`: Registers files at
|
|
257
|
-
`__files/<name>` – the base name unless an object source sets `name`. A call
|
|
258
|
-
registers all files or none.
|
|
259
|
-
- `start()`: Starts the container and returns a `StartedWiremockContainer`.
|
|
260
|
-
Runtime failures (no daemon, image pull denied, start-up timeout, name or
|
|
261
|
-
port conflicts) are propagated unchanged.
|
|
262
|
-
|
|
263
|
-
### `StartedWiremockContainer`
|
|
264
|
-
|
|
265
|
-
- `rpcUrl`: Returns the base URL of the running WireMock instance (e.g.,
|
|
266
|
-
`http://localhost:32768`).
|
|
267
|
-
- `stop()`: Stops the container (inherited from Testcontainers).
|
|
268
|
-
- `[Symbol.asyncDispose]`: `await using container = await new WiremockContainer().start();`
|
|
269
|
-
stops the container automatically when the scope exits (TypeScript 5.2+).
|
|
270
|
-
|
|
271
|
-
## Best Practices
|
|
272
|
-
|
|
273
|
-
1. **Test Isolation**: Start a new container for each test suite (or even each
|
|
274
|
-
test if performance allows) to ensure a clean state.
|
|
275
|
-
2. **Mapping Organization**: Keep your mappings organized in a dedicated
|
|
276
|
-
directory structure that mirrors your API endpoints.
|
|
277
|
-
3. **Timeouts**: Docker container startup can sometimes exceed the default test
|
|
278
|
-
runner timeout (e.g. 5 s in Jest, 10 s in Vitest). Always set a higher timeout for
|
|
279
|
-
`beforeAll` hooks that start containers.
|
|
280
|
-
4. **Resource Management**: Always ensure `container.stop()` is called in an
|
|
281
|
-
`afterAll` or `afterEach` block to prevent orphaned containers.
|
|
282
|
-
|
|
283
|
-
## Development
|
|
284
|
-
|
|
285
|
-
Tooling: [Vitest](https://vitest.dev/) (tests + v8 coverage),
|
|
286
|
-
[oxlint](https://oxc.rs/docs/guide/usage/linter) (lint), `tsc` (typecheck)
|
|
287
|
-
and [tsdown](https://tsdown.dev/) (build – rolldown + oxc, emitting
|
|
288
|
-
declarations natively via `isolatedDeclarations` in `tsconfig.build.json`).
|
|
289
|
-
Node version: see `.nvmrc`.
|
|
290
|
-
|
|
291
|
-
### Scripts
|
|
292
|
-
|
|
293
|
-
| Command | What it does | Needs Docker |
|
|
294
|
-
|----------------------|--------------------------------------------------------------------------|--------------|
|
|
295
|
-
| `pnpm build` | ESM + CJS + declarations into `dist/`, then `publint` + `attw` checks | No |
|
|
296
|
-
| `pnpm typecheck` | `tsc --noEmit` over `src/` and `test/` | No |
|
|
297
|
-
| `pnpm lint` | `oxlint --deny-warnings` with the rules in `.oxlintrc.json` | No |
|
|
298
|
-
| `pnpm test:unit` | `test/unit/**` – container wrapper logic, registration API and fixture integrity checks | No |
|
|
299
|
-
| `pnpm test:e2e` | `test/index.test.ts` – a real WireMock container serving the fixtures | **Yes** |
|
|
300
|
-
| `pnpm test` | Both suites, no coverage (fast local loop) | **Yes** |
|
|
301
|
-
| `pnpm test:coverage` | Both suites with coverage of `src/`, thresholds enforced | **Yes** |
|
|
302
|
-
| `pnpm check` | `build` + `typecheck` + `lint` + `test:coverage` – the full CI gate | **Yes** |
|
|
303
|
-
|
|
304
|
-
Append `--coverage` to any test script to collect coverage for that run, e.g.
|
|
305
|
-
`pnpm test:unit --coverage`. Coverage thresholds are **95 %** for statements,
|
|
306
|
-
branches, functions and lines; the unit suite alone currently reaches 100 %
|
|
307
|
-
and completes in well under two seconds of test time.
|
|
308
|
-
|
|
309
|
-
### Running the E2E suite in containerised environments
|
|
310
|
-
|
|
311
|
-
The E2E suite starts a real container through Testcontainers, so the test
|
|
312
|
-
process needs a container runtime it can talk to. Without one, `pnpm test:e2e`,
|
|
313
|
-
`pnpm test` and `pnpm check` fail in the E2E suite with:
|
|
149
|
+
- **Speed:** a C1-only JIT and a class-data archive per JAR and Java in `cacheDir`. The first run
|
|
150
|
+
records it (a slower `stop()`); later runs boot ~2× faster and stop instantly. `JAVA_OPTS`
|
|
151
|
+
override the JVM flags.
|
|
152
|
+
- **Differences:** WireMock listens on `127.0.0.1`; `exec()`, networks and copying after start
|
|
153
|
+
throw; leftover JVMs are killed on exit.
|
|
154
|
+
- **Also exported:** `detectCI(env?)` – the CI variable set, if any; `isNoDockerRequested(env?)` –
|
|
155
|
+
whether `NO_DOCKER_ENV` (`WIREMOCK_NO_DOCKER`) is `1` or `true`.
|
|
314
156
|
|
|
315
|
-
|
|
316
|
-
Could not find a working container runtime strategy
|
|
317
|
-
```
|
|
157
|
+
## More
|
|
318
158
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
```bash
|
|
323
|
-
pnpm build && pnpm typecheck && pnpm lint && pnpm test:unit --coverage
|
|
324
|
-
```
|
|
159
|
+
- [`examples/`](./examples) – a standalone project using the package via `npm link`.
|
|
160
|
+
- [CONTRIBUTING.md](./CONTRIBUTING.md) – scripts, CI and tests.
|
|
325
161
|
|
|
326
|
-
|
|
327
|
-
environment can provide:
|
|
328
|
-
|
|
329
|
-
| Environment | How to enable E2E |
|
|
330
|
-
|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
331
|
-
| GitHub Codespaces / VS Code Dev Containers | Use the provided `.devcontainer/devcontainer.json` – it adds the `docker-in-docker` feature, so a daemon runs inside the dev container. |
|
|
332
|
-
| Dev container with the host socket mounted | Add the `docker-outside-of-docker` feature (or mount `/var/run/docker.sock`). Set `TESTCONTAINERS_HOST_OVERRIDE=host.docker.internal` if port lookups fail. |
|
|
333
|
-
| Remote or rootless daemon | `DOCKER_HOST=tcp://host:2375` (or `unix:///path/to/docker.sock`). |
|
|
334
|
-
| Podman | `DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock` and `TESTCONTAINERS_RYUK_DISABLED=true` (or run Ryuk privileged). |
|
|
335
|
-
| No runtime can be installed (locked-down sandbox) | [Testcontainers Cloud](https://testcontainers.com/cloud/): run the agent and export `TC_CLOUD_TOKEN`; containers start remotely, tests run locally. |
|
|
336
|
-
|
|
337
|
-
Sandboxes that have **no runtime binary and no socket at all** (as is the case
|
|
338
|
-
for some hosted dev VMs) cannot run the E2E suite; the suite states this in its
|
|
339
|
-
header comment and `pnpm test:unit` is the supported loop there.
|
|
340
|
-
|
|
341
|
-
CI (`.github/workflows/main.yml`) runs build, typecheck, lint, unit tests
|
|
342
|
-
(with coverage) and E2E tests as separate steps on `ubuntu-latest`, which
|
|
343
|
-
ships with Docker, for every active Node LTS line.
|
|
344
|
-
|
|
345
|
-
### Supply-chain controls
|
|
346
|
-
|
|
347
|
-
- `pnpm install --frozen-lockfile` everywhere; the lockfile is the source of truth.
|
|
348
|
-
- `pnpm-workspace.yaml` allow-lists the only packages permitted to run install
|
|
349
|
-
scripts (`ssh2`, `cpu-features`, `protobufjs` – all transitive via
|
|
350
|
-
`testcontainers`) and sets `minimumReleaseAge: 1440` so a version must be at
|
|
351
|
-
least 24 h old before it can be resolved.
|
|
352
|
-
- CI runs `pnpm audit --prod --audit-level=high` on every push and PR;
|
|
353
|
-
Dependabot (`.github/dependabot.yml`) proposes weekly updates with a 3-day
|
|
354
|
-
cooldown, grouping dev tooling and leaving `testcontainers` bumps individual.
|
|
355
|
-
- `pnpm build` runs [publint](https://publint.dev/) and
|
|
356
|
-
[Are the types wrong?](https://arethetypeswrong.github.io/) against the
|
|
357
|
-
emitted package; `size.yml` fails a PR if the tarball exceeds 25 kB.
|
|
358
|
-
- Releases publish with npm provenance (`--provenance`, OIDC) after a
|
|
359
|
-
Docker-free verify step.
|
|
360
|
-
|
|
361
|
-
### Fixtures and schema-based assertions
|
|
362
|
-
|
|
363
|
-
The recorded WireMock session lives in `test/__mocks__/wiremock`:
|
|
364
|
-
|
|
365
|
-
- `mappings/*.json` – one stub per endpoint (`request.url`, `response.status`,
|
|
366
|
-
`response.headers`, `response.bodyFileName`).
|
|
367
|
-
- `__files/*.json` – the response bodies referenced by the mappings.
|
|
368
|
-
|
|
369
|
-
`test/helpers/fixtures.ts` loads these from disk and declares the TypeScript
|
|
370
|
-
shapes of every JSON payload. `test/helpers/assertions.ts` declares a
|
|
371
|
-
`Schema<T>` per payload – stub mappings, the admin API response and each
|
|
372
|
-
recorded body. The compiler requires a schema to cover **every** field of
|
|
373
|
-
`T`; `expectObject` then asserts each field's shape, its recorded value and
|
|
374
|
-
the exact key set (`partialOf` relaxes the key set for third-party shapes).
|
|
375
|
-
|
|
376
|
-
The E2E suite runs a mapping-driven contract test for every file in
|
|
377
|
-
`mappings/` (status, headers and full JSON body), so adding a new recorded
|
|
378
|
-
mapping automatically puts it under test. Endpoint-specific suites add
|
|
379
|
-
schema assertions, which the unit suite also runs against the fixture files
|
|
380
|
-
themselves to catch drift early.
|
|
381
|
-
|
|
382
|
-
Negative cases are hand-written stubs alongside the recorded ones:
|
|
383
|
-
|
|
384
|
-
- `mapping-cards-bad-request-400.json` – `GET /cards?page=0` → 400 with a
|
|
385
|
-
validation error envelope.
|
|
386
|
-
- `mapping-account-balance-server-error-500.json` – `GET /account/balance`
|
|
387
|
-
→ 500 **only** when the request carries `X-Mock-Scenario: server-error`.
|
|
388
|
-
It sets `"priority": 1` so it wins over the recorded 200 stub for the same
|
|
389
|
-
URL; without the header the 200 stub is still served. This is the standard
|
|
390
|
-
WireMock pattern for simulating outages on demand.
|
|
391
|
-
|
|
392
|
-
Unmatched requests (unknown path, wrong method) get WireMock's default 404.
|
|
393
|
-
|
|
394
|
-
`test/__mocks__/standalone` holds loose fixtures for `withMapping()` and
|
|
395
|
-
`withFiles()`. Their unit tests need no Docker: `test/helpers/container.ts`
|
|
396
|
-
reads the tar archive Testcontainers would upload and asserts exactly which
|
|
397
|
-
files land where.
|
|
398
|
-
|
|
399
|
-
## Maintainers
|
|
400
|
-
|
|
401
|
-
Maintained by [Hella Labs](https://hellaweb3.com/).
|
|
402
|
-
|
|
403
|
-
## License
|
|
404
|
-
|
|
405
|
-
MIT
|
|
162
|
+
Maintained by [Hella Labs](https://hellaweb3.com/). [MIT](./LICENSE) licensed.
|