@usebruno/js 0.13.0 → 0.15.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.
@@ -1,4 +1,4 @@
1
- const { NodeVM } = require('vm2');
1
+ const { NodeVM } = require('@usebruno/vm2');
2
2
  const chai = require('chai');
3
3
  const path = require('path');
4
4
  const http = require('http');
@@ -15,7 +15,7 @@ const BrunoRequest = require('../bruno-request');
15
15
  const BrunoResponse = require('../bruno-response');
16
16
  const Test = require('../test');
17
17
  const TestResults = require('../test-results');
18
- const { cleanJson } = require('../utils');
18
+ const { cleanJson, appendAwaitToTestFunc } = require('../utils');
19
19
 
20
20
  // Inbuilt Library Support
21
21
  const ajv = require('ajv');
@@ -29,17 +29,20 @@ const nanoid = require('nanoid');
29
29
  const axios = require('axios');
30
30
  const fetch = require('node-fetch');
31
31
  const CryptoJS = require('crypto-js');
32
- const NodeSecrets = require('node-vault');
32
+ const NodeVault = require('node-vault');
33
+ const { executeQuickJsVmAsync } = require('../sandbox/quickjs');
33
34
 
34
35
  class TestRuntime {
35
- constructor() {}
36
+ constructor(props) {
37
+ this.runtime = props?.runtime || 'vm2';
38
+ }
36
39
 
37
40
  async runTests(
38
41
  testsFile,
39
42
  request,
40
43
  response,
41
44
  envVariables,
42
- collectionVariables,
45
+ runtimeVariables,
43
46
  collectionPath,
44
47
  onConsoleLog,
45
48
  processEnvVars,
@@ -47,14 +50,16 @@ class TestRuntime {
47
50
  historyLogger,
48
51
  secretVariables
49
52
  ) {
53
+ const requestVariables = request?.requestVariables || {};
50
54
  const bru = new Bru(
51
55
  envVariables,
52
- collectionVariables,
56
+ runtimeVariables,
53
57
  processEnvVars,
54
58
  collectionPath,
55
59
  historyLogger,
56
- undefined, // setHtmlVisualizationString
57
- secretVariables
60
+ undefined, // setVisualizations
61
+ secretVariables,
62
+ requestVariables
58
63
  );
59
64
  const req = new BrunoRequest(request, historyLogger);
60
65
  const res = new BrunoResponse(response);
@@ -84,11 +89,15 @@ class TestRuntime {
84
89
  return {
85
90
  request,
86
91
  envVariables,
87
- collectionVariables,
88
- results: __brunoTestResults.getResults()
92
+ runtimeVariables,
93
+ results: __brunoTestResults.getResults(),
94
+ nextRequestName: bru.nextRequest
89
95
  };
90
96
  }
91
97
 
98
+ // add 'await' prefix to the test function calls
99
+ testsFile = appendAwaitToTestFunc(testsFile);
100
+
92
101
  const context = {
93
102
  test,
94
103
  bru,
@@ -109,48 +118,56 @@ class TestRuntime {
109
118
  log: customLogger('log'),
110
119
  info: customLogger('info'),
111
120
  warn: customLogger('warn'),
121
+ debug: customLogger('debug'),
112
122
  error: customLogger('error')
113
123
  };
114
124
  }
115
125
 
116
- const vm = new NodeVM({
117
- sandbox: context,
118
- require: {
119
- context: 'sandbox',
120
- external: true,
121
- root: [collectionPath, ...additionalContextRootsAbsolute],
122
- mock: {
123
- // node libs
124
- path,
125
- stream,
126
- util,
127
- url,
128
- http,
129
- https,
130
- punycode,
131
- zlib,
132
- // 3rd party libs
133
- ajv,
134
- 'ajv-formats': addFormats,
135
- btoa,
136
- atob,
137
- lodash,
138
- moment,
139
- uuid,
140
- nanoid,
141
- axios,
142
- chai,
143
- 'node-fetch': fetch,
144
- 'crypto-js': CryptoJS,
145
- ...whitelistedModules,
146
- fs: allowScriptFilesystemAccess ? fs : undefined,
147
- 'node-vault': NodeSecrets
126
+ if (this.runtime === 'quickjs') {
127
+ await executeQuickJsVmAsync({
128
+ script: testsFile,
129
+ context: context
130
+ });
131
+ } else {
132
+ // default runtime is vm2
133
+ const vm = new NodeVM({
134
+ sandbox: context,
135
+ require: {
136
+ context: 'sandbox',
137
+ external: true,
138
+ root: [collectionPath, ...additionalContextRootsAbsolute],
139
+ mock: {
140
+ // node libs
141
+ path,
142
+ stream,
143
+ util,
144
+ url,
145
+ http,
146
+ https,
147
+ punycode,
148
+ zlib,
149
+ // 3rd party libs
150
+ ajv,
151
+ 'ajv-formats': addFormats,
152
+ btoa,
153
+ atob,
154
+ lodash,
155
+ moment,
156
+ uuid,
157
+ nanoid,
158
+ axios,
159
+ chai,
160
+ 'node-fetch': fetch,
161
+ 'crypto-js': CryptoJS,
162
+ ...whitelistedModules,
163
+ fs: allowScriptFilesystemAccess ? fs : undefined,
164
+ 'node-vault': NodeVault
165
+ }
148
166
  }
149
- }
150
- });
151
-
152
- const asyncVM = vm.run(`module.exports = async () => { ${testsFile}}`, path.join(collectionPath, 'vm.js'));
153
- await asyncVM();
167
+ });
168
+ const asyncVM = vm.run(`module.exports = async () => { ${testsFile}}`, path.join(collectionPath, 'vm.js'));
169
+ await asyncVM();
170
+ }
154
171
 
155
172
  if (historyLogger) {
156
173
  historyLogger({
@@ -164,8 +181,9 @@ class TestRuntime {
164
181
  return {
165
182
  request,
166
183
  envVariables: cleanJson(envVariables),
167
- collectionVariables: cleanJson(collectionVariables),
168
- results: cleanJson(__brunoTestResults.getResults())
184
+ runtimeVariables: cleanJson(runtimeVariables),
185
+ results: cleanJson(__brunoTestResults.getResults()),
186
+ nextRequestName: bru.nextRequest
169
187
  };
170
188
  }
171
189
  }
@@ -3,17 +3,42 @@ const Bru = require('../bru');
3
3
  const BrunoRequest = require('../bruno-request');
4
4
  const { evaluateJsTemplateLiteral, evaluateJsExpression, createResponseParser } = require('../utils');
5
5
 
6
+ const { executeQuickJsVm } = require('../sandbox/quickjs');
7
+
8
+ const evaluateJsTemplateLiteralBasedOnRuntime = (literal, context, runtime) => {
9
+ if (runtime === 'quickjs') {
10
+ return executeQuickJsVm({
11
+ script: literal,
12
+ context,
13
+ scriptType: 'template-literal'
14
+ });
15
+ }
16
+
17
+ return evaluateJsTemplateLiteral(literal, context);
18
+ };
19
+
20
+ const evaluateJsExpressionBasedOnRuntime = (expr, context, runtime, mode) => {
21
+ if (runtime === 'quickjs') {
22
+ return executeQuickJsVm({
23
+ script: expr,
24
+ context,
25
+ scriptType: 'expression'
26
+ });
27
+ }
28
+
29
+ return evaluateJsExpression(expr, context);
30
+ };
31
+
6
32
  class VarsRuntime {
7
- runPreRequestVars(
8
- vars,
9
- request,
10
- envVariables,
11
- collectionVariables,
12
- collectionPath,
13
- processEnvVars,
14
- historyLogger,
15
- secretVars = {}
16
- ) {
33
+ constructor(props) {
34
+ this.runtime = props?.runtime || 'vm2';
35
+ this.mode = props?.mode || 'developer';
36
+ }
37
+
38
+ runPreRequestVars(vars, request, envVariables, runtimeVariables, collectionPath, processEnvVars, historyLogger, secretVars = {}) {
39
+ if (!request?.requestVariables) {
40
+ request.requestVariables = {};
41
+ }
17
42
  const enabledVars = _.filter(vars, (v) => v.enabled);
18
43
  if (!enabledVars.length) {
19
44
  return;
@@ -21,12 +46,13 @@ class VarsRuntime {
21
46
 
22
47
  const bru = new Bru(
23
48
  envVariables,
24
- collectionVariables,
49
+ runtimeVariables,
25
50
  processEnvVars,
26
51
  null,
27
52
  historyLogger,
28
- undefined, // setHtmlVisualizationString
29
- secretVars
53
+ undefined, // setVisualizations
54
+ secretVars,
55
+ undefined, // requestVariables
30
56
  );
31
57
  const req = new BrunoRequest(request, historyLogger);
32
58
 
@@ -37,19 +63,15 @@ class VarsRuntime {
37
63
 
38
64
  const context = {
39
65
  ...envVariables,
40
- ...collectionVariables,
66
+ ...runtimeVariables,
41
67
  ...secretVars,
42
68
  ...bruContext
43
69
  };
44
70
 
45
71
  _.each(enabledVars, (v) => {
46
- const value = evaluateJsTemplateLiteral(v.value, context);
47
- bru.setVar(v.name, value);
72
+ const value = evaluateJsTemplateLiteralBasedOnRuntime(v.value, context, this.runtime);
73
+ request?.requestVariables && (request.requestVariables[v.name] = value);
48
74
  });
49
-
50
- return {
51
- collectionVariables
52
- };
53
75
  }
54
76
 
55
77
  runPostResponseVars(
@@ -57,12 +79,13 @@ class VarsRuntime {
57
79
  request,
58
80
  response,
59
81
  envVariables,
60
- collectionVariables,
82
+ runtimeVariables,
61
83
  collectionPath,
62
84
  processEnvVars,
63
85
  historyLogger,
64
86
  secretVars = {}
65
87
  ) {
88
+ const requestVariables = request?.requestVariables || {};
66
89
  const enabledVars = _.filter(vars, (v) => v.enabled);
67
90
  if (!enabledVars.length) {
68
91
  return;
@@ -70,12 +93,13 @@ class VarsRuntime {
70
93
 
71
94
  const bru = new Bru(
72
95
  envVariables,
73
- collectionVariables,
96
+ runtimeVariables,
74
97
  processEnvVars,
75
98
  null,
76
99
  historyLogger,
77
- undefined, // setHtmlVisualizationString
78
- secretVars
100
+ undefined, // setVisualizations
101
+ secretVars,
102
+ requestVariables
79
103
  );
80
104
  const req = new BrunoRequest(request, historyLogger);
81
105
  const res = createResponseParser(response);
@@ -88,19 +112,32 @@ class VarsRuntime {
88
112
 
89
113
  const context = {
90
114
  ...envVariables,
91
- ...collectionVariables,
115
+ ...runtimeVariables,
92
116
  ...secretVars,
93
117
  ...bruContext
94
118
  };
95
119
 
120
+ const errors = new Map();
96
121
  _.each(enabledVars, (v) => {
97
- const value = evaluateJsExpression(v.value, context);
98
- bru.setVar(v.name, value);
122
+ try {
123
+ const value = evaluateJsExpressionBasedOnRuntime(v.value, context, this.runtime);
124
+ bru.setVar(v.name, value);
125
+ } catch (error) {
126
+ errors.set(v.name, error);
127
+ }
99
128
  });
100
129
 
130
+ let error = null;
131
+ if (errors.size > 0) {
132
+ // Format all errors as a single string to be displayed in a toast
133
+ const errorMessage = [...errors.entries()].map(([name, err]) => `${name}: ${err.message ?? err}`).join('\n');
134
+ error = `${errors.size} error${errors.size === 1 ? '' : 's'} in post response variables: \n${errorMessage}`;
135
+ }
136
+
101
137
  return {
102
138
  envVariables,
103
- collectionVariables
139
+ runtimeVariables,
140
+ error
104
141
  };
105
142
  }
106
143
  }