specmatic 0.67.3 → 0.67.5
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/.github/workflows/npm-publish.yml +6 -17
- package/.github/workflows/test.yml +1 -1
- package/README.md +20 -5
- package/dist/bin/core.js +7 -3
- package/dist/lib/index.js +38 -23
- package/dist/logger.js +31 -0
- package/global.d.ts +1 -0
- package/package.json +12 -3
- package/src/bin/core.ts +7 -4
- package/src/lib/__tests__/index.ts +42 -9
- package/src/lib/index.ts +44 -23
- package/src/logger.ts +16 -0
- package/tsconfig.json +1 -1
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
|
|
3
|
-
|
|
4
|
-
name: publish
|
|
1
|
+
name: NPM Publish
|
|
5
2
|
|
|
6
3
|
on:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
types:
|
|
10
|
-
- completed
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
11
6
|
|
|
12
7
|
jobs:
|
|
13
|
-
|
|
14
|
-
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
8
|
+
publish:
|
|
15
9
|
runs-on: ubuntu-latest
|
|
16
10
|
steps:
|
|
17
11
|
- uses: actions/checkout@v2
|
|
@@ -20,14 +14,9 @@ jobs:
|
|
|
20
14
|
node-version: 14
|
|
21
15
|
- run: npm install
|
|
22
16
|
- run: npm run build
|
|
23
|
-
-
|
|
24
|
-
- name: Create Tag
|
|
25
|
-
id: create_tag
|
|
26
|
-
uses: jaywcjlove/create-tag-action@main
|
|
27
|
-
if: env.previous_tag
|
|
17
|
+
- uses: reedyuk/npm-version@1.1.1
|
|
28
18
|
with:
|
|
29
|
-
|
|
30
|
-
release: true
|
|
19
|
+
version: ${{ github.event.release.tag_name }}
|
|
31
20
|
- uses: JS-DevTools/npm-publish@v1
|
|
32
21
|
with:
|
|
33
22
|
check-version: true
|
package/README.md
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
[](https://github.com/znsio/specmatic-node/releases/latest)
|
|
6
6
|
|
|
7
7
|
This node module is a thin wrapper over the [standalone executable jar](https://specmatic.in/getting_started.html#setup). All core capabilities are in the main [Specmatic project](https://github.com/znsio/specmatic). The purpose of this wrapper module is to act as a convenience to help with below aspects.
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
- Easy installation and upgrade of the jar file in node projects through npm
|
|
10
|
+
- JS helper library which provides to do various setup steps like start, stop the specmatic stub server, installing specs etc. These helpers methods can be used inside a setup file inside a javascript project programmatically instead of using cli scripts.
|
|
10
11
|
|
|
11
12
|
## Quick Start
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
`npm install specmatic` will install the specmatic locally to the node project.
|
|
13
15
|
|
|
14
16
|
Sample npm scripts to run specmatic, (Check [Documentation](https://specmatic.in/documentation.html) for more information on cli commands and arguments.)
|
|
15
17
|
|
|
@@ -26,6 +28,7 @@ Tests for Free – Specmatic parses your API Specification files and based on th
|
|
|
26
28
|
Check [Documentation](https://specmatic.in/documentation.html) for more information on cli commands and arguments.
|
|
27
29
|
|
|
28
30
|
## Sample Repo
|
|
31
|
+
|
|
29
32
|
https://github.com/znsio/specmatic-order-bff-nodejs
|
|
30
33
|
|
|
31
34
|
## Programmatic Access
|
|
@@ -33,10 +36,10 @@ https://github.com/znsio/specmatic-order-bff-nodejs
|
|
|
33
36
|
Specmatic JS library exposes some of the commands as methods that can be run programmatically from any javascript testing framework, during setup or test phases.
|
|
34
37
|
|
|
35
38
|
```
|
|
36
|
-
import {
|
|
39
|
+
import {
|
|
37
40
|
startStub,
|
|
38
41
|
stopStub,
|
|
39
|
-
test,
|
|
42
|
+
test,
|
|
40
43
|
setExpecations,
|
|
41
44
|
showTestResults,
|
|
42
45
|
printJarVersion
|
|
@@ -60,3 +63,15 @@ method to report test results in any framework so that it shows up in IDE test r
|
|
|
60
63
|
|
|
61
64
|
`printJarVersion()` <br />
|
|
62
65
|
method to print the version of specmatic.jar
|
|
66
|
+
|
|
67
|
+
## Logging
|
|
68
|
+
|
|
69
|
+
By default only warning and error messages are displayed. You can configure the loglevel in package.json as
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
"specmatic": {
|
|
73
|
+
"logLevel": "debug"
|
|
74
|
+
},
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
logLevel accepts all values supported by winston logger (https://github.com/winstonjs/winston#logging-levels)
|
package/dist/bin/core.js
CHANGED
|
@@ -7,15 +7,19 @@ exports.default = void 0;
|
|
|
7
7
|
var _execSh = _interopRequireDefault(require("exec-sh"));
|
|
8
8
|
var _path = _interopRequireDefault(require("path"));
|
|
9
9
|
var _config = require("../config");
|
|
10
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
10
11
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
12
|
var callSpecmaticCli = args => {
|
|
12
13
|
var specmaticJarPath = _path.default.resolve(_config.specmaticJarPathLocal);
|
|
13
14
|
var cliArgs = (args || process.argv).slice(2).join(' ');
|
|
14
|
-
|
|
15
|
+
_logger.default.info("CLI: Running with args \"".concat(cliArgs, "\""));
|
|
15
16
|
(0, _execSh.default)("java -jar ".concat(specmaticJarPath, " ").concat(cliArgs), {}, err => {
|
|
16
17
|
if (err) {
|
|
17
|
-
|
|
18
|
-
process.
|
|
18
|
+
_logger.default.info('CLI: Finished with non zero exit code: ', err.code);
|
|
19
|
+
process.exitCode = err.code;
|
|
20
|
+
} else {
|
|
21
|
+
_logger.default.info('CLI: Finished');
|
|
22
|
+
process.exitCode = 0;
|
|
19
23
|
}
|
|
20
24
|
});
|
|
21
25
|
};
|
package/dist/lib/index.js
CHANGED
|
@@ -10,6 +10,7 @@ var _execSh = _interopRequireDefault(require("exec-sh"));
|
|
|
10
10
|
var _config = require("../config");
|
|
11
11
|
var _fastXmlParser = require("fast-xml-parser");
|
|
12
12
|
var _fs = _interopRequireDefault(require("fs"));
|
|
13
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
13
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
15
|
var specmaticJarPath = _path.default.resolve(_config.specmaticJarPathLocal);
|
|
15
16
|
var startStub = (host, port, stubDir) => {
|
|
@@ -18,34 +19,37 @@ var startStub = (host, port, stubDir) => {
|
|
|
18
19
|
if (stubDir) cmd += " --data=".concat(stubs);
|
|
19
20
|
if (host) cmd += " --host=".concat(host);
|
|
20
21
|
if (port) cmd += " --port=".concat(port);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return new Promise((resolve, _reject) => {
|
|
22
|
+
_logger.default.info('Stub: Starting server');
|
|
23
|
+
_logger.default.debug("Stub: Executing \"".concat(cmd, "\""));
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
25
|
var javaProcess = (0, _execSh.default)(cmd, {
|
|
26
26
|
stdio: 'pipe',
|
|
27
27
|
stderr: 'pipe'
|
|
28
28
|
}, err => {
|
|
29
29
|
if (err) {
|
|
30
|
-
|
|
30
|
+
_logger.default.error("Stub: Exited with error ".concat(err));
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
javaProcess.stdout.on('data', function (data) {
|
|
34
|
-
// console.log('STDOUT: ' + data);
|
|
35
34
|
if (data.indexOf('Stub server is running') > -1) {
|
|
36
|
-
|
|
35
|
+
_logger.default.info("Stub: ".concat(data));
|
|
37
36
|
resolve(javaProcess);
|
|
37
|
+
} else if (data.indexOf('Address already in use') > -1) {
|
|
38
|
+
_logger.default.error("Stub: ".concat(data));
|
|
39
|
+
reject();
|
|
40
|
+
} else {
|
|
41
|
+
_logger.default.debug("Stub: ".concat(data));
|
|
38
42
|
}
|
|
39
43
|
});
|
|
40
44
|
javaProcess.stderr.on('data', function (data) {
|
|
41
|
-
|
|
45
|
+
_logger.default.error("Stub: ".concat(data));
|
|
42
46
|
});
|
|
43
47
|
});
|
|
44
48
|
};
|
|
45
49
|
exports.startStub = startStub;
|
|
46
50
|
var stopStub = javaProcess => {
|
|
47
51
|
var _javaProcess$stdout, _javaProcess$stderr;
|
|
48
|
-
|
|
52
|
+
_logger.default.info('Stopping stub server');
|
|
49
53
|
(_javaProcess$stdout = javaProcess.stdout) === null || _javaProcess$stdout === void 0 ? void 0 : _javaProcess$stdout.removeAllListeners();
|
|
50
54
|
(_javaProcess$stderr = javaProcess.stderr) === null || _javaProcess$stderr === void 0 ? void 0 : _javaProcess$stderr.removeAllListeners();
|
|
51
55
|
javaProcess.removeAllListeners('close');
|
|
@@ -59,22 +63,21 @@ var test = (host, port, specs) => {
|
|
|
59
63
|
cmd += ' --junitReportDir=dist/test-report';
|
|
60
64
|
if (host) cmd += " --host=".concat(host);
|
|
61
65
|
if (port) cmd += " --port=".concat(port);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.log('Running specmatic tests');
|
|
66
|
+
_logger.default.info('Test: Running');
|
|
67
|
+
_logger.default.debug("Test: Executing \"".concat(cmd, "\""));
|
|
65
68
|
var reportDir = _path.default.resolve('dist/test-report');
|
|
66
69
|
_fs.default.rmSync(reportDir, {
|
|
67
70
|
recursive: true,
|
|
68
71
|
force: true
|
|
69
72
|
});
|
|
70
73
|
return new Promise((resolve, _reject) => {
|
|
71
|
-
(0, _execSh.default)(cmd, {
|
|
74
|
+
var javaProcess = (0, _execSh.default)(cmd, {
|
|
72
75
|
stdio: 'pipe',
|
|
73
76
|
stderr: 'pipe'
|
|
74
77
|
}, err => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
if (err) {
|
|
79
|
+
_logger.default.error("Test: Failed with error ".concat(err));
|
|
80
|
+
}
|
|
78
81
|
var testCases = parseJunitXML();
|
|
79
82
|
var total = testCases.length;
|
|
80
83
|
var success = testCases.filter(testcase => testcase['system-out'] && !testcase['failure']).length;
|
|
@@ -86,6 +89,12 @@ var test = (host, port, specs) => {
|
|
|
86
89
|
};
|
|
87
90
|
resolve(result);
|
|
88
91
|
});
|
|
92
|
+
javaProcess.stdout.on('data', function (data) {
|
|
93
|
+
_logger.default.debug("Test: ".concat(data));
|
|
94
|
+
});
|
|
95
|
+
javaProcess.stderr.on('data', function (data) {
|
|
96
|
+
_logger.default.error("Test: ".concat(data));
|
|
97
|
+
});
|
|
89
98
|
});
|
|
90
99
|
};
|
|
91
100
|
exports.test = test;
|
|
@@ -101,22 +110,28 @@ var showTestResults = testFn => {
|
|
|
101
110
|
exports.showTestResults = showTestResults;
|
|
102
111
|
var setExpectations = (stubPath, stubServerBaseUrl) => {
|
|
103
112
|
var stubResponse = require(_path.default.resolve(stubPath));
|
|
104
|
-
|
|
105
|
-
return new Promise((resolve,
|
|
113
|
+
_logger.default.info('Set Expectations: Running');
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
106
115
|
(0, _nodeFetch.default)("".concat(stubServerBaseUrl ? stubServerBaseUrl : "http://localhost:9000/", "_specmatic/expectations"), {
|
|
107
116
|
method: 'POST',
|
|
108
117
|
body: JSON.stringify(stubResponse)
|
|
109
|
-
}).then(
|
|
110
|
-
|
|
111
|
-
resolve(
|
|
118
|
+
}).then(() => {
|
|
119
|
+
_logger.default.info('Set Expectations: Finished');
|
|
120
|
+
resolve();
|
|
121
|
+
}).catch(err => {
|
|
122
|
+
_logger.default.error("Set Expectations: Failed with error ".concat(err));
|
|
123
|
+
reject();
|
|
112
124
|
});
|
|
113
125
|
});
|
|
114
126
|
};
|
|
115
127
|
exports.setExpectations = setExpectations;
|
|
116
128
|
var printJarVersion = () => {
|
|
117
|
-
|
|
129
|
+
var cmd = "java -jar ".concat(specmaticJarPath, " --version");
|
|
130
|
+
_logger.default.info('Print Jar Version: Running');
|
|
131
|
+
_logger.default.debug("Print Jar Version: Executing \"".concat(cmd, "\""));
|
|
132
|
+
(0, _execSh.default)(cmd, {}, err => {
|
|
118
133
|
if (err) {
|
|
119
|
-
|
|
134
|
+
_logger.default.error("Print Jar Version: Failed with error ".concat(err));
|
|
120
135
|
}
|
|
121
136
|
});
|
|
122
137
|
};
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _winston = require("winston");
|
|
8
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
var data = _fs.default.readFileSync('./package.json');
|
|
11
|
+
var packageConfig = JSON.parse(data);
|
|
12
|
+
var specmaticConfig = packageConfig.specmatic || {};
|
|
13
|
+
var logFormat = _winston.format.printf(_ref => {
|
|
14
|
+
var {
|
|
15
|
+
level,
|
|
16
|
+
message,
|
|
17
|
+
label,
|
|
18
|
+
timestamp
|
|
19
|
+
} = _ref;
|
|
20
|
+
return "[".concat(label, "] ").concat(timestamp, " ").concat(level, ": ").concat(message);
|
|
21
|
+
});
|
|
22
|
+
var _default = (0, _winston.createLogger)({
|
|
23
|
+
level: specmaticConfig.logLevel || 'warn',
|
|
24
|
+
format: _winston.format.combine(_winston.format.label({
|
|
25
|
+
label: 'specmatic'
|
|
26
|
+
}), _winston.format.timestamp({
|
|
27
|
+
format: 'DD-MM-YYYY HH:mm:ss'
|
|
28
|
+
}), logFormat),
|
|
29
|
+
transports: [new _winston.transports.Console()]
|
|
30
|
+
});
|
|
31
|
+
exports.default = _default;
|
package/global.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'jest-extended';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specmatic",
|
|
3
|
-
"version": "0.67.
|
|
3
|
+
"version": "0.67.5",
|
|
4
4
|
"description": "Node wrapper for Specmatic",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,8 +24,15 @@
|
|
|
24
24
|
},
|
|
25
25
|
"homepage": "https://github.com/znsio/specmatic-node#readme",
|
|
26
26
|
"bin": {
|
|
27
|
-
"specmatic": "dist/bin/index.js"
|
|
28
|
-
|
|
27
|
+
"specmatic": "dist/bin/index.js"
|
|
28
|
+
},
|
|
29
|
+
"jest": {
|
|
30
|
+
"setupFilesAfterEnv": [
|
|
31
|
+
"jest-extended/all"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"specmatic": {
|
|
35
|
+
"logLevel": "debug"
|
|
29
36
|
},
|
|
30
37
|
"dependencies": {
|
|
31
38
|
"@babel/cli": "^7.21.5",
|
|
@@ -39,11 +46,13 @@
|
|
|
39
46
|
"fast-xml-parser": "^4.2.2",
|
|
40
47
|
"node-fetch": "^2.6.11",
|
|
41
48
|
"rimraf": "^5.0.1",
|
|
49
|
+
"winston": "^3.8.2",
|
|
42
50
|
"yargs": "^17.7.2"
|
|
43
51
|
},
|
|
44
52
|
"devDependencies": {
|
|
45
53
|
"@types/jest": "^29.5.1",
|
|
46
54
|
"jest": "^29.5.0",
|
|
55
|
+
"jest-extended": "^3.2.4",
|
|
47
56
|
"jest-mock-extended": "^3.0.4"
|
|
48
57
|
}
|
|
49
58
|
}
|
package/src/bin/core.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import execSh from 'exec-sh';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { specmaticJarPathLocal } from '../config';
|
|
4
|
+
import logger from '../logger';
|
|
4
5
|
|
|
5
6
|
const callSpecmaticCli = (args?: string[]) => {
|
|
6
7
|
const specmaticJarPath = path.resolve(specmaticJarPathLocal);
|
|
7
8
|
const cliArgs = (args || process.argv).slice(2).join(' ');
|
|
8
|
-
|
|
9
|
-
console.log('starting specmatic server', cliArgs);
|
|
9
|
+
logger.info(`CLI: Running with args "${cliArgs}"`);
|
|
10
10
|
execSh(`java -jar ${specmaticJarPath} ${cliArgs}`, {}, (err: any) => {
|
|
11
11
|
if (err) {
|
|
12
|
-
|
|
13
|
-
process.
|
|
12
|
+
logger.info('CLI: Finished with non zero exit code: ', err.code);
|
|
13
|
+
process.exitCode = err.code;
|
|
14
|
+
} else {
|
|
15
|
+
logger.info('CLI: Finished');
|
|
16
|
+
process.exitCode = 0;
|
|
14
17
|
}
|
|
15
18
|
});
|
|
16
19
|
};
|
|
@@ -46,6 +46,21 @@ test('startStub method starts the specmatic stub server', async () => {
|
|
|
46
46
|
);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
// test('startStub method notifies when start fails due to port not available', async () => {
|
|
50
|
+
// execSh.mockReturnValue(javaProcessMock);
|
|
51
|
+
|
|
52
|
+
// specmatic.startStub().then(javaProcess => {
|
|
53
|
+
// throw new Error('Expected to fail due to port not available');
|
|
54
|
+
// });
|
|
55
|
+
|
|
56
|
+
// readableMock.on.mock.calls[0][1]('Stub server is running');
|
|
57
|
+
|
|
58
|
+
// expect(execSh).toHaveBeenCalledTimes(1);
|
|
59
|
+
// expect(execSh.mock.calls[0][0]).toBe(
|
|
60
|
+
// `java -jar ${path.resolve(specmaticJarPathLocal)} stub`
|
|
61
|
+
// );
|
|
62
|
+
// });
|
|
63
|
+
|
|
49
64
|
test('startStub method stubDir is optional', async () => {
|
|
50
65
|
execSh.mockReturnValue(javaProcessMock);
|
|
51
66
|
|
|
@@ -81,6 +96,8 @@ test('stopStub method stops any running stub server', () => {
|
|
|
81
96
|
});
|
|
82
97
|
|
|
83
98
|
test('test runs the contract tests', function (done) {
|
|
99
|
+
execSh.mockReturnValue(javaProcessMock);
|
|
100
|
+
|
|
84
101
|
specmatic.test(HOST, PORT, CONTRACT_YAML_FILE_PATH).then(result => {
|
|
85
102
|
expect(result).toBeTruthy();
|
|
86
103
|
done();
|
|
@@ -96,6 +113,8 @@ test('test runs the contract tests', function (done) {
|
|
|
96
113
|
});
|
|
97
114
|
|
|
98
115
|
test('test runs the contract tests with host and port optional', function (done) {
|
|
116
|
+
execSh.mockReturnValue(javaProcessMock);
|
|
117
|
+
|
|
99
118
|
specmatic.test().then(result => {
|
|
100
119
|
expect(result).toBeTruthy();
|
|
101
120
|
done();
|
|
@@ -107,6 +126,8 @@ test('test runs the contract tests with host and port optional', function (done)
|
|
|
107
126
|
});
|
|
108
127
|
|
|
109
128
|
test('test runs the contract tests with contracts path optional', function (done) {
|
|
129
|
+
execSh.mockReturnValue(javaProcessMock);
|
|
130
|
+
|
|
110
131
|
specmatic.test(HOST, PORT).then(result => {
|
|
111
132
|
expect(result).toBeTruthy();
|
|
112
133
|
done();
|
|
@@ -120,6 +141,8 @@ test('test runs the contract tests with contracts path optional', function (done
|
|
|
120
141
|
});
|
|
121
142
|
|
|
122
143
|
test('test runs the contract tests and get summary', function (done) {
|
|
144
|
+
execSh.mockReturnValue(javaProcessMock);
|
|
145
|
+
|
|
123
146
|
specmatic.test().then(result => {
|
|
124
147
|
expect(result).not.toBeUndefined();
|
|
125
148
|
expect(result!.total).toBe(5);
|
|
@@ -134,6 +157,8 @@ test('test runs the contract tests and get summary', function (done) {
|
|
|
134
157
|
});
|
|
135
158
|
|
|
136
159
|
test('test runs the contract tests and get summary when there is just one test', function (done) {
|
|
160
|
+
execSh.mockReturnValue(javaProcessMock);
|
|
161
|
+
|
|
137
162
|
specmatic.test().then(result => {
|
|
138
163
|
expect(result).not.toBeUndefined();
|
|
139
164
|
expect(result!.total).toBe(1);
|
|
@@ -148,6 +173,8 @@ test('test runs the contract tests and get summary when there is just one test',
|
|
|
148
173
|
});
|
|
149
174
|
|
|
150
175
|
test('test invocation makes sure previous junit report if any is deleted', function (done) {
|
|
176
|
+
execSh.mockReturnValue(javaProcessMock);
|
|
177
|
+
|
|
151
178
|
copyReportFileWithName('sample-junit-result-single.xml');
|
|
152
179
|
specmatic.test(HOST, PORT).then(result => {
|
|
153
180
|
expect(result).toBeTruthy();
|
|
@@ -165,12 +192,21 @@ test('printJarVersion', () => {
|
|
|
165
192
|
expect(execSh.mock.calls[0][0]).toBe(`java -jar ${path.resolve(specmaticJarPathLocal)} --version`);
|
|
166
193
|
});
|
|
167
194
|
|
|
168
|
-
test('setExpectations with default baseUrl',
|
|
195
|
+
test('setExpectations with default baseUrl', async () => {
|
|
169
196
|
fetchMock.mockReturnValue(Promise.resolve('{}'));
|
|
170
|
-
specmatic.setExpectations(path.resolve(STUB_PATH)).
|
|
171
|
-
|
|
172
|
-
|
|
197
|
+
await expect(specmatic.setExpectations(path.resolve(STUB_PATH))).toResolve();
|
|
198
|
+
|
|
199
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
200
|
+
expect(fetchMock.mock.calls[0][0]).toBe('http://localhost:9000/_specmatic/expectations');
|
|
201
|
+
expect(fetchMock.mock.calls[0][1]).toMatchObject({
|
|
202
|
+
method: 'POST',
|
|
203
|
+
body: JSON.stringify(mockStub),
|
|
173
204
|
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('setExpectations notify when it fails', async () => {
|
|
208
|
+
fetchMock.mockReturnValue(Promise.reject());
|
|
209
|
+
await expect(specmatic.setExpectations(path.resolve(STUB_PATH))).toReject();
|
|
174
210
|
|
|
175
211
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
176
212
|
expect(fetchMock.mock.calls[0][0]).toBe('http://localhost:9000/_specmatic/expectations');
|
|
@@ -180,13 +216,10 @@ test('setExpectations with default baseUrl', done => {
|
|
|
180
216
|
});
|
|
181
217
|
});
|
|
182
218
|
|
|
183
|
-
test('setExpectations with a different baseUrl for the stub server',
|
|
219
|
+
test('setExpectations with a different baseUrl for the stub server', async () => {
|
|
184
220
|
fetchMock.mockReturnValue(Promise.resolve('{}'));
|
|
185
221
|
const stubServerBaseUrl = 'http://localhost:8000/';
|
|
186
|
-
specmatic.setExpectations(path.resolve(STUB_PATH), stubServerBaseUrl).
|
|
187
|
-
expect(result).toBeTruthy();
|
|
188
|
-
done();
|
|
189
|
-
});
|
|
222
|
+
await expect(specmatic.setExpectations(path.resolve(STUB_PATH), stubServerBaseUrl)).toResolve();
|
|
190
223
|
|
|
191
224
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
192
225
|
expect(fetchMock.mock.calls[0][0]).toBe(`${stubServerBaseUrl}_specmatic/expectations`);
|
package/src/lib/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { specmaticJarPathLocal, specmatic } from '../config';
|
|
|
5
5
|
import { ChildProcess } from 'child_process';
|
|
6
6
|
import { XMLParser } from 'fast-xml-parser';
|
|
7
7
|
import fs from 'fs';
|
|
8
|
+
import logger from '../logger';
|
|
8
9
|
|
|
9
10
|
const specmaticJarPath = path.resolve(specmaticJarPathLocal);
|
|
10
11
|
|
|
@@ -15,30 +16,35 @@ const startStub = (host?: string, port?: string, stubDir?: string): Promise<Chil
|
|
|
15
16
|
if (stubDir) cmd += ` --data=${stubs}`;
|
|
16
17
|
if (host) cmd += ` --host=${host}`;
|
|
17
18
|
if (port) cmd += ` --port=${port}`;
|
|
18
|
-
// console.log(cmd);
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
logger.info('Stub: Starting server');
|
|
21
|
+
logger.debug(`Stub: Executing "${cmd}"`);
|
|
22
|
+
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
22
24
|
const javaProcess = execSh(cmd, { stdio: 'pipe', stderr: 'pipe' }, (err: any) => {
|
|
23
25
|
if (err) {
|
|
24
|
-
|
|
26
|
+
logger.error(`Stub: Exited with error ${err}`);
|
|
25
27
|
}
|
|
26
28
|
});
|
|
27
29
|
javaProcess.stdout.on('data', function (data: String) {
|
|
28
|
-
// console.log('STDOUT: ' + data);
|
|
29
30
|
if (data.indexOf('Stub server is running') > -1) {
|
|
30
|
-
|
|
31
|
+
logger.info(`Stub: ${data}`);
|
|
31
32
|
resolve(javaProcess);
|
|
33
|
+
} else if (data.indexOf('Address already in use') > -1) {
|
|
34
|
+
logger.error(`Stub: ${data}`);
|
|
35
|
+
reject();
|
|
36
|
+
} else {
|
|
37
|
+
logger.debug(`Stub: ${data}`);
|
|
32
38
|
}
|
|
33
39
|
});
|
|
34
40
|
javaProcess.stderr.on('data', function (data: String) {
|
|
35
|
-
|
|
41
|
+
logger.error(`Stub: ${data}`);
|
|
36
42
|
});
|
|
37
43
|
});
|
|
38
44
|
};
|
|
39
45
|
|
|
40
46
|
const stopStub = (javaProcess: ChildProcess) => {
|
|
41
|
-
|
|
47
|
+
logger.info('Stopping stub server');
|
|
42
48
|
javaProcess.stdout?.removeAllListeners();
|
|
43
49
|
javaProcess.stderr?.removeAllListeners();
|
|
44
50
|
javaProcess.removeAllListeners('close');
|
|
@@ -53,18 +59,18 @@ const test = (host?: string, port?: string, specs?: string): Promise<{ [k: strin
|
|
|
53
59
|
cmd += ' --junitReportDir=dist/test-report';
|
|
54
60
|
if (host) cmd += ` --host=${host}`;
|
|
55
61
|
if (port) cmd += ` --port=${port}`;
|
|
56
|
-
// console.log(cmd);
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
logger.info('Test: Running');
|
|
64
|
+
logger.debug(`Test: Executing "${cmd}"`);
|
|
59
65
|
|
|
60
66
|
const reportDir = path.resolve('dist/test-report');
|
|
61
67
|
fs.rmSync(reportDir, { recursive: true, force: true });
|
|
62
68
|
|
|
63
69
|
return new Promise((resolve, _reject) => {
|
|
64
|
-
execSh(cmd, { stdio: 'pipe', stderr: 'pipe' }, (err: any) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
const javaProcess = execSh(cmd, { stdio: 'pipe', stderr: 'pipe' }, (err: any) => {
|
|
71
|
+
if (err) {
|
|
72
|
+
logger.error(`Test: Failed with error ${err}`);
|
|
73
|
+
}
|
|
68
74
|
var testCases = parseJunitXML();
|
|
69
75
|
const total = testCases.length;
|
|
70
76
|
const success = testCases.filter((testcase: { [id: string]: any }) => testcase['system-out'] && !testcase['failure']).length;
|
|
@@ -72,6 +78,12 @@ const test = (host?: string, port?: string, specs?: string): Promise<{ [k: strin
|
|
|
72
78
|
var result = { total, success, failure };
|
|
73
79
|
resolve(result);
|
|
74
80
|
});
|
|
81
|
+
javaProcess.stdout.on('data', function (data: String) {
|
|
82
|
+
logger.debug(`Test: ${data}`);
|
|
83
|
+
});
|
|
84
|
+
javaProcess.stderr.on('data', function (data: String) {
|
|
85
|
+
logger.error(`Test: ${data}`);
|
|
86
|
+
});
|
|
75
87
|
});
|
|
76
88
|
};
|
|
77
89
|
|
|
@@ -85,26 +97,35 @@ const showTestResults = (testFn: (name: string, cb: () => void) => void) => {
|
|
|
85
97
|
});
|
|
86
98
|
};
|
|
87
99
|
|
|
88
|
-
const setExpectations = (stubPath: string, stubServerBaseUrl?: string): Promise<
|
|
100
|
+
const setExpectations = (stubPath: string, stubServerBaseUrl?: string): Promise<void> => {
|
|
89
101
|
const stubResponse = require(path.resolve(stubPath));
|
|
90
102
|
|
|
91
|
-
|
|
103
|
+
logger.info('Set Expectations: Running');
|
|
92
104
|
|
|
93
|
-
return new Promise((resolve,
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
94
106
|
fetch(`${stubServerBaseUrl ? stubServerBaseUrl : `http://localhost:9000/`}_specmatic/expectations`, {
|
|
95
107
|
method: 'POST',
|
|
96
108
|
body: JSON.stringify(stubResponse),
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
})
|
|
110
|
+
.then(() => {
|
|
111
|
+
logger.info('Set Expectations: Finished');
|
|
112
|
+
resolve();
|
|
113
|
+
})
|
|
114
|
+
.catch(err => {
|
|
115
|
+
logger.error(`Set Expectations: Failed with error ${err}`);
|
|
116
|
+
reject();
|
|
117
|
+
});
|
|
101
118
|
});
|
|
102
119
|
};
|
|
103
120
|
|
|
104
121
|
const printJarVersion = () => {
|
|
105
|
-
|
|
122
|
+
const cmd = `java -jar ${specmaticJarPath} --version`;
|
|
123
|
+
logger.info('Print Jar Version: Running');
|
|
124
|
+
logger.debug(`Print Jar Version: Executing "${cmd}"`);
|
|
125
|
+
|
|
126
|
+
execSh(cmd, {}, (err: any) => {
|
|
106
127
|
if (err) {
|
|
107
|
-
|
|
128
|
+
logger.error(`Print Jar Version: Failed with error ${err}`);
|
|
108
129
|
}
|
|
109
130
|
});
|
|
110
131
|
};
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createLogger, format, transports } from 'winston';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
|
|
4
|
+
const data = fs.readFileSync('./package.json');
|
|
5
|
+
const packageConfig = JSON.parse(data as unknown as string);
|
|
6
|
+
const specmaticConfig = packageConfig.specmatic || {};
|
|
7
|
+
|
|
8
|
+
const logFormat = format.printf(({ level, message, label, timestamp }) => {
|
|
9
|
+
return `[${label}] ${timestamp} ${level}: ${message}`;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export default createLogger({
|
|
13
|
+
level: specmaticConfig.logLevel || 'warn',
|
|
14
|
+
format: format.combine(format.label({ label: 'specmatic' }), format.timestamp({ format: 'DD-MM-YYYY HH:mm:ss' }), logFormat),
|
|
15
|
+
transports: [new transports.Console()],
|
|
16
|
+
});
|