@hellaweb3/wiremock-testcontainers-nodejs 0.1.3 → 0.2.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/dist/index.d.cts CHANGED
@@ -1,56 +1,113 @@
1
- import { AbstractStartedContainer, StartedTestContainer, GenericContainer } from 'testcontainers';
2
-
1
+ import { AbstractStartedContainer, GenericContainer, StartedTestContainer } from "testcontainers";
2
+ /** A path (relative to the working directory) or a `file:` URL. */
3
+ type WiremockPath = string | URL;
3
4
  /**
4
- * A Testcontainer for Wiremock.
5
+ * A fixture file: a local path or `file:` URL, `{ file }`, a file inside an installed npm
6
+ * package `{ package, file }` (its `exports` are ignored), or a file next to a module
7
+ * `{ module: import.meta.url | __filename | __dirname, file }`.
8
+ */
9
+ type WiremockFileSource = WiremockPath | {
10
+ readonly file: WiremockPath;
11
+ } | {
12
+ readonly package: string;
13
+ readonly file: string;
14
+ } | {
15
+ readonly module: WiremockPath;
16
+ readonly file: string;
17
+ };
18
+ /** A WireMock stub; fields besides `request` and `response` are passed through. */
19
+ interface WiremockStubMapping {
20
+ readonly request: object;
21
+ readonly response: object;
22
+ readonly [field: string]: unknown;
23
+ }
24
+ /** A file source, or inline JSON: a string, a stub or `{ mappings: [...] }`. */
25
+ type WiremockMappingSource = WiremockFileSource | {
26
+ readonly json: string | WiremockStubMapping | {
27
+ readonly mappings: readonly WiremockStubMapping[];
28
+ };
29
+ };
30
+ /** A file source; object forms may set `name`, the path below `__files/` (default: the base name). */
31
+ type WiremockStaticFile = WiremockPath | (Exclude<WiremockFileSource, WiremockPath> & {
32
+ readonly name?: string;
33
+ });
34
+ /**
35
+ * A Testcontainer for Wiremock. Stubs are registered with {@link withMappings} (a directory),
36
+ * {@link withMapping} (one named stub) and {@link withFiles} (response bodies), in any
37
+ * combination. Registrations are validated immediately and may not overwrite one another.
5
38
  *
6
39
  * @example
7
40
  * ```typescript
8
41
  * const container = await new WiremockContainer().start();
9
42
  * ```
10
43
  */
