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 +17 -41
- package/README.md +5 -5
- package/dist/lib/index.js +37 -13
- package/package.json +6 -3
- package/src/lib/__tests__/index.ts +118 -27
- package/src/lib/index.ts +34 -13
- package/.vscode/settings.json +0 -7
package/CONTRIBUTING.MD
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Contributing
|
|
2
2
|
|
|
3
|
-
Thanks for
|
|
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
|
|
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
|
-
*
|
|
52
|
-
* Node version
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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?:
|
|
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(
|
|
64
|
+
`stopStub(stub: Stub)` <br />
|
|
65
65
|
Stop the stub server
|
|
66
66
|
|
|
67
|
-
`test(host?: string, port?: string,
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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 =
|
|
66
|
+
var stopStub = stub => {
|
|
46
67
|
var _javaProcess$stdout, _javaProcess$stderr;
|
|
47
|
-
_logger.default.debug(
|
|
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(
|
|
74
|
+
_logger.default.info("Stopped stub server at ".concat(stub.url));
|
|
53
75
|
};
|
|
54
76
|
exports.stopStub = stopStub;
|
|
55
|
-
var test = (host, port,
|
|
56
|
-
var specsPath = _path.default.resolve(
|
|
77
|
+
var test = (host, port, contractPath, args) => {
|
|
78
|
+
var specsPath = _path.default.resolve(contractPath + '');
|
|
57
79
|
var cmd = "test";
|
|
58
|
-
if (
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
53
|
+
"@types/jest": "^29.5.2",
|
|
51
54
|
"jest": "^29.5.0",
|
|
52
|
-
"jest-extended": "^
|
|
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
|
|
22
|
-
const STUB_DIR_PATH = './data';
|
|
22
|
+
const CONTRACT_FILE_PATH = './contracts';
|
|
23
23
|
const HOST = 'localhost';
|
|
24
|
-
const PORT =
|
|
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](
|
|
43
|
+
setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
|
|
41
44
|
|
|
42
|
-
await expect(specmatic.startStub(HOST, PORT
|
|
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
|
|
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
|
-
|
|
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
|
|
85
|
+
test('startStub method fails if host info is not available in start up message', async () => {
|
|
63
86
|
execSh.mockReturnValue(javaProcessMock);
|
|
64
|
-
|
|
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)).
|
|
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](
|
|
111
|
+
setTimeout(() => readableMock.on.mock.calls[0][1](`Stub server is running on ${stubUrl}`), 0);
|
|
75
112
|
|
|
76
|
-
await expect(specmatic.startStub()).resolves.
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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 = (
|
|
48
|
-
logger.debug(
|
|
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(
|
|
72
|
+
logger.info(`Stopped stub server at ${stub.url}`);
|
|
54
73
|
};
|
|
55
74
|
|
|
56
|
-
const test = (host?: string, port?: string,
|
|
57
|
-
const specsPath = path.resolve(
|
|
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 (
|
|
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(
|
|
131
|
+
logger.info(`Set Expectations: Stub url is ${stubServerBaseUrl}`);
|
|
111
132
|
|
|
112
133
|
return new Promise((resolve, reject) => {
|
|
113
|
-
fetch(`${stubServerBaseUrl
|
|
134
|
+
fetch(`${stubServerBaseUrl}/_specmatic/expectations`, {
|
|
114
135
|
method: 'POST',
|
|
115
136
|
body: JSON.stringify(stubResponse),
|
|
116
137
|
})
|