@usebruno/js 0.22.0 → 0.24.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/package.json +3 -3
- package/src/bru.js +11 -0
- package/src/runtime/assert-runtime.js +8 -0
- package/src/runtime/script-runtime.js +24 -6
- package/src/runtime/test-runtime.js +57 -1
- package/src/sandbox/bundle-libraries.js +1 -1
- package/src/sandbox/quickjs/shims/bru.js +85 -0
- package/src/utils.js +6 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usebruno/js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@usebruno/common": "0.3.0",
|
|
19
|
+
"@usebruno/crypto-js": "^3.1.9",
|
|
19
20
|
"@usebruno/query": "0.1.0",
|
|
20
21
|
"ajv": "^8.12.0",
|
|
21
22
|
"ajv-formats": "^2.1.1",
|
|
@@ -25,11 +26,10 @@
|
|
|
25
26
|
"chai": "^4.3.7",
|
|
26
27
|
"chai-string": "^1.5.0",
|
|
27
28
|
"crypto-js": "^4.1.1",
|
|
28
|
-
"crypto-js-3.1.9-1": "npm:crypto-js@^3.1.9-1",
|
|
29
29
|
"json-query": "^2.2.2",
|
|
30
30
|
"lodash": "^4.17.21",
|
|
31
31
|
"moment": "^2.29.4",
|
|
32
|
-
"nanoid": "3.3.
|
|
32
|
+
"nanoid": "3.3.8",
|
|
33
33
|
"node-fetch": "2.7.0",
|
|
34
34
|
"node-vault": "^0.10.2",
|
|
35
35
|
"path": "^0.12.7",
|
package/src/bru.js
CHANGED
|
@@ -17,6 +17,17 @@ class Bru {
|
|
|
17
17
|
this.collectionPath = collectionPath;
|
|
18
18
|
this.historyLogger = historyLogger;
|
|
19
19
|
this.setVisualizations = setVisualizations;
|
|
20
|
+
this.runner = {
|
|
21
|
+
skipRequest: () => {
|
|
22
|
+
this.skipRequest = true;
|
|
23
|
+
},
|
|
24
|
+
stopExecution: () => {
|
|
25
|
+
this.stopExecution = true;
|
|
26
|
+
},
|
|
27
|
+
setNextRequest: (nextRequest) => {
|
|
28
|
+
this.nextRequest = nextRequest;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
20
31
|
}
|
|
21
32
|
|
|
22
33
|
_interpolate = (str) => {
|
|
@@ -58,6 +58,7 @@ chai.use(function (chai, utils) {
|
|
|
58
58
|
* endsWith : ends with
|
|
59
59
|
* between : between
|
|
60
60
|
* isEmpty : is empty
|
|
61
|
+
* isNotEmpty : is not empty
|
|
61
62
|
* isNull : is null
|
|
62
63
|
* isUndefined : is undefined
|
|
63
64
|
* isDefined : is defined
|
|
@@ -95,6 +96,7 @@ const parseAssertionOperator = (str = '') => {
|
|
|
95
96
|
'endsWith',
|
|
96
97
|
'between',
|
|
97
98
|
'isEmpty',
|
|
99
|
+
'isNotEmpty',
|
|
98
100
|
'isNull',
|
|
99
101
|
'isUndefined',
|
|
100
102
|
'isDefined',
|
|
@@ -109,6 +111,7 @@ const parseAssertionOperator = (str = '') => {
|
|
|
109
111
|
|
|
110
112
|
const unaryOperators = [
|
|
111
113
|
'isEmpty',
|
|
114
|
+
'isNotEmpty',
|
|
112
115
|
'isNull',
|
|
113
116
|
'isUndefined',
|
|
114
117
|
'isDefined',
|
|
@@ -147,6 +150,7 @@ const parseAssertionOperator = (str = '') => {
|
|
|
147
150
|
const isUnaryOperator = (operator) => {
|
|
148
151
|
const unaryOperators = [
|
|
149
152
|
'isEmpty',
|
|
153
|
+
'isNotEmpty',
|
|
150
154
|
'isNull',
|
|
151
155
|
'isUndefined',
|
|
152
156
|
'isDefined',
|
|
@@ -348,6 +352,9 @@ class AssertRuntime {
|
|
|
348
352
|
case 'isEmpty':
|
|
349
353
|
expect(lhs).to.be.empty;
|
|
350
354
|
break;
|
|
355
|
+
case 'isNotEmpty':
|
|
356
|
+
expect(lhs).to.not.be.empty;
|
|
357
|
+
break;
|
|
351
358
|
case 'isNull':
|
|
352
359
|
expect(lhs).to.be.null;
|
|
353
360
|
break;
|
|
@@ -412,6 +419,7 @@ class AssertRuntime {
|
|
|
412
419
|
createdAt: new Date().toISOString()
|
|
413
420
|
});
|
|
414
421
|
}
|
|
422
|
+
request.assertionResults = assertionResults;
|
|
415
423
|
|
|
416
424
|
return assertionResults;
|
|
417
425
|
}
|
|
@@ -47,7 +47,8 @@ class ScriptRuntime {
|
|
|
47
47
|
processEnvVars,
|
|
48
48
|
scriptingConfig,
|
|
49
49
|
historyLogger,
|
|
50
|
-
secretVariables
|
|
50
|
+
secretVariables,
|
|
51
|
+
runRequestByItemPathname
|
|
51
52
|
) {
|
|
52
53
|
let visualizations = [];
|
|
53
54
|
let setVisualizations = (data) => {
|
|
@@ -98,6 +99,10 @@ class ScriptRuntime {
|
|
|
98
99
|
};
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
if(runRequestByItemPathname) {
|
|
103
|
+
context.bru.runRequest = runRequestByItemPathname;
|
|
104
|
+
}
|
|
105
|
+
|
|
101
106
|
if (this.runtime === 'quickjs') {
|
|
102
107
|
await executeQuickJsVmAsync({
|
|
103
108
|
script: script,
|
|
@@ -111,7 +116,9 @@ class ScriptRuntime {
|
|
|
111
116
|
runtimeVariables: cleanJson(runtimeVariables),
|
|
112
117
|
visualizations,
|
|
113
118
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
|
114
|
-
nextRequestName: bru.nextRequest
|
|
119
|
+
nextRequestName: bru.nextRequest,
|
|
120
|
+
skipRequest: bru.skipRequest,
|
|
121
|
+
stopExecution: bru.stopExecution
|
|
115
122
|
};
|
|
116
123
|
}
|
|
117
124
|
|
|
@@ -160,7 +167,9 @@ class ScriptRuntime {
|
|
|
160
167
|
runtimeVariables: cleanJson(runtimeVariables),
|
|
161
168
|
visualizations,
|
|
162
169
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
|
163
|
-
nextRequestName: bru.nextRequest
|
|
170
|
+
nextRequestName: bru.nextRequest,
|
|
171
|
+
skipRequest: bru.skipRequest,
|
|
172
|
+
stopExecution: bru.stopExecution
|
|
164
173
|
};
|
|
165
174
|
}
|
|
166
175
|
|
|
@@ -175,7 +184,8 @@ class ScriptRuntime {
|
|
|
175
184
|
processEnvVars,
|
|
176
185
|
scriptingConfig,
|
|
177
186
|
historyLogger,
|
|
178
|
-
secretVariables
|
|
187
|
+
secretVariables,
|
|
188
|
+
runRequestByItemPathname
|
|
179
189
|
) {
|
|
180
190
|
let visualizations = [];
|
|
181
191
|
let setVisualizations = (data) => {
|
|
@@ -223,6 +233,10 @@ class ScriptRuntime {
|
|
|
223
233
|
};
|
|
224
234
|
}
|
|
225
235
|
|
|
236
|
+
if(runRequestByItemPathname) {
|
|
237
|
+
context.bru.runRequest = runRequestByItemPathname;
|
|
238
|
+
}
|
|
239
|
+
|
|
226
240
|
if (this.runtime === 'quickjs') {
|
|
227
241
|
await executeQuickJsVmAsync({
|
|
228
242
|
script: script,
|
|
@@ -236,7 +250,9 @@ class ScriptRuntime {
|
|
|
236
250
|
runtimeVariables: cleanJson(runtimeVariables),
|
|
237
251
|
visualizations,
|
|
238
252
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
|
239
|
-
nextRequestName: bru.nextRequest
|
|
253
|
+
nextRequestName: bru.nextRequest,
|
|
254
|
+
skipRequest: bru.skipRequest,
|
|
255
|
+
stopExecution: bru.stopExecution
|
|
240
256
|
};
|
|
241
257
|
}
|
|
242
258
|
|
|
@@ -285,7 +301,9 @@ class ScriptRuntime {
|
|
|
285
301
|
runtimeVariables: cleanJson(runtimeVariables),
|
|
286
302
|
visualizations,
|
|
287
303
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
|
288
|
-
nextRequestName: bru.nextRequest
|
|
304
|
+
nextRequestName: bru.nextRequest,
|
|
305
|
+
skipRequest: bru.skipRequest,
|
|
306
|
+
stopExecution: bru.stopExecution
|
|
289
307
|
};
|
|
290
308
|
}
|
|
291
309
|
}
|
|
@@ -32,6 +32,25 @@ const CryptoJS = require('crypto-js');
|
|
|
32
32
|
const NodeVault = require('node-vault');
|
|
33
33
|
const { executeQuickJsVmAsync } = require('../sandbox/quickjs');
|
|
34
34
|
|
|
35
|
+
const getResultsSummary = (results) => {
|
|
36
|
+
const summary = {
|
|
37
|
+
total: results.length,
|
|
38
|
+
passed: 0,
|
|
39
|
+
failed: 0,
|
|
40
|
+
skipped: 0,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
results.forEach((r) => {
|
|
44
|
+
const passed = r.status === "pass";
|
|
45
|
+
if (passed) summary.passed += 1;
|
|
46
|
+
else if (r.status === "fail") summary.failed += 1;
|
|
47
|
+
else summary.skipped += 1;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return summary;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
35
54
|
class TestRuntime {
|
|
36
55
|
constructor(props) {
|
|
37
56
|
this.runtime = props?.runtime || 'vm2';
|
|
@@ -48,12 +67,14 @@ class TestRuntime {
|
|
|
48
67
|
processEnvVars,
|
|
49
68
|
scriptingConfig,
|
|
50
69
|
historyLogger,
|
|
51
|
-
secretVariables
|
|
70
|
+
secretVariables,
|
|
71
|
+
runRequestByItemPathname
|
|
52
72
|
) {
|
|
53
73
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
|
54
74
|
const collectionVariables = request?.collectionVariables || {};
|
|
55
75
|
const folderVariables = request?.folderVariables || {};
|
|
56
76
|
const requestVariables = request?.requestVariables || {};
|
|
77
|
+
const assertionResults = request?.assertionResults || [];
|
|
57
78
|
const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, historyLogger, undefined, secretVariables, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables);
|
|
58
79
|
const req = new BrunoRequest(request, historyLogger);
|
|
59
80
|
const res = new BrunoResponse(response);
|
|
@@ -77,6 +98,7 @@ class TestRuntime {
|
|
|
77
98
|
}
|
|
78
99
|
|
|
79
100
|
const __brunoTestResults = new TestResults();
|
|
101
|
+
|
|
80
102
|
const test = Test(__brunoTestResults, chai);
|
|
81
103
|
|
|
82
104
|
if (!testsFile || !testsFile.length) {
|
|
@@ -90,6 +112,36 @@ class TestRuntime {
|
|
|
90
112
|
};
|
|
91
113
|
}
|
|
92
114
|
|
|
115
|
+
bru.getTestResults = async () => {
|
|
116
|
+
let results = await __brunoTestResults.getResults();
|
|
117
|
+
const summary = getResultsSummary(results);
|
|
118
|
+
return {
|
|
119
|
+
summary,
|
|
120
|
+
results: results?.map?.(r => ({
|
|
121
|
+
status: r?.status,
|
|
122
|
+
description: r?.description,
|
|
123
|
+
expected: r?.expected,
|
|
124
|
+
actual: r?.actual,
|
|
125
|
+
error: r?.error
|
|
126
|
+
}))
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
bru.getAssertionResults = async () => {
|
|
130
|
+
let results = assertionResults;
|
|
131
|
+
const summary = getResultsSummary(results);
|
|
132
|
+
return {
|
|
133
|
+
summary,
|
|
134
|
+
results: results?.map?.(r => ({
|
|
135
|
+
status: r?.status,
|
|
136
|
+
lhsExpr: r?.lhsExpr,
|
|
137
|
+
rhsExpr: r?.rhsExpr,
|
|
138
|
+
operator: r?.operator,
|
|
139
|
+
rhsOperand: r?.rhsOperand,
|
|
140
|
+
error: r?.error
|
|
141
|
+
}))
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
93
145
|
const context = {
|
|
94
146
|
test,
|
|
95
147
|
bru,
|
|
@@ -115,6 +167,10 @@ class TestRuntime {
|
|
|
115
167
|
};
|
|
116
168
|
}
|
|
117
169
|
|
|
170
|
+
if(runRequestByItemPathname) {
|
|
171
|
+
context.bru.runRequest = runRequestByItemPathname;
|
|
172
|
+
}
|
|
173
|
+
|
|
118
174
|
if (this.runtime === 'quickjs') {
|
|
119
175
|
await executeQuickJsVmAsync({
|
|
120
176
|
script: testsFile,
|
|
@@ -11,7 +11,7 @@ const bundleLibraries = async () => {
|
|
|
11
11
|
import moment from "moment";
|
|
12
12
|
import btoa from "btoa";
|
|
13
13
|
import atob from "atob";
|
|
14
|
-
import * as CryptoJS from "crypto-js
|
|
14
|
+
import * as CryptoJS from "@usebruno/crypto-js";
|
|
15
15
|
globalThis.expect = expect;
|
|
16
16
|
globalThis.assert = assert;
|
|
17
17
|
globalThis.moment = moment;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
const { cleanJson } = require('../../../utils');
|
|
1
2
|
const { marshallToVm } = require('../utils');
|
|
2
3
|
|
|
3
4
|
const addBruShimToContext = (vm, bru) => {
|
|
4
5
|
const bruObject = vm.newObject();
|
|
6
|
+
const bruRunnerObject = vm.newObject();
|
|
5
7
|
|
|
6
8
|
let cwd = vm.newFunction('cwd', function () {
|
|
7
9
|
return marshallToVm(bru.cwd(), vm);
|
|
@@ -93,6 +95,24 @@ const addBruShimToContext = (vm, bru) => {
|
|
|
93
95
|
vm.setProp(bruObject, 'setNextRequest', setNextRequest);
|
|
94
96
|
setNextRequest.dispose();
|
|
95
97
|
|
|
98
|
+
let runnerSkipRequest = vm.newFunction('skipRequest', function () {
|
|
99
|
+
bru?.runner?.skipRequest();
|
|
100
|
+
});
|
|
101
|
+
vm.setProp(bruRunnerObject, 'skipRequest', runnerSkipRequest);
|
|
102
|
+
runnerSkipRequest.dispose();
|
|
103
|
+
|
|
104
|
+
let runnerStopExecution = vm.newFunction('stopExecution', function () {
|
|
105
|
+
bru?.runner?.stopExecution();
|
|
106
|
+
});
|
|
107
|
+
vm.setProp(bruRunnerObject, 'stopExecution', runnerStopExecution);
|
|
108
|
+
runnerStopExecution.dispose();
|
|
109
|
+
|
|
110
|
+
let runnerSetNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
|
|
111
|
+
bru?.runner?.setNextRequest(vm.dump(nextRequest));
|
|
112
|
+
});
|
|
113
|
+
vm.setProp(bruRunnerObject, 'setNextRequest', runnerSetNextRequest);
|
|
114
|
+
runnerSetNextRequest.dispose();
|
|
115
|
+
|
|
96
116
|
let visualize = vm.newFunction('visualize', function (type, data) {
|
|
97
117
|
bru.visualize(vm.dump(type), vm.dump(data));
|
|
98
118
|
});
|
|
@@ -123,6 +143,70 @@ const addBruShimToContext = (vm, bru) => {
|
|
|
123
143
|
vm.setProp(bruObject, 'getCollectionVar', getCollectionVar);
|
|
124
144
|
getCollectionVar.dispose();
|
|
125
145
|
|
|
146
|
+
let getTestResults = vm.newFunction('getTestResults', () => {
|
|
147
|
+
const promise = vm.newPromise();
|
|
148
|
+
bru.getTestResults()
|
|
149
|
+
.then((results) => {
|
|
150
|
+
promise.resolve(marshallToVm(cleanJson(results), vm));
|
|
151
|
+
})
|
|
152
|
+
.catch((err) => {
|
|
153
|
+
promise.resolve(
|
|
154
|
+
marshallToVm(
|
|
155
|
+
cleanJson({
|
|
156
|
+
message: err.message
|
|
157
|
+
}),
|
|
158
|
+
vm
|
|
159
|
+
)
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
promise.settled.then(vm.runtime.executePendingJobs);
|
|
163
|
+
return promise.handle;
|
|
164
|
+
});
|
|
165
|
+
getTestResults.consume((handle) => vm.setProp(bruObject, 'getTestResults', handle));
|
|
166
|
+
|
|
167
|
+
let getAssertionResults = vm.newFunction('getAssertionResults', () => {
|
|
168
|
+
const promise = vm.newPromise();
|
|
169
|
+
bru.getAssertionResults()
|
|
170
|
+
.then((results) => {
|
|
171
|
+
promise.resolve(marshallToVm(cleanJson(results), vm));
|
|
172
|
+
})
|
|
173
|
+
.catch((err) => {
|
|
174
|
+
promise.resolve(
|
|
175
|
+
marshallToVm(
|
|
176
|
+
cleanJson({
|
|
177
|
+
message: err.message
|
|
178
|
+
}),
|
|
179
|
+
vm
|
|
180
|
+
)
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
promise.settled.then(vm.runtime.executePendingJobs);
|
|
184
|
+
return promise.handle;
|
|
185
|
+
});
|
|
186
|
+
getAssertionResults.consume((handle) => vm.setProp(bruObject, 'getAssertionResults', handle));
|
|
187
|
+
|
|
188
|
+
let runRequestHandle = vm.newFunction('runRequest', (args) => {
|
|
189
|
+
const promise = vm.newPromise();
|
|
190
|
+
bru.runRequest(vm.dump(args))
|
|
191
|
+
.then((response) => {
|
|
192
|
+
const { status, headers, data, dataBuffer, size } = response || {};
|
|
193
|
+
promise.resolve(marshallToVm(cleanJson({ status, headers, data, dataBuffer, size }), vm));
|
|
194
|
+
})
|
|
195
|
+
.catch((err) => {
|
|
196
|
+
promise.resolve(
|
|
197
|
+
marshallToVm(
|
|
198
|
+
cleanJson({
|
|
199
|
+
message: err.message
|
|
200
|
+
}),
|
|
201
|
+
vm
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
promise.settled.then(vm.runtime.executePendingJobs);
|
|
206
|
+
return promise.handle;
|
|
207
|
+
});
|
|
208
|
+
runRequestHandle.consume((handle) => vm.setProp(bruObject, 'runRequest', handle));
|
|
209
|
+
|
|
126
210
|
const sleep = vm.newFunction('sleep', (timer) => {
|
|
127
211
|
const t = vm.getString(timer);
|
|
128
212
|
const promise = vm.newPromise();
|
|
@@ -134,6 +218,7 @@ const addBruShimToContext = (vm, bru) => {
|
|
|
134
218
|
});
|
|
135
219
|
sleep.consume((handle) => vm.setProp(bruObject, 'sleep', handle));
|
|
136
220
|
|
|
221
|
+
vm.setProp(bruObject, 'runner', bruRunnerObject);
|
|
137
222
|
vm.setProp(vm.global, 'bru', bruObject);
|
|
138
223
|
bruObject.dispose();
|
|
139
224
|
};
|
package/src/utils.js
CHANGED
|
@@ -19,8 +19,8 @@ const JS_KEYWORDS = `
|
|
|
19
19
|
* ```js
|
|
20
20
|
* res.data.pets.map(pet => pet.name.toUpperCase())
|
|
21
21
|
*
|
|
22
|
-
* function(
|
|
23
|
-
* const { res, pet } =
|
|
22
|
+
* function(__bruno__functionInnerContext) {
|
|
23
|
+
* const { res, pet } = __bruno__functionInnerContext;
|
|
24
24
|
* return res.data.pets.map(pet => pet.name.toUpperCase())
|
|
25
25
|
* }
|
|
26
26
|
* ```
|
|
@@ -46,9 +46,11 @@ const compileJsExpression = (expr) => {
|
|
|
46
46
|
globals: globals.map((name) => ` ${name} = ${name} ?? globalThis.${name};`).join('')
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
// param name that is unlikely to show up as a var in an expression
|
|
50
|
+
const param = `__bruno__functionInnerContext`;
|
|
51
|
+
const body = `let { ${code.vars} } = ${param}; ${code.globals}; return ${expr}`;
|
|
50
52
|
|
|
51
|
-
return new Function(
|
|
53
|
+
return new Function(param, body);
|
|
52
54
|
};
|
|
53
55
|
|
|
54
56
|
const internalExpressionCache = new Map();
|