specmatic 0.70.0 → 0.70.2

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/CONTRIBUTING.MD CHANGED
@@ -1,6 +1,8 @@
1
1
  # Contributing
2
2
 
3
- Thanks for being willing to contribute!
3
+ Thanks for your willingness to contribute!
4
+
5
+ Please check [open issues](https://github.com/znsio/specmatic-node/issues?q=is%3Aopen+is%3Aissue). Please respond to questions/bug reports/feature requests!
4
6
 
5
7
  ## Project setup
6
8
 
@@ -29,53 +31,27 @@ Please make sure to run the tests before you commit your changes by using the co
29
31
 
30
32
  `npm test`
31
33
 
32
- Build the dist files using
34
+ Build the dist files locally once to make sure build works
33
35
 
34
36
  `npm run build`
35
37
 
36
-
37
- ### Update Typings
38
-
39
- If your PR introduced some changes in the API, you are more than welcome to
40
- modify the Typescript type definition to reflect those changes. Just modify the
41
- `/types/index.d.ts` file accordingly. If you have never seen Typescript
42
- definitions before, you can read more about it in its
43
- [documentation pages](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html).
44
- Though this library itself is not written in Typescript we use
45
- [dtslint](https://github.com/microsoft/dtslint) to lint our typings.
46
-
38
+ Finally commit
47
39
 
48
40
  ## Publishing a new version to npm
49
41
 
50
42
  ### Prerequisites
51
- * Access to push to master.
52
- * Node version > 14 is needed.
53
-
54
- ### Step 1: Make the changes
55
- If there is a new version available in [specmatic downloads](https://specmatic.in/download/), download it in the project root, replacing the older version. Commit the new version.
56
-
57
- ### Step 2: Update node module's version
58
- `npm version` displays the existing version of the npm module.
59
-
60
- Use the suitable command to auto increment the npm version:
61
-
62
- `npm version major`
63
-
64
- `npm version minor`
65
-
66
- `npm version patch`
67
-
68
- OR
69
-
70
- Update the version to a specific semver by using command `npm version x.y.z`
71
-
72
- ### Step 3: Publish to npm
73
- If the version updated in step 2 is different from the one available in npm global repository, push to remote master on github will automatically build, run the tests and publish the new version to npm. You can check the status of the publish in [github actions](https://github.com/znsio/specmatic-node/actions). Though, it might take some time to reflect in the [specmatic npm page](https://www.npmjs.com/package/specmatic) because of the npm caching.
74
-
43
+ * Push access to master branch
44
+ * Node version 14 or higher
75
45
 
76
- ## Help needed
46
+ ### Step 1: Update specmatic core jar
47
+ If there is a new version available in [latest github release](https://github.com/znsio/specmatic/releases/latest), download it in the project root, replacing the older version. Commit the new version.
77
48
 
78
- Please checkout the [the open issues][issues]
49
+ ### Step 2: Make a release via github releases
50
+ * Goto [github releases](https://github.com/znsio/specmatic-node/releases) and draft a new release
51
+ * Click `choose a tag` and enter the required version. If the tag exists then you might be releasing a wrong version. Reverify the tag and version number. Ideally the tag should not exist as this is a new version and thus you should be presented with option to `+ Create new tag: <version> on publish` option. Click it.
52
+ * Give a release title of format `v<version>`.
53
+ * Describe the changes in this release briefly
54
+ * You can either save this draft and come back later to publish it or publish it now.
55
+ * On publish, a github action is triggered that updates the release on npm repository.
79
56
 
80
- Also, please watch the repo and respond to questions/bug reports/feature
81
- requests! Thanks!
57
+ You can check the publish status in [github actions](https://github.com/znsio/specmatic-node/actions). Though, it might take some time to reflect in the [specmatic npm page](https://www.npmjs.com/package/specmatic) because of the npm caching.
package/README.md CHANGED
@@ -58,14 +58,14 @@ import {
58
58
  } from 'specmatic';
59
59
  ```
60
60
 
61
- `startStub(host?: string, port?: string, stubDir?: string) : Promise<ChildProcess>` <br />
62
- Start the stub server
61
+ `startStub(host?: string, port?: number, args?: (string | number)[]): Promise<Stub>` <br />
62
+ Start the stub server. Argument `args` values are passed directly to specmatic jar executable.
63
63
 
64
- `stopStub(process: ChildProcess)` <br />
64
+ `stopStub(stub: Stub)` <br />
65
65
  Stop the stub server
66
66
 
67
- `test(host?: string, port?: string, specs?: string): Promise<boolean>` <br />
68
- Run tests
67
+ `test(host?: string, port?: string, contractPath?: string, args?: (string | number)[]): Promise<{ [k: string]: number } | undefined>` <br />
68
+ Run tests. Argument `args` values are passed directly to specmatic jar executable.
69
69
 
70
70
  `setExpectations(stubPath: string, stubServerBaseUrl?: string): Promise<boolean>` <br />
71
71
  Set stub expectiona. Stub should be running before invoking this method.
package/dist/lib/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.test = exports.stopStub = exports.startStub = exports.showTestResults = exports.setExpectations = exports.printJarVersion = void 0;
6
+ exports.test = exports.stopStub = exports.startStub = exports.showTestResults = exports.setExpectations = exports.printJarVersion = exports.Stub = void 0;
7
7
  var _nodeFetch = _interopRequireDefault(require("node-fetch"));
8
8
  var _path = _interopRequireDefault(require("path"));
9
9
  var _fastXmlParser = require("fast-xml-parser");
@@ -11,12 +11,27 @@ var _fs = _interopRequireDefault(require("fs"));
11
11
  var _logger = _interopRequireDefault(require("../common/logger"));
12
12
  var _runner = _interopRequireDefault(require("../common/runner"));
13
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
- var startStub = (host, port, stubDir) => {
15
- var stubs = _path.default.resolve(stubDir + '');
14
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
15
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
16
+ function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
17
+ class Stub {
18
+ constructor(host, port, url, process) {
19
+ _defineProperty(this, "host", void 0);
20
+ _defineProperty(this, "port", void 0);
21
+ _defineProperty(this, "url", void 0);
22
+ _defineProperty(this, "process", void 0);
23
+ this.host = host;
24
+ this.port = port;
25
+ this.url = url;
26
+ this.process = process;
27
+ }
28
+ }
29
+ exports.Stub = Stub;
30
+ var startStub = (host, port, args) => {
16
31
  var cmd = "stub";
17
- if (stubDir) cmd += " --data=".concat(stubs);
18
32
  if (host) cmd += " --host=".concat(host);
19
33
  if (port) cmd += " --port=".concat(port);
34
+ if (args) cmd += ' ' + args.join(' ');
20
35
  _logger.default.info('Stub: Starting server');
21
36
  _logger.default.debug("Stub: Executing \"".concat(cmd, "\""));
22
37
  return new Promise((resolve, reject) => {
@@ -28,7 +43,13 @@ var startStub = (host, port, stubDir) => {
28
43
  if (!error) {
29
44
  if (message.indexOf('Stub server is running') > -1) {
30
45
  _logger.default.info("Stub: ".concat(message));
31
- resolve(javaProcess);
46
+ var stubInfo = message.split('on');
47
+ if (stubInfo.length < 2) reject();else {
48
+ var _urlInfo$length;
49
+ var url = stubInfo[1].trim();
50
+ var urlInfo = /(.*?):\/\/(.*?):([0-9]+)/.exec(url);
51
+ if (((_urlInfo$length = urlInfo === null || urlInfo === void 0 ? void 0 : urlInfo.length) !== null && _urlInfo$length !== void 0 ? _urlInfo$length : 0) < 4) reject();else resolve(new Stub(urlInfo[2], parseInt(urlInfo[3]), urlInfo[0], javaProcess));
52
+ }
32
53
  } else if (message.indexOf('Address already in use') > -1) {
33
54
  _logger.default.error("Stub: ".concat(message));
34
55
  reject();
@@ -42,23 +63,25 @@ var startStub = (host, port, stubDir) => {
42
63
  });
43
64
  };
44
65
  exports.startStub = startStub;
45
- var stopStub = javaProcess => {
66
+ var stopStub = stub => {
46
67
  var _javaProcess$stdout, _javaProcess$stderr;
47
- _logger.default.debug('Stopping stub server');
68
+ _logger.default.debug("Stopping stub server at ".concat(stub.url));
69
+ var javaProcess = stub.process;
48
70
  (_javaProcess$stdout = javaProcess.stdout) === null || _javaProcess$stdout === void 0 ? void 0 : _javaProcess$stdout.removeAllListeners();
49
71
  (_javaProcess$stderr = javaProcess.stderr) === null || _javaProcess$stderr === void 0 ? void 0 : _javaProcess$stderr.removeAllListeners();
50
72
  javaProcess.removeAllListeners('close');
51
73
  javaProcess.kill();
52
- _logger.default.info('Stopped stub server');
74
+ _logger.default.info("Stopped stub server at ".concat(stub.url));
53
75
  };
54
76
  exports.stopStub = stopStub;
55
- var test = (host, port, specs) => {
56
- var specsPath = _path.default.resolve(specs + '');
77
+ var test = (host, port, contractPath, args) => {
78
+ var specsPath = _path.default.resolve(contractPath + '');
57
79
  var cmd = "test";
58
- if (specs) cmd += " ".concat(specsPath);
80
+ if (contractPath) cmd += " ".concat(specsPath);
59
81
  cmd += ' --junitReportDir=dist/test-report';
60
82
  if (host) cmd += " --host=".concat(host);
61
83
  if (port) cmd += " --port=".concat(port);
84
+ if (args) cmd += ' ' + args.join(' ');
62
85
  _logger.default.info('Test: Running');
63
86
  _logger.default.debug("Test: Executing \"".concat(cmd, "\""));
64
87
  var reportDir = _path.default.resolve('dist/test-report');
@@ -101,9 +124,10 @@ var showTestResults = testFn => {
101
124
  exports.showTestResults = showTestResults;
102
125
  var setExpectations = (stubPath, stubServerBaseUrl) => {
103
126
  var stubResponse = require(_path.default.resolve(stubPath));
104
- _logger.default.info('Set Expectations: Running');
127
+ stubServerBaseUrl = stubServerBaseUrl || 'http://localhost:9000';
128
+ _logger.default.info("Set Expectations: Stub url is ".concat(stubServerBaseUrl));
105
129
  return new Promise((resolve, reject) => {
106
- (0, _nodeFetch.default)("".concat(stubServerBaseUrl ? stubServerBaseUrl : "http://localhost:9000/", "_specmatic/expectations"), {
130
+ (0, _nodeFetch.default)("".concat(stubServerBaseUrl, "/_specmatic/expectations"), {
107
131
  method: 'POST',
108
132
  body: JSON.stringify(stubResponse)
109
133
  }).then(response => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specmatic",
3
- "version": "0.70.0",
3
+ "version": "0.70.2",
4
4
  "description": "Node wrapper for Specmatic",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -31,6 +31,9 @@
31
31
  "jest-extended/all"
32
32
  ]
33
33
  },
34
+ "specmatic": {
35
+ "logLevel": "trace"
36
+ },
34
37
  "dependencies": {
35
38
  "@babel/cli": "^7.21.5",
36
39
  "@babel/core": "^7.21.8",
@@ -47,9 +50,9 @@
47
50
  "yargs": "^17.7.2"
48
51
  },
49
52
  "devDependencies": {
50
- "@types/jest": "^29.5.1",
53
+ "@types/jest": "^29.5.2",
51
54
  "jest": "^29.5.0",
52
- "jest-extended": "^3.2.4",
55
+ "jest-extended": "^4.0.0",
53
56
  "jest-mock-extended": "^3.0.4"
54
57
  }
55
58
  }
@@ -10,6 +10,7 @@ import fs from 'fs';
10
10
  import * as specmatic from '../../';
11
11
  import { specmaticJarName } from '../../config';
12
12
  import mockStub from '../../../test-resources/sample-mock-stub.json';
13
+ import { Stub } from '..';
13
14
 
14
15
  jest.mock('exec-sh');
15
16
  jest.mock('node-fetch');
@@ -18,16 +19,18 @@ const fetchMock = fetch as unknown as jest.Mock;
18
19
 
19
20
  const SPECMATIC_JAR_PATH = path.resolve(__dirname, '..', '..', '..', specmaticJarName);
20
21
  const STUB_PATH = 'test-resources/sample-mock-stub.json';
21
- const CONTRACT_YAML_FILE_PATH = './contracts';
22
- const STUB_DIR_PATH = './data';
22
+ const CONTRACT_FILE_PATH = './contracts';
23
23
  const HOST = 'localhost';
24
- const PORT = '8000';
24
+ const PORT = 8000;
25
25
 
26
26
  const javaProcessMock = jestMock<ChildProcess>();
27
27
  const readableMock = jestMock<Readable>();
28
28
  javaProcessMock.stdout = readableMock;
29
29
  javaProcessMock.stderr = readableMock;
30
30
 
31
+ const stubUrl = `http://${HOST}:${PORT}`;
32
+ const stub = new Stub(HOST, PORT, stubUrl, javaProcessMock);
33
+
31
34
  beforeEach(() => {
32
35
  execSh.mockReset();
33
36
  fetchMock.mockReset();
@@ -37,33 +40,67 @@ beforeEach(() => {
37
40
 
38
41
  test('startStub method starts the specmatic stub server', async () => {
39
42
  execSh.mockReturnValue(javaProcessMock);
40
- setTimeout(() => readableMock.on.mock.calls[0][1]('Stub server is running'), 0);
43
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
41
44
 
42
- await expect(specmatic.startStub(HOST, PORT, STUB_DIR_PATH)).resolves.toBe(javaProcessMock);
45
+ await expect(specmatic.startStub(HOST, PORT)).resolves.toStrictEqual(stub);
43
46
 
44
47
  expect(execSh).toHaveBeenCalledTimes(1);
45
- expect(execSh.mock.calls[0][0]).toBe(
46
- `java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --data=${path.resolve(STUB_DIR_PATH)} --host=${HOST} --port=${PORT}`
47
- );
48
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT}`);
48
49
  });
49
50
 
50
51
  test('startStub method notifies when start fails due to port not available', async () => {
51
52
  execSh.mockReturnValue(javaProcessMock);
52
53
  setTimeout(() => readableMock.on.mock.calls[0][1]('Address already in use'), 0);
53
54
 
54
- await expect(specmatic.startStub(HOST, PORT, STUB_DIR_PATH)).toReject();
55
+ await expect(specmatic.startStub(HOST, PORT)).toReject();
55
56
 
56
57
  expect(execSh).toHaveBeenCalledTimes(1);
57
- expect(execSh.mock.calls[0][0]).toBe(
58
- `java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --data=${path.resolve(STUB_DIR_PATH)} --host=${HOST} --port=${PORT}`
59
- );
58
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT}`);
59
+ });
60
+
61
+ test('startStub method returns host, port and stub url', async () => {
62
+ execSh.mockReturnValue(javaProcessMock);
63
+ const randomPort = 62269;
64
+ const stubUrl = `http://${HOST}:${randomPort}`;
65
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}. Ctrl + C to stop.`), 0);
66
+
67
+ const stub = new Stub(HOST, randomPort, stubUrl, javaProcessMock);
68
+
69
+ await expect(specmatic.startStub(HOST, PORT)).resolves.toStrictEqual(stub);
70
+
71
+ expect(execSh).toHaveBeenCalledTimes(1);
72
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT}`);
73
+ });
74
+
75
+ test('startStub method fails if stub url is not available in start up message', async () => {
76
+ execSh.mockReturnValue(javaProcessMock);
77
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running`), 0);
78
+
79
+ await expect(specmatic.startStub(HOST, PORT)).toReject();
80
+
81
+ expect(execSh).toHaveBeenCalledTimes(1);
82
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT}`);
60
83
  });
61
84
 
62
- test('startStub method stubDir is optional', async () => {
85
+ test('startStub method fails if host info is not available in start up message', async () => {
63
86
  execSh.mockReturnValue(javaProcessMock);
64
- setTimeout(() => readableMock.on.mock.calls[0][1]('Stub server is running'), 0);
87
+ const randomPort = 62269;
88
+ const stubUrl = `http://`;
89
+ const stub = new Stub(HOST, randomPort, stubUrl, javaProcessMock);
90
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
65
91
 
66
- await expect(specmatic.startStub(HOST, PORT)).resolves.toBe(javaProcessMock);
92
+ await expect(specmatic.startStub(HOST, PORT)).toReject();
93
+
94
+ expect(execSh).toHaveBeenCalledTimes(1);
95
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT}`);
96
+ });
97
+
98
+ test('startStub method fails if port info is not available in start up message', async () => {
99
+ execSh.mockReturnValue(javaProcessMock);
100
+ const stubUrl = `http://${HOST}`;
101
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
102
+
103
+ await expect(specmatic.startStub(HOST, PORT)).toReject();
67
104
 
68
105
  expect(execSh).toHaveBeenCalledTimes(1);
69
106
  expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT}`);
@@ -71,16 +108,36 @@ test('startStub method stubDir is optional', async () => {
71
108
 
72
109
  test('startStub method host and port are optional', async () => {
73
110
  execSh.mockReturnValue(javaProcessMock);
74
- setTimeout(() => readableMock.on.mock.calls[0][1]('Stub server is running'), 0);
111
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
75
112
 
76
- await expect(specmatic.startStub()).resolves.toBe(javaProcessMock);
113
+ await expect(specmatic.startStub()).resolves.toStrictEqual(stub);
77
114
 
78
115
  expect(execSh).toHaveBeenCalledTimes(1);
79
116
  expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub`);
80
117
  });
81
118
 
119
+ test('startStub method takes additional pass through arguments', async () => {
120
+ execSh.mockReturnValue(javaProcessMock);
121
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
122
+
123
+ await expect(specmatic.startStub(HOST, PORT, ['p1', 'p2'])).resolves.toStrictEqual(stub);
124
+
125
+ expect(execSh).toHaveBeenCalledTimes(1);
126
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT} p1 p2`);
127
+ });
128
+
129
+ test('startStub method takes additional pass through arguments can be string or number', async () => {
130
+ execSh.mockReturnValue(javaProcessMock);
131
+ setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
132
+
133
+ await expect(specmatic.startStub(HOST, PORT, ['p1', 123])).resolves.toStrictEqual(stub);
134
+
135
+ expect(execSh).toHaveBeenCalledTimes(1);
136
+ expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(SPECMATIC_JAR_PATH)} stub --host=${HOST} --port=${PORT} p1 123`);
137
+ });
138
+
82
139
  test('stopStub method stops any running stub server', () => {
83
- specmatic.stopStub(javaProcessMock);
140
+ specmatic.stopStub(stub);
84
141
 
85
142
  expect(readableMock.removeAllListeners).toHaveBeenCalledTimes(2);
86
143
  expect(javaProcessMock.removeAllListeners).toHaveBeenCalledTimes(1);
@@ -94,16 +151,50 @@ test('test runs the contract tests', async function () {
94
151
  execSh.mock.calls[0][2]();
95
152
  }, 0);
96
153
 
97
- await expect(specmatic.test(HOST, PORT, CONTRACT_YAML_FILE_PATH)).resolves.toBeTruthy();
154
+ await expect(specmatic.test(HOST, PORT, CONTRACT_FILE_PATH)).resolves.toBeTruthy();
98
155
 
99
156
  expect(execSh).toHaveBeenCalledTimes(1);
100
157
  expect(execSh.mock.calls[0][0]).toBe(
101
158
  `java -jar ${path.resolve(SPECMATIC_JAR_PATH)} test ${path.resolve(
102
- CONTRACT_YAML_FILE_PATH
159
+ CONTRACT_FILE_PATH
103
160
  )} --junitReportDir=dist/test-report --host=${HOST} --port=${PORT}`
104
161
  );
105
162
  });
106
163
 
164
+ test('test takes additional pass through arguments', async () => {
165
+ execSh.mockReturnValue(javaProcessMock);
166
+ setTimeout(() => {
167
+ copyReportFile();
168
+ execSh.mock.calls[0][2]();
169
+ }, 0);
170
+
171
+ await expect(specmatic.test(HOST, PORT, CONTRACT_FILE_PATH, ['P1', 'P2'])).resolves.toBeTruthy();
172
+
173
+ expect(execSh).toHaveBeenCalledTimes(1);
174
+ expect(execSh.mock.calls[0][0]).toBe(
175
+ `java -jar ${path.resolve(SPECMATIC_JAR_PATH)} test ${path.resolve(
176
+ CONTRACT_FILE_PATH
177
+ )} --junitReportDir=dist/test-report --host=${HOST} --port=${PORT} P1 P2`
178
+ );
179
+ });
180
+
181
+ test('test takes additional pass through arguments can be string or number', async () => {
182
+ execSh.mockReturnValue(javaProcessMock);
183
+ setTimeout(() => {
184
+ copyReportFile();
185
+ execSh.mock.calls[0][2]();
186
+ }, 0);
187
+
188
+ await expect(specmatic.test(HOST, PORT, CONTRACT_FILE_PATH, ['P1', 123])).resolves.toBeTruthy();
189
+
190
+ expect(execSh).toHaveBeenCalledTimes(1);
191
+ expect(execSh.mock.calls[0][0]).toBe(
192
+ `java -jar ${path.resolve(SPECMATIC_JAR_PATH)} test ${path.resolve(
193
+ CONTRACT_FILE_PATH
194
+ )} --junitReportDir=dist/test-report --host=${HOST} --port=${PORT} P1 123`
195
+ );
196
+ });
197
+
107
198
  test('test runs the contract tests with host and port optional', async function () {
108
199
  execSh.mockReturnValue(javaProcessMock);
109
200
  setTimeout(() => {
@@ -198,7 +289,7 @@ test('printJarVersion', () => {
198
289
  });
199
290
 
200
291
  test('setExpectations with default baseUrl', async () => {
201
- fetchMock.mockReturnValue(Promise.resolve({status: 200}));
292
+ fetchMock.mockReturnValue(Promise.resolve({ status: 200 }));
202
293
  await expect(specmatic.setExpectations(path.resolve(STUB_PATH))).toResolve();
203
294
 
204
295
  expect(fetchMock).toHaveBeenCalledTimes(1);
@@ -210,13 +301,13 @@ test('setExpectations with default baseUrl', async () => {
210
301
  });
211
302
 
212
303
  test('setExpectations with a different baseUrl for the stub server', async () => {
213
- fetchMock.mockReturnValue(Promise.resolve({status: 200}));
214
- const stubServerBaseUrl = 'http://localhost:8000/';
304
+ fetchMock.mockReturnValue(Promise.resolve({ status: 200 }));
305
+ const stubServerBaseUrl = 'http://localhost:8000';
215
306
 
216
307
  await expect(specmatic.setExpectations(path.resolve(STUB_PATH), stubServerBaseUrl)).toResolve();
217
308
 
218
309
  expect(fetchMock).toHaveBeenCalledTimes(1);
219
- expect(fetchMock.mock.calls[0][0]).toBe(`${stubServerBaseUrl}_specmatic/expectations`);
310
+ expect(fetchMock.mock.calls[0][0]).toBe(`${stubServerBaseUrl}/_specmatic/expectations`);
220
311
  expect(fetchMock.mock.calls[0][1]).toMatchObject({
221
312
  method: 'POST',
222
313
  body: JSON.stringify(mockStub),
@@ -237,13 +328,13 @@ test('setExpectations notifies when it fails', async () => {
237
328
  });
238
329
 
239
330
  test('setExpectations notifies as failure when status code is not 200', async () => {
240
- fetchMock.mockReturnValue(Promise.resolve({status: 400}));
241
- const stubServerBaseUrl = 'http://localhost:8000/';
331
+ fetchMock.mockReturnValue(Promise.resolve({ status: 400 }));
332
+ const stubServerBaseUrl = 'http://localhost:8000';
242
333
 
243
334
  await expect(specmatic.setExpectations(path.resolve(STUB_PATH), stubServerBaseUrl)).toReject();
244
335
 
245
336
  expect(fetchMock).toHaveBeenCalledTimes(1);
246
- expect(fetchMock.mock.calls[0][0]).toBe(`${stubServerBaseUrl}_specmatic/expectations`);
337
+ expect(fetchMock.mock.calls[0][0]).toBe(`${stubServerBaseUrl}/_specmatic/expectations`);
247
338
  expect(fetchMock.mock.calls[0][1]).toMatchObject({
248
339
  method: 'POST',
249
340
  body: JSON.stringify(mockStub),
package/src/lib/index.ts CHANGED
@@ -6,13 +6,24 @@ import fs from 'fs';
6
6
  import logger from '../common/logger';
7
7
  import callSpecmatic from '../common/runner';
8
8
 
9
- const startStub = (host?: string, port?: string, stubDir?: string): Promise<ChildProcess> => {
10
- const stubs = path.resolve(stubDir + '');
11
-
9
+ export class Stub {
10
+ host: string;
11
+ port: number;
12
+ url: string;
13
+ process: ChildProcess;
14
+ constructor(host: string, port: number, url: string, process: ChildProcess) {
15
+ this.host = host;
16
+ this.port = port;
17
+ this.url = url;
18
+ this.process = process;
19
+ }
20
+ }
21
+
22
+ const startStub = (host?: string, port?: number, args?: (string | number)[]): Promise<Stub> => {
12
23
  var cmd = `stub`;
13
- if (stubDir) cmd += ` --data=${stubs}`;
14
24
  if (host) cmd += ` --host=${host}`;
15
25
  if (port) cmd += ` --port=${port}`;
26
+ if (args) cmd += ' ' + args.join(' ');
16
27
 
17
28
  logger.info('Stub: Starting server');
18
29
  logger.debug(`Stub: Executing "${cmd}"`);
@@ -29,7 +40,14 @@ const startStub = (host?: string, port?: string, stubDir?: string): Promise<Chil
29
40
  if (!error) {
30
41
  if (message.indexOf('Stub server is running') > -1) {
31
42
  logger.info(`Stub: ${message}`);
32
- resolve(javaProcess);
43
+ const stubInfo = message.split('on');
44
+ if (stubInfo.length < 2) reject();
45
+ else {
46
+ const url = stubInfo[1].trim();
47
+ const urlInfo = /(.*?):\/\/(.*?):([0-9]+)/.exec(url);
48
+ if ((urlInfo?.length ?? 0) < 4) reject();
49
+ else resolve(new Stub(urlInfo![2], parseInt(urlInfo![3]), urlInfo![0], javaProcess));
50
+ }
33
51
  } else if (message.indexOf('Address already in use') > -1) {
34
52
  logger.error(`Stub: ${message}`);
35
53
  reject();
@@ -44,23 +62,25 @@ const startStub = (host?: string, port?: string, stubDir?: string): Promise<Chil
44
62
  });
45
63
  };
46
64
 
47
- const stopStub = (javaProcess: ChildProcess) => {
48
- logger.debug('Stopping stub server');
65
+ const stopStub = (stub: Stub) => {
66
+ logger.debug(`Stopping stub server at ${stub.url}`);
67
+ const javaProcess = stub.process;
49
68
  javaProcess.stdout?.removeAllListeners();
50
69
  javaProcess.stderr?.removeAllListeners();
51
70
  javaProcess.removeAllListeners('close');
52
71
  javaProcess.kill();
53
- logger.info('Stopped stub server');
72
+ logger.info(`Stopped stub server at ${stub.url}`);
54
73
  };
55
74
 
56
- const test = (host?: string, port?: string, specs?: string): Promise<{ [k: string]: number } | undefined> => {
57
- const specsPath = path.resolve(specs + '');
75
+ const test = (host?: string, port?: number, contractPath?: string, args?: (string | number)[]): Promise<{ [k: string]: number } | undefined> => {
76
+ const specsPath = path.resolve(contractPath + '');
58
77
 
59
78
  var cmd = `test`;
60
- if (specs) cmd += ` ${specsPath}`;
79
+ if (contractPath) cmd += ` ${specsPath}`;
61
80
  cmd += ' --junitReportDir=dist/test-report';
62
81
  if (host) cmd += ` --host=${host}`;
63
82
  if (port) cmd += ` --port=${port}`;
83
+ if (args) cmd += ' ' + args.join(' ');
64
84
 
65
85
  logger.info('Test: Running');
66
86
  logger.debug(`Test: Executing "${cmd}"`);
@@ -106,11 +126,12 @@ const showTestResults = (testFn: (name: string, cb: () => void) => void) => {
106
126
 
107
127
  const setExpectations = (stubPath: string, stubServerBaseUrl?: string): Promise<void> => {
108
128
  const stubResponse = require(path.resolve(stubPath));
129
+ stubServerBaseUrl = stubServerBaseUrl || 'http://localhost:9000';
109
130
 
110
- logger.info('Set Expectations: Running');
131
+ logger.info(`Set Expectations: Stub url is ${stubServerBaseUrl}`);
111
132
 
112
133
  return new Promise((resolve, reject) => {
113
- fetch(`${stubServerBaseUrl ? stubServerBaseUrl : `http://localhost:9000/`}_specmatic/expectations`, {
134
+ fetch(`${stubServerBaseUrl}/_specmatic/expectations`, {
114
135
  method: 'POST',
115
136
  body: JSON.stringify(stubResponse),
116
137
  })
@@ -1,7 +0,0 @@
1
- {
2
- "cSpell.words": [
3
- "qontract",
4
- "qontracts",
5
- "specmatic"
6
- ]
7
- }