11
- declare class WiremockContainer extends GenericContainer {
12
- /**
13
- * Creates a new WiremockContainer.
14
- * @example
15
- * ```typescript
16
- * const container = await new WiremockContainer().start();
17
- * ```
18
- * @param image The docker image to use. Defaults to "wiremock/wiremock".
19
- */
20
- constructor(image?: string);
21
- /**
22
- * Adds mappings to the Wiremock container.
23
- * @example
24
- * ```typescript
25
- * const container = await new WiremockContainer()
26
- * .withMappings("./test/__mocks__/wiremock")
27
- * .start();
28
- * ```
29
- * @param directory The directory containing the mappings and __files.
30
- */
31
- withMappings(directory: string): this;
32
- /**
33
- * Starts the container and returns a {@link StartedWiremockContainer}.
34
- * @returns A promise that resolves to the started container.
35
- */
36
- start(): Promise<StartedWiremockContainer>;
44
+ export declare class WiremockContainer extends GenericContainer {
45
+ #private;
46
+ /**
47
+ * Creates a new WiremockContainer.
48
+ * @example
49
+ * ```typescript
50
+ * const container = await new WiremockContainer().start();
51
+ * ```
52
+ * @param image The docker image to use. Defaults to "wiremock/wiremock".
53
+ */
54
+ constructor(image?: string);
55
+ /**
56
+ * Adds mappings to the Wiremock container.
57
+ * @example
58
+ * ```typescript
59
+ * const container = await new WiremockContainer()
60
+ * .withMappings("./test/__mocks__/wiremock")
61
+ * .start();
62
+ * ```
63
+ * @param directory The directory containing `mappings/` and, optionally, `__files/`.
64
+ * @throws If `mappings/` is not a directory in `directory`, or a file would overwrite an earlier registration.
65
+ */
66
+ withMappings(directory: string): this;
67
+ /**
68
+ * Registers one stub at `mappings/<name>.json`, validated and copied byte-for-byte.
69
+ * @example
70
+ * ```typescript
71
+ * new WiremockContainer()
72
+ * .withMapping("cards", "./test/fixtures/cards.json")
73
+ * .withMapping("user", { package: "@acme/fixtures", file: "wiremock/user.json" })
74
+ * .withMapping("balance", { module: import.meta.url, file: "./balance.json" })
75
+ * .withMapping("ping", { json: { request: { url: "/ping" }, response: { status: 200 } } });
76
+ * ```
77
+ * @param name File name below `mappings/`, may contain `/`; `.json` is appended unless present.
78
+ * @throws If the name or source is invalid, the source is not a WireMock mapping, or it would overwrite an earlier registration.
79
+ */
80
+ withMapping(name: string, source: WiremockMappingSource): this;
81
+ /**
82
+ * Registers response bodies at `__files/<name>` (default: the base name), copied as-is.
83
+ * @example
84
+ * ```typescript
85
+ * new WiremockContainer().withFiles("./test/fixtures/body.json", { file: "./logo.png", name: "img/logo.png" });
86
+ * ```
87
+ * @throws If a source or name is invalid, or a file would overwrite an earlier registration; nothing is registered then.
88
+ */
89
+ withFiles(...files: WiremockStaticFile[]): this;
90
+ /**
91
+ * Starts the container and returns a {@link StartedWiremockContainer}.
92
+ * @returns A promise that resolves to the started container.
93
+ */
94
+ override start(): Promise<StartedWiremockContainer>;
37
95
  }
38
96
  /**
39
97
  * A started Wiremock container with helper methods for interacting with the node.
40
98
  */
41
- declare class StartedWiremockContainer extends AbstractStartedContainer {
42
- private readonly _rpcUrl;
43
- /**
44
- * Creates a new StartedWiremockContainer.
45
- * @param startedTestContainer The underlying TestContainer.
46
- * @param url The URL of the started container.
47
- */
48
- constructor(startedTestContainer: StartedTestContainer, url: string);
49
- /**
50
- * Gets the URL of the Wiremock node.
51
- */
52
- get rpcUrl(): string;
99
+ export declare class StartedWiremockContainer extends AbstractStartedContainer {
100
+ #private;
101
+ /**
102
+ * Creates a new StartedWiremockContainer.
103
+ * @param startedTestContainer The underlying TestContainer.
104
+ * @param url The URL of the started container.
105
+ */
106
+ constructor(startedTestContainer: StartedTestContainer, url: string);
107
+ /**
108
+ * Gets the URL of the Wiremock node.
109
+ */
110
+ get rpcUrl(): string;
53
111
  }
54
-
55
- export { StartedWiremockContainer, WiremockContainer };
56
- //# sourceMappingURL=index.d.cts.map
112
+ export type { WiremockFileSource, WiremockMappingSource, WiremockPath, WiremockStaticFile, WiremockStubMapping };
113
+ //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sources":["../src/index.ts"],"sourcesContent":["import {\n AbstractStartedContainer,\n GenericContainer,\n StartedTestContainer,\n Wait,\n} from \"testcontainers\";\n\n/**\n * A Testcontainer for Wiremock.\n *\n * @example\n * ```typescript\n * const container = await new WiremockContainer().start();\n * ```\n */\nexport class WiremockContainer extends GenericContainer {\n /**\n * Creates a new WiremockContainer.\n * @example\n * ```typescript\n * const container = await new WiremockContainer().start();\n * ```\n * @param image The docker image to use. Defaults to \"wiremock/wiremock\".\n */\n constructor(image: string = \"wiremock/wiremock\") {\n super(image);\n this.withExposedPorts(8080);\n this.withWaitStrategy(Wait.forListeningPorts());\n }\n\n /**\n * Adds mappings to the Wiremock container.\n * @example\n * ```typescript\n * const container = await new WiremockContainer()\n * .withMappings(\"./test/__mocks__/wiremock\")\n * .start();\n * ```\n * @param directory The directory containing the mappings and __files.\n */\n public withMappings(directory: string) {\n this.withCopyDirectoriesToContainer([{\n source: `${directory}/__files`,\n target: \"/home/wiremock/__files\",\n }]);\n this.withCopyDirectoriesToContainer([{\n source: `${directory}/mappings`,\n target: \"/home/wiremock/mappings\",\n }]);\n\n return this;\n }\n\n /**\n * Starts the container and returns a {@link StartedWiremockContainer}.\n * @returns A promise that resolves to the started container.\n */\n public override async start(): Promise<StartedWiremockContainer> {\n const startedContainer = await super.start();\n return new StartedWiremockContainer(\n startedContainer,\n `http://${startedContainer.getHost()}:${startedContainer.getMappedPort(8080)}`,\n );\n }\n}\n\n/**\n * A started Wiremock container with helper methods for interacting with the node.\n */\nexport class StartedWiremockContainer extends AbstractStartedContainer {\n private readonly _rpcUrl;\n\n /**\n * Creates a new StartedWiremockContainer.\n * @param startedTestContainer The underlying TestContainer.\n * @param url The URL of the started container.\n */\n constructor(startedTestContainer: StartedTestContainer, url: string) {\n super(startedTestContainer);\n this._rpcUrl = url;\n }\n\n /**\n * Gets the URL of the Wiremock node.\n */\n get rpcUrl() {\n return this._rpcUrl;\n }\n}\n"],"names":[],"mappings":";;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,iBAAA,SAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,OAAA,CAAA,wBAAA;AACA;AACA;AACA;AACA;AACO,cAAA,wBAAA,SAAA,wBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,sCAAA,oBAAA;AACA;AACA;AACA;AACA;AACA;;;;"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/sources.ts","../src/index.ts"],"mappings":";;KAMY,wBAAwB;;;;;;KAOxB,qBACR;WACW,MAAM;;WACN;WAA0B;;WAC1B,QAAQ;WAAuB;;;UAG7B;WACN;WACA;;;;KAKC,wBACR;WACW,eAAe;aAAiC,mBAAmB;;;;KAGtE,qBAAqB,gBAAgB,QAAQ,oBAAoB;WAA2B;;;;;;;;;;;;qBCoB3F,0BAA0B;;;;;;;;;;EAcrC,YAAY;;;;;;;;;;;;EAiBZ,aAAoB;;;;;;;;;;;;;;EAmCpB,YAAmB,cAAc,QAAQ;;;;;;;;;EAqBzC,aAAoB,OAAO;;;;;WAgBL,SAAS,QAAQ;;;;;qBAmC5B,iCAAiC;;;;;;;EAQ5C,YAAY,sBAAsB,sBAAsB;;;;MAQpD"}
package/dist/index.d.ts CHANGED
@@ -1,56 +1,113 @@
1
- import { AbstractStartedContainer, StartedTestContainer, GenericContainer } from 'testcontainers';
2
-
1
+ import { AbstractStartedContainer, GenericContainer, StartedTestContainer } from "testcontainers";
2
+ /** A path (relative to the working directory) or a `file:` URL. */
3
+ type WiremockPath = string | URL;
3
4
  /**
4
- * A Testcontainer for Wiremock.
5
+ * A fixture file: a local path or `file:` URL, `{ file }`, a file inside an installed npm
6
+ * package `{ package, file }` (its `exports` are ignored), or a file next to a module
7
+ * `{ module: import.meta.url | __filename | __dirname, file }`.
8
+ */
9
+ type WiremockFileSource = WiremockPath | {
10
+ readonly file: WiremockPath;
11
+ } | {
12
+ readonly package: string;
13
+ readonly file: string;
14
+ } | {
15
+ readonly module: WiremockPath;
16
+ readonly file: string;
17
+ };
18
+ /** A WireMock stub; fields besides `request` and `response` are passed through. */
19
+ interface WiremockStubMapping {
20
+ readonly request: object;
21
+ readonly response: object;
22
+ readonly [field: string]: unknown;
23
+ }
24
+ /** A file source, or inline JSON: a string, a stub or `{ mappings: [...] }`. */
25
+ type WiremockMappingSource = WiremockFileSource | {
26
+ readonly json: string | WiremockStubMapping | {
27
+ readonly mappings: readonly WiremockStubMapping[];
28
+ };
29
+ };
30
+ /** A file source; object forms may set `name`, the path below `__files/` (default: the base name). */
31
+ type WiremockStaticFile = WiremockPath | (Exclude<WiremockFileSource, WiremockPath> & {
32
+ readonly name?: string;
33
+ });
34
+ /**
35
+ * A Testcontainer for Wiremock. Stubs are registered with {@link withMappings} (a directory),
36
+ * {@link withMapping} (one named stub) and {@link withFiles} (response bodies), in any
37
+ * combination. Registrations are validated immediately and may not overwrite one another.
5
38
  *
6
39
  * @example
7
40
  * ```typescript
8
41
  * const container = await new WiremockContainer().start();
9
42
  * ```
10
43
  */
11
- declare class WiremockContainer extends GenericContainer {
12
- /**
13
- * Creates a new WiremockContainer.
14
- * @example
15
- * ```typescript
16
- * const container = await new WiremockContainer().start();
17
- * ```
18
- * @param image The docker image to use. Defaults to "wiremock/wiremock".
19
- */
20
- constructor(image?: string);
21
- /**
22
- * Adds mappings to the Wiremock container.
23
- * @example
24
- * ```typescript
25
- * const container = await new WiremockContainer()
26
- * .withMappings("./test/__mocks__/wiremock")
27
- * .start();
28
- * ```
29
- * @param directory The directory containing the mappings and __files.
30
- */
31
- withMappings(directory: string): this;
32
- /**
33
- * Starts the container and returns a {@link StartedWiremockContainer}.
34
- * @returns A promise that resolves to the started container.
35
- */
36
- start(): Promise<StartedWiremockContainer>;
44
+ export declare class WiremockContainer extends GenericContainer {
45
+ #private;
46
+ /**
47
+ * Creates a new WiremockContainer.
48
+ * @example
49
+ * ```typescript
50
+ * const container = await new WiremockContainer().start();
51
+ * ```
52
+ * @param image The docker image to use. Defaults to "wiremock/wiremock".
53
+ */
54
+ constructor(image?: string);
55
+ /**
56
+ * Adds mappings to the Wiremock container.
57
+ * @example
58
+ * ```typescript
59
+ * const container = await new WiremockContainer()
60
+ * .withMappings("./test/__mocks__/wiremock")
61
+ * .start();
62
+ * ```
63
+ * @param directory The directory containing `mappings/` and, optionally, `__files/`.
64
+ * @throws If `mappings/` is not a directory in `directory`, or a file would overwrite an earlier registration.
65
+ */
66
+ withMappings(directory: string): this;
67
+ /**
68
+ * Registers one stub at `mappings/<name>.json`, validated and copied byte-for-byte.
69
+ * @example
70
+ * ```typescript
71
+ * new WiremockContainer()
72
+ * .withMapping("cards", "./test/fixtures/cards.json")
73
+ * .withMapping("user", { package: "@acme/fixtures", file: "wiremock/user.json" })
74
+ * .withMapping("balance", { module: import.meta.url, file: "./balance.json" })
75
+ * .withMapping("ping", { json: { request: { url: "/ping" }, response: { status: 200 } } });
76
+ * ```
77
+ * @param name File name below `mappings/`, may contain `/`; `.json` is appended unless present.
78
+ * @throws If the name or source is invalid, the source is not a WireMock mapping, or it would overwrite an earlier registration.
79
+ */
80
+ withMapping(name: string, source: WiremockMappingSource): this;
81
+ /**
82
+ * Registers response bodies at `__files/<name>` (default: the base name), copied as-is.
83
+ * @example
84
+ * ```typescript
85
+ * new WiremockContainer().withFiles("./test/fixtures/body.json", { file: "./logo.png", name: "img/logo.png" });
86
+ * ```
87
+ * @throws If a source or name is invalid, or a file would overwrite an earlier registration; nothing is registered then.
88
+ */
89
+ withFiles(...files: WiremockStaticFile[]): this;
90
+ /**
91
+ * Starts the container and returns a {@link StartedWiremockContainer}.
92
+ * @returns A promise that resolves to the started container.
93
+ */
94
+ override start(): Promise<StartedWiremockContainer>;
37
95
  }
38
96
  /**
39
97
  * A started Wiremock container with helper methods for interacting with the node.
40
98
  */
41
- declare class StartedWiremockContainer extends AbstractStartedContainer {
42
- private readonly _rpcUrl;
43
- /**
44
- * Creates a new StartedWiremockContainer.
45
- * @param startedTestContainer The underlying TestContainer.
46
- * @param url The URL of the started container.
47
- */
48
- constructor(startedTestContainer: StartedTestContainer, url: string);
49
- /**
50
- * Gets the URL of the Wiremock node.
51
- */
52
- get rpcUrl(): string;
99
+ export declare class StartedWiremockContainer extends AbstractStartedContainer {
100
+ #private;
101
+ /**
102
+ * Creates a new StartedWiremockContainer.
103
+ * @param startedTestContainer The underlying TestContainer.
104
+ * @param url The URL of the started container.
105
+ */
106
+ constructor(startedTestContainer: StartedTestContainer, url: string);
107
+ /**
108
+ * Gets the URL of the Wiremock node.
109
+ */
110
+ get rpcUrl(): string;
53
111
  }
54
-
55
- export { StartedWiremockContainer, WiremockContainer };
56
- //# sourceMappingURL=index.d.ts.map
112
+ export type { WiremockFileSource, WiremockMappingSource, WiremockPath, WiremockStaticFile, WiremockStubMapping };
113
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sources":["../src/index.ts"],"sourcesContent":["import {\n AbstractStartedContainer,\n GenericContainer,\n StartedTestContainer,\n Wait,\n} from \"testcontainers\";\n\n/**\n * A Testcontainer for Wiremock.\n *\n * @example\n * ```typescript\n * const container = await new WiremockContainer().start();\n * ```\n */\nexport class WiremockContainer extends GenericContainer {\n /**\n * Creates a new WiremockContainer.\n * @example\n * ```typescript\n * const container = await new WiremockContainer().start();\n * ```\n * @param image The docker image to use. Defaults to \"wiremock/wiremock\".\n */\n constructor(image: string = \"wiremock/wiremock\") {\n super(image);\n this.withExposedPorts(8080);\n this.withWaitStrategy(Wait.forListeningPorts());\n }\n\n /**\n * Adds mappings to the Wiremock container.\n * @example\n * ```typescript\n * const container = await new WiremockContainer()\n * .withMappings(\"./test/__mocks__/wiremock\")\n * .start();\n * ```\n * @param directory The directory containing the mappings and __files.\n */\n public withMappings(directory: string) {\n this.withCopyDirectoriesToContainer([{\n source: `${directory}/__files`,\n target: \"/home/wiremock/__files\",\n }]);\n this.withCopyDirectoriesToContainer([{\n source: `${directory}/mappings`,\n target: \"/home/wiremock/mappings\",\n }]);\n\n return this;\n }\n\n /**\n * Starts the container and returns a {@link StartedWiremockContainer}.\n * @returns A promise that resolves to the started container.\n */\n public override async start(): Promise<StartedWiremockContainer> {\n const startedContainer = await super.start();\n return new StartedWiremockContainer(\n startedContainer,\n `http://${startedContainer.getHost()}:${startedContainer.getMappedPort(8080)}`,\n );\n }\n}\n\n/**\n * A started Wiremock container with helper methods for interacting with the node.\n */\nexport class StartedWiremockContainer extends AbstractStartedContainer {\n private readonly _rpcUrl;\n\n /**\n * Creates a new StartedWiremockContainer.\n * @param startedTestContainer The underlying TestContainer.\n * @param url The URL of the started container.\n */\n constructor(startedTestContainer: StartedTestContainer, url: string) {\n super(startedTestContainer);\n this._rpcUrl = url;\n }\n\n /**\n * Gets the URL of the Wiremock node.\n */\n get rpcUrl() {\n return this._rpcUrl;\n }\n}\n"],"names":[],"mappings":";;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,iBAAA,SAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,OAAA,CAAA,wBAAA;AACA;AACA;AACA;AACA;AACO,cAAA,wBAAA,SAAA,wBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,sCAAA,oBAAA;AACA;AACA;AACA;AACA;AACA;;;;"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/sources.ts","../src/index.ts"],"mappings":";;KAMY,wBAAwB;;;;;;KAOxB,qBACR;WACW,MAAM;;WACN;WAA0B;;WAC1B,QAAQ;WAAuB;;;UAG7B;WACN;WACA;;;;KAKC,wBACR;WACW,eAAe;aAAiC,mBAAmB;;;;KAGtE,qBAAqB,gBAAgB,QAAQ,oBAAoB;WAA2B;;;;;;;;;;;;qBCoB3F,0BAA0B;;;;;;;;;;EAcrC,YAAY;;;;;;;;;;;;EAiBZ,aAAoB;;;;;;;;;;;;;;EAmCpB,YAAmB,cAAc,QAAQ;;;;;;;;;EAqBzC,aAAoB,OAAO;;;;;WAgBL,SAAS,QAAQ;;;;;qBAmC5B,iCAAiC;;;;;;;EAQ5C,YAAY,sBAAsB,sBAAsB;;;;MAQpD"}
package/dist/index.js CHANGED
@@ -1,73 +1,192 @@
1
- import { GenericContainer, Wait, AbstractStartedContainer } from 'testcontainers';
2
-
3
- /**
4
- * A Testcontainer for Wiremock.
5
- *
6
- * @example
7
- * ```typescript
8
- * const container = await new WiremockContainer().start();
9
- * ```
10
- */ class WiremockContainer extends GenericContainer {
11
- /**
12
- * Creates a new WiremockContainer.
13
- * @example
14
- * ```typescript
15
- * const container = await new WiremockContainer().start();
16
- * ```
17
- * @param image The docker image to use. Defaults to "wiremock/wiremock".
18
- */ constructor(image = "wiremock/wiremock"){
19
- super(image);
20
- this.withExposedPorts(8080);
21
- this.withWaitStrategy(Wait.forListeningPorts());
22
- }
23
- /**
24
- * Adds mappings to the Wiremock container.
25
- * @example
26
- * ```typescript
27
- * const container = await new WiremockContainer()
28
- * .withMappings("./test/__mocks__/wiremock")
29
- * .start();
30
- * ```
31
- * @param directory The directory containing the mappings and __files.
32
- */ withMappings(directory) {
33
- this.withCopyDirectoriesToContainer([
34
- {
35
- source: `${directory}/__files`,
36
- target: "/home/wiremock/__files"
37
- }
38
- ]);
39
- this.withCopyDirectoriesToContainer([
40
- {
41
- source: `${directory}/mappings`,
42
- target: "/home/wiremock/mappings"
43
- }
44
- ]);
45
- return this;
46
- }
47
- /**
48
- * Starts the container and returns a {@link StartedWiremockContainer}.
49
- * @returns A promise that resolves to the started container.
50
- */ async start() {
51
- const startedContainer = await super.start();
52
- return new StartedWiremockContainer(startedContainer, `http://${startedContainer.getHost()}:${startedContainer.getMappedPort(8080)}`);
53
- }
1
+ import { createRequire } from "node:module";
2
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
+ import { basename, dirname, join, posix, relative, resolve, sep } from "node:path";
4
+ import { AbstractStartedContainer, GenericContainer, Wait } from "testcontainers";
5
+ import { fileURLToPath } from "node:url";
6
+ // src/sources.ts
7
+ const PACKAGE_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/u;
8
+ function fail(message) {
9
+ throw new Error(message);
54
10
  }
55
- /**
56
- * A started Wiremock container with helper methods for interacting with the node.
57
- */ class StartedWiremockContainer extends AbstractStartedContainer {
58
- /**
59
- * Creates a new StartedWiremockContainer.
60
- * @param startedTestContainer The underlying TestContainer.
61
- * @param url The URL of the started container.
62
- */ constructor(startedTestContainer, url){
63
- super(startedTestContainer);
64
- this._rpcUrl = url;
65
- }
66
- /**
67
- * Gets the URL of the Wiremock node.
68
- */ get rpcUrl() {
69
- return this._rpcUrl;
70
- }
11
+ function within(context, fn) {
12
+ try {
13
+ return fn();
14
+ } catch (error) {
15
+ throw new Error(`${context}: ${error.message}`, { cause: error });
16
+ }
71
17
  }
72
-
18
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
19
+ const show = (value) => value instanceof URL ? value.href : JSON.stringify(value) ?? String(value);
20
+ const text = (value, field) => typeof value === "string" && value.trim() !== "" ? value : fail(`"${field}" must be a non-empty string, got ${show(value)}`);
21
+ const toPath = (value, field) => {
22
+ if (!(value instanceof URL) && !text(value, field).startsWith("file:")) return resolve(value);
23
+ try {
24
+ return fileURLToPath(value);
25
+ } catch {
26
+ return fail(`"${field}" must be a path or a file: URL, got ${show(value)}`);
27
+ }
28
+ };
29
+ const existingFile = (path) => {
30
+ const stats = statSync(path, { throwIfNoEntry: false });
31
+ return stats?.isFile() ? path : fail(`"${path}" ${stats ? "is not a file" : "does not exist"}`);
32
+ };
33
+ const packageRoot = (name) => {
34
+ if (!PACKAGE_NAME.test(name)) fail(`"${name}" is not a valid npm package name`);
35
+ return (createRequire(join(process.cwd(), "noop.js")).resolve.paths(name) ?? []).map((dir) => join(dir, name)).find((dir) => existsSync(join(dir, "package.json"))) ?? fail(`package "${name}" is not installed (searched from "${process.cwd()}")`);
36
+ };
37
+ function resolveFile(source) {
38
+ if (typeof source === "string" || source instanceof URL) return existingFile(toPath(source, "source"));
39
+ if (!isRecord(source)) return fail(`unsupported source ${show(source)}; expected a path, a file: URL, { file }, { package, file } or { module, file }`);
40
+ const { file, package: pkg, module } = source;
41
+ if (pkg !== void 0 && module !== void 0) fail("a source may set \"package\" or \"module\", not both");
42
+ if (pkg !== void 0) {
43
+ const root = packageRoot(text(pkg, "package"));
44
+ const path = resolve(root, text(file, "file"));
45
+ return relative(root, path).split(sep)[0] === ".." ? fail(`"${String(file)}" must point to a file inside package "${pkg}"`) : existingFile(path);
46
+ }
47
+ if (module === void 0) return existingFile(toPath(file, "file"));
48
+ const anchor = toPath(module, "module");
49
+ return existingFile(resolve(statSync(anchor, { throwIfNoEntry: false })?.isDirectory() ? anchor : dirname(anchor), text(file, "file")));
50
+ }
51
+ const containerName = (name) => {
52
+ const value = text(name, "name");
53
+ return value.split("/").some((part) => [
54
+ "",
55
+ ".",
56
+ ".."
57
+ ].includes(part) || /[\\\0]/u.test(part)) ? fail(`name "${value}" must be a relative path using "/" separators, without empty, "." or ".." segments`) : value;
58
+ };
59
+ const inlineJson = (json) => typeof json === "string" ? json : JSON.stringify(json, null, 2) ?? fail("\"json\" must be a JSON string or an object");
60
+ const parseJson = (json) => {
61
+ try {
62
+ return JSON.parse(json);
63
+ } catch (error) {
64
+ return fail(`invalid JSON (${error.message})`);
65
+ }
66
+ };
67
+ function stubIds(json) {
68
+ const value = parseJson(json);
69
+ const many = isRecord(value) && "mappings" in value;
70
+ const stubs = many ? value.mappings : [value];
71
+ if (!Array.isArray(stubs) || stubs.length === 0) fail("\"mappings\" must be a non-empty array of stub mappings");
72
+ return stubs.flatMap((stub, index) => {
73
+ if (!isRecord(stub) || !isRecord(stub.request) || !isRecord(stub.response)) fail(`${many ? `mappings[${index}]` : "the mapping"} is not a WireMock stub mapping ("request" and "response" objects are required)`);
74
+ const id = stub.id ?? stub.uuid;
75
+ return typeof id === "string" ? [id] : [];
76
+ });
77
+ }
78
+ const stubIdsOf = (path) => {
79
+ try {
80
+ return path.endsWith(".json") ? stubIds(readFileSync(path, "utf8")) : [];
81
+ } catch {
82
+ return [];
83
+ }
84
+ };
85
+ const listFiles = (dir) => readdirSync(dir, {
86
+ recursive: true,
87
+ withFileTypes: true
88
+ }).filter((entry) => !entry.isDirectory()).map((entry) => relative(dir, join(entry.parentPath, entry.name)).split(sep).join("/"));
89
+ // src/index.ts
90
+ const MAPPINGS = "/home/wiremock/mappings";
91
+ const FILES = "/home/wiremock/__files";
92
+ const INLINE = "inline JSON";
93
+ var WiremockContainer = class extends GenericContainer {
94
+ #origins = /* @__PURE__ */ new Map();
95
+ #stubIds = /* @__PURE__ */ new Map();
96
+ constructor(image = "wiremock/wiremock") {
97
+ super(image);
98
+ this.withExposedPorts(8080);
99
+ this.withWaitStrategy(Wait.forListeningPorts());
100
+ }
101
+ withMappings(directory) {
102
+ within("WiremockContainer.withMappings", () => {
103
+ const mappings = join(directory, "mappings");
104
+ if (!existsSync(mappings)) fail(`"${mappings}" does not exist`);
105
+ if (!statSync(mappings).isDirectory()) fail(`"${mappings}" is not a directory`);
106
+ const files = join(directory, "__files");
107
+ const dirs = [{
108
+ source: mappings,
109
+ target: MAPPINGS
110
+ }, ...existsSync(files) ? [{
111
+ source: files,
112
+ target: FILES
113
+ }] : []];
114
+ this.#claim(dirs.flatMap(({ source, target }) => listFiles(source).map((name) => ({
115
+ target: posix.join(target, name),
116
+ origin: resolve(source, name),
117
+ ids: target === MAPPINGS ? stubIdsOf(join(source, name)) : []
118
+ }))));
119
+ this.withCopyDirectoriesToContainer(dirs);
120
+ });
121
+ return this;
122
+ }
123
+ withMapping(name, source) {
124
+ within(`WiremockContainer.withMapping("${name}")`, () => {
125
+ const file = containerName(name);
126
+ const target = posix.join(MAPPINGS, file.endsWith(".json") ? file : `${file}.json`);
127
+ const inline = isRecord(source) && "json" in source;
128
+ const origin = inline ? INLINE : resolveFile(source);
129
+ const content = inline ? inlineJson(source.json) : readFileSync(origin);
130
+ const ids = within(origin, () => stubIds(content.toString()));
131
+ this.withCopyContentToContainer(this.#claim([{
132
+ target,
133
+ origin,
134
+ ids
135
+ }]).map(() => ({
136
+ content,
137
+ target
138
+ })));
139
+ });
140
+ return this;
141
+ }
142
+ withFiles(...files) {
143
+ within("WiremockContainer.withFiles", () => {
144
+ const claims = files.map((file) => {
145
+ const origin = resolveFile(file);
146
+ const name = isRecord(file) && file.name !== void 0 ? containerName(file.name) : basename(origin);
147
+ return {
148
+ target: posix.join(FILES, name),
149
+ origin
150
+ };
151
+ });
152
+ this.withCopyFilesToContainer(this.#claim(claims).map(({ origin, target }) => ({
153
+ source: origin,
154
+ target
155
+ })));
156
+ });
157
+ return this;
158
+ }
159
+ async start() {
160
+ const startedContainer = await super.start();
161
+ return new StartedWiremockContainer(startedContainer, `http://${startedContainer.getHost()}:${startedContainer.getMappedPort(8080)}`);
162
+ }
163
+ #claim(claims) {
164
+ const origins = new Map(this.#origins);
165
+ const owners = new Map(this.#stubIds);
166
+ const fresh = claims.filter(({ target, origin, ids = [] }) => {
167
+ const existing = origins.get(target);
168
+ if (existing === origin && origin !== INLINE) return false;
169
+ if (existing) fail(`"${target}" is already registered from ${existing}; registering ${origin} would overwrite it`);
170
+ for (const id of ids) {
171
+ const owner = owners.get(id);
172
+ if (owner) fail(`stub id "${id}" in ${origin} is already used by "${owner}"; WireMock refuses to start with duplicate stub ids`);
173
+ owners.set(id, target);
174
+ }
175
+ origins.set(target, origin);
176
+ return true;
177
+ });
178
+ [this.#origins, this.#stubIds] = [origins, owners];
179
+ return fresh;
180
+ }
181
+ };
182
+ var StartedWiremockContainer = class extends AbstractStartedContainer {
183
+ #rpcUrl;
184
+ constructor(startedTestContainer, url) {
185
+ super(startedTestContainer);
186
+ this.#rpcUrl = url;
187
+ }
188
+ get rpcUrl() {
189
+ return this.#rpcUrl;
190
+ }
191
+ };
73
192
  export { StartedWiremockContainer, WiremockContainer };