@usebruno/js 0.4.0 → 0.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usebruno/js",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "main": "src/index.js",
5
5
  "files": [
6
6
  "src",
package/src/bru.js CHANGED
@@ -1,8 +1,11 @@
1
-
2
1
  class Bru {
3
2
  constructor(envVariables, collectionVariables) {
4
- this._envVariables = envVariables;
5
- this._collectionVariables = collectionVariables;
3
+ this.envVariables = envVariables;
4
+ this.collectionVariables = collectionVariables;
5
+ }
6
+
7
+ getEnvName() {
8
+ return this.envVariables.__name__;
6
9
  }
7
10
 
8
11
  getProcessEnv(key) {
@@ -10,32 +13,32 @@ class Bru {
10
13
  }
11
14
 
12
15
  getEnvVar(key) {
13
- return this._envVariables[key];
16
+ return this.envVariables[key];
14
17
  }
15
18
 
16
19
  setEnvVar(key, value) {
17
- if(!key) {
20
+ if (!key) {
18
21
  throw new Error('Key is required');
19
22
  }
20
23
 
21
24
  // gracefully ignore if key is not present in environment
22
- if(!this._envVariables.hasOwnProperty(key)) {
23
- return;
25
+ if (!this.envVariables.hasOwnProperty(key)) {
26
+ return;
24
27
  }
25
28
 
26
- this._envVariables[key] = value;
29
+ this.envVariables[key] = value;
27
30
  }
28
31
 
29
32
  setVar(key, value) {
30
- if(!key) {
33
+ if (!key) {
31
34
  throw new Error('Key is required');
32
35
  }
33
36
 
34
- this._collectionVariables[key] = value;
37
+ this.collectionVariables[key] = value;
35
38
  }
36
39
 
37
40
  getVar(key) {
38
- return this._collectionVariables[key];
41
+ return this.collectionVariables[key];
39
42
  }
40
43
  }
41
44
 
@@ -46,6 +46,10 @@ class BrunoRequest {
46
46
  setBody(data) {
47
47
  this.req.data = data;
48
48
  }
49
+
50
+ setMaxRedirects(maxRedirects) {
51
+ this.req.maxRedirects = maxRedirects;
52
+ }
49
53
  }
50
54
 
51
- module.exports = BrunoRequest;
55
+ module.exports = BrunoRequest;
@@ -12,7 +12,7 @@ class BrunoResponse {
12
12
  }
13
13
 
14
14
  getHeader(name) {
15
- return (this.res && this.res.headers) ? this.res.headers[name] : null;
15
+ return this.res && this.res.headers ? this.res.headers[name] : null;
16
16
  }
17
17
 
18
18
  getHeaders() {
@@ -12,11 +12,7 @@ chai.use(function (chai, utils) {
12
12
  const obj = this._obj;
13
13
  const isJson = typeof obj === 'object' && obj !== null && !Array.isArray(obj) && obj.constructor === Object;
14
14
 
15
- this.assert(
16
- isJson,
17
- `expected ${utils.inspect(obj)} to be JSON`,
18
- `expected ${utils.inspect(obj)} not to be JSON`
19
- );
15
+ this.assert(isJson, `expected ${utils.inspect(obj)} to be JSON`, `expected ${utils.inspect(obj)} not to be JSON`);
20
16
  });
21
17
  });
22
18
 
@@ -25,7 +21,7 @@ chai.use(function (chai, utils) {
25
21
  chai.Assertion.addMethod('match', function (regex) {
26
22
  const obj = this._obj;
27
23
  let match = false;
28
- if(obj === undefined) {
24
+ if (obj === undefined) {
29
25
  match = false;
30
26
  } else {
31
27
  match = regex.test(obj);
@@ -41,7 +37,7 @@ chai.use(function (chai, utils) {
41
37
 
42
38
  /**
43
39
  * Assertion operators
44
- *
40
+ *
45
41
  * eq : equal to
46
42
  * neq : not equal to
47
43
  * gt : greater than
@@ -70,7 +66,7 @@ chai.use(function (chai, utils) {
70
66
  * isBoolean : is boolean
71
67
  */
72
68
  const parseAssertionOperator = (str = '') => {
73
- if(!str || typeof str !== 'string' || !str.length) {
69
+ if (!str || typeof str !== 'string' || !str.length) {
74
70
  return {
75
71
  operator: 'eq',
76
72
  value: str
@@ -78,27 +74,58 @@ const parseAssertionOperator = (str = '') => {
78
74
  }
79
75
 
80
76
  const operators = [
81
- 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn',
82
- 'contains', 'notContains', 'length', 'matches', 'notMatches',
83
- 'startsWith', 'endsWith', 'between', 'isEmpty', 'isNull', 'isUndefined',
84
- 'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
77
+ 'eq',
78
+ 'neq',
79
+ 'gt',
80
+ 'gte',
81
+ 'lt',
82
+ 'lte',
83
+ 'in',
84
+ 'notIn',
85
+ 'contains',
86
+ 'notContains',
87
+ 'length',
88
+ 'matches',
89
+ 'notMatches',
90
+ 'startsWith',
91
+ 'endsWith',
92
+ 'between',
93
+ 'isEmpty',
94
+ 'isNull',
95
+ 'isUndefined',
96
+ 'isDefined',
97
+ 'isTruthy',
98
+ 'isFalsy',
99
+ 'isJson',
100
+ 'isNumber',
101
+ 'isString',
102
+ 'isBoolean'
85
103
  ];
86
104
 
87
105
  const unaryOperators = [
88
- 'isEmpty', 'isNull', 'isUndefined', 'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
106
+ 'isEmpty',
107
+ 'isNull',
108
+ 'isUndefined',
109
+ 'isDefined',
110
+ 'isTruthy',
111
+ 'isFalsy',
112
+ 'isJson',
113
+ 'isNumber',
114
+ 'isString',
115
+ 'isBoolean'
89
116
  ];
90
117
 
91
118
  const [operator, ...rest] = str.trim().split(' ');
92
119
  const value = rest.join(' ');
93
120
 
94
- if(unaryOperators.includes(operator)) {
121
+ if (unaryOperators.includes(operator)) {
95
122
  return {
96
123
  operator,
97
124
  value: ''
98
125
  };
99
126
  }
100
127
 
101
- if(operators.includes(operator)) {
128
+ if (operators.includes(operator)) {
102
129
  return {
103
130
  operator,
104
131
  value
@@ -113,34 +140,43 @@ const parseAssertionOperator = (str = '') => {
113
140
 
114
141
  const isUnaryOperator = (operator) => {
115
142
  const unaryOperators = [
116
- 'isEmpty', 'isNull', 'isUndefined', 'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
143
+ 'isEmpty',
144
+ 'isNull',
145
+ 'isUndefined',
146
+ 'isDefined',
147
+ 'isTruthy',
148
+ 'isFalsy',
149
+ 'isJson',
150
+ 'isNumber',
151
+ 'isString',
152
+ 'isBoolean'
117
153
  ];
118
154
 
119
155
  return unaryOperators.includes(operator);
120
156
  };
121
157
 
122
158
  const evaluateRhsOperand = (rhsOperand, operator, context) => {
123
- if(isUnaryOperator(operator)) {
159
+ if (isUnaryOperator(operator)) {
124
160
  return;
125
161
  }
126
162
 
127
163
  // gracefully allow both a,b as well as [a, b]
128
- if(operator === 'in' || operator === 'notIn') {
129
- if(rhsOperand.startsWith('[') && rhsOperand.endsWith(']')) {
164
+ if (operator === 'in' || operator === 'notIn') {
165
+ if (rhsOperand.startsWith('[') && rhsOperand.endsWith(']')) {
130
166
  rhsOperand = rhsOperand.substring(1, rhsOperand.length - 1);
131
167
  }
132
168
 
133
169
  return rhsOperand.split(',').map((v) => evaluateJsTemplateLiteral(v.trim(), context));
134
170
  }
135
171
 
136
- if(operator === 'between') {
172
+ if (operator === 'between') {
137
173
  const [lhs, rhs] = rhsOperand.split(',').map((v) => evaluateJsTemplateLiteral(v.trim(), context));
138
174
  return [lhs, rhs];
139
175
  }
140
176
 
141
177
  // gracefully allow both ^[a-Z] as well as /^[a-Z]/
142
- if(operator === 'matches' || operator === 'notMatches') {
143
- if(rhsOperand.startsWith('/') && rhsOperand.endsWith('/')) {
178
+ if (operator === 'matches' || operator === 'notMatches') {
179
+ if (rhsOperand.startsWith('/') && rhsOperand.endsWith('/')) {
144
180
  rhsOperand = rhsOperand.substring(1, rhsOperand.length - 1);
145
181
  }
146
182
 
@@ -153,7 +189,7 @@ const evaluateRhsOperand = (rhsOperand, operator, context) => {
153
189
  class AssertRuntime {
154
190
  runAssertions(assertions, request, response, envVariables, collectionVariables, collectionPath) {
155
191
  const enabledAssertions = _.filter(assertions, (a) => a.enabled);
156
- if(!enabledAssertions.length) {
192
+ if (!enabledAssertions.length) {
157
193
  return [];
158
194
  }
159
195
 
@@ -171,7 +207,7 @@ class AssertRuntime {
171
207
  ...envVariables,
172
208
  ...collectionVariables,
173
209
  ...bruContext
174
- }
210
+ };
175
211
 
176
212
  const assertionResults = [];
177
213
 
@@ -179,16 +215,13 @@ class AssertRuntime {
179
215
  for (const v of enabledAssertions) {
180
216
  const lhsExpr = v.name;
181
217
  const rhsExpr = v.value;
182
- const {
183
- operator,
184
- value: rhsOperand
185
- } = parseAssertionOperator(rhsExpr);
218
+ const { operator, value: rhsOperand } = parseAssertionOperator(rhsExpr);
186
219
 
187
220
  try {
188
221
  const lhs = evaluateJsExpression(lhsExpr, context);
189
222
  const rhs = evaluateRhsOperand(rhsOperand, operator, context);
190
223
 
191
- switch(operator) {
224
+ switch (operator) {
192
225
  case 'eq':
193
226
  expect(lhs).to.equal(rhs);
194
227
  break;
@@ -281,8 +314,7 @@ class AssertRuntime {
281
314
  operator,
282
315
  status: 'pass'
283
316
  });
284
- }
285
- catch (err) {
317
+ } catch (err) {
286
318
  assertionResults.push({
287
319
  uid: nanoid(),
288
320
  lhsExpr,
@@ -10,6 +10,7 @@ const punycode = require('punycode');
10
10
  const Bru = require('../bru');
11
11
  const BrunoRequest = require('../bruno-request');
12
12
  const BrunoResponse = require('../bruno-response');
13
+ const { cleanJson } = require('../utils');
13
14
 
14
15
  // Inbuilt Library Support
15
16
  const atob = require('atob');
@@ -23,16 +24,31 @@ const fetch = require('node-fetch');
23
24
  const CryptoJS = require('crypto-js');
24
25
 
25
26
  class ScriptRuntime {
26
- constructor() {
27
- }
27
+ constructor() {}
28
28
 
29
- async runRequestScript(script, request, envVariables, collectionVariables, collectionPath){
29
+ async runRequestScript(script, request, envVariables, collectionVariables, collectionPath, onConsoleLog) {
30
30
  const bru = new Bru(envVariables, collectionVariables);
31
31
  const req = new BrunoRequest(request);
32
+
32
33
  const context = {
33
34
  bru,
34
35
  req
35
36
  };
37
+
38
+ if (onConsoleLog && typeof onConsoleLog === 'function') {
39
+ const customLogger = (type) => {
40
+ return (...args) => {
41
+ onConsoleLog(type, cleanJson(args));
42
+ };
43
+ };
44
+ context.console = {
45
+ log: customLogger('log'),
46
+ info: customLogger('info'),
47
+ warn: customLogger('warn'),
48
+ error: customLogger('error')
49
+ };
50
+ }
51
+
36
52
  const vm = new NodeVM({
37
53
  sandbox: context,
38
54
  require: {
@@ -62,16 +78,16 @@ class ScriptRuntime {
62
78
  }
63
79
  }
64
80
  });
65
- const asyncVM = vm.run(`module.exports = async () => { ${script} }`, path.join(collectionPath, 'vm.js'));
81
+ const asyncVM = vm.run(`module.exports = async () => { ${script} }`, path.join(collectionPath, 'vm.js'));
66
82
  await asyncVM();
67
83
  return {
68
84
  request,
69
- envVariables,
70
- collectionVariables
85
+ envVariables: cleanJson(envVariables),
86
+ collectionVariables: cleanJson(collectionVariables)
71
87
  };
72
88
  }
73
89
 
74
- async runResponseScript(script, request, response, envVariables, collectionVariables, collectionPath) {
90
+ async runResponseScript(script, request, response, envVariables, collectionVariables, collectionPath, onConsoleLog) {
75
91
  const bru = new Bru(envVariables, collectionVariables);
76
92
  const req = new BrunoRequest(request);
77
93
  const res = new BrunoResponse(response);
@@ -81,6 +97,21 @@ class ScriptRuntime {
81
97
  req,
82
98
  res
83
99
  };
100
+
101
+ if (onConsoleLog && typeof onConsoleLog === 'function') {
102
+ const customLogger = (type) => {
103
+ return (...args) => {
104
+ onConsoleLog(type, cleanJson(args));
105
+ };
106
+ };
107
+ context.console = {
108
+ log: customLogger('log'),
109
+ info: customLogger('info'),
110
+ warn: customLogger('warn'),
111
+ error: customLogger('error')
112
+ };
113
+ }
114
+
84
115
  const vm = new NodeVM({
85
116
  sandbox: context,
86
117
  require: {
@@ -101,13 +132,13 @@ class ScriptRuntime {
101
132
  }
102
133
  });
103
134
 
104
- const asyncVM = vm.run(`module.exports = async () => { ${script} }`, path.join(collectionPath, 'vm.js'));
135
+ const asyncVM = vm.run(`module.exports = async () => { ${script} }`, path.join(collectionPath, 'vm.js'));
105
136
  await asyncVM();
106
137
 
107
138
  return {
108
139
  response,
109
- envVariables,
110
- collectionVariables
140
+ envVariables: cleanJson(envVariables),
141
+ collectionVariables: cleanJson(collectionVariables)
111
142
  };
112
143
  }
113
144
  }
@@ -1,11 +1,12 @@
1
1
  const { NodeVM } = require('vm2');
2
- const chai = require('chai');
2
+ const chai = require('chai');
3
3
  const path = require('path');
4
4
  const Bru = require('../bru');
5
5
  const BrunoRequest = require('../bruno-request');
6
6
  const BrunoResponse = require('../bruno-response');
7
7
  const Test = require('../test');
8
8
  const TestResults = require('../test-results');
9
+ const { cleanJson } = require('../utils');
9
10
 
10
11
  // Inbuilt Library Support
11
12
  const atob = require('atob');
@@ -17,10 +18,9 @@ const nanoid = require('nanoid');
17
18
  const CryptoJS = require('crypto-js');
18
19
 
19
20
  class TestRuntime {
20
- constructor() {
21
- }
21
+ constructor() {}
22
22
 
23
- runTests(testsFile, request, response, envVariables, collectionVariables, collectionPath) {
23
+ runTests(testsFile, request, response, envVariables, collectionVariables, collectionPath, onConsoleLog) {
24
24
  const bru = new Bru(envVariables, collectionVariables);
25
25
  const req = new BrunoRequest(request);
26
26
  const res = new BrunoResponse(response);
@@ -28,7 +28,7 @@ class TestRuntime {
28
28
  const __brunoTestResults = new TestResults();
29
29
  const test = Test(__brunoTestResults, chai);
30
30
 
31
- if(!testsFile || !testsFile.length) {
31
+ if (!testsFile || !testsFile.length) {
32
32
  return {
33
33
  request,
34
34
  envVariables,
@@ -47,6 +47,20 @@ class TestRuntime {
47
47
  __brunoTestResults: __brunoTestResults
48
48
  };
49
49
 
50
+ if (onConsoleLog && typeof onConsoleLog === 'function') {
51
+ const customLogger = (type) => {
52
+ return (...args) => {
53
+ onConsoleLog(type, cleanJson(args));
54
+ };
55
+ };
56
+ context.console = {
57
+ log: customLogger('log'),
58
+ info: customLogger('info'),
59
+ warn: customLogger('warn'),
60
+ error: customLogger('error')
61
+ };
62
+ }
63
+
50
64
  const vm = new NodeVM({
51
65
  sandbox: context,
52
66
  require: {
@@ -69,9 +83,9 @@ class TestRuntime {
69
83
 
70
84
  return {
71
85
  request,
72
- envVariables,
73
- collectionVariables,
74
- results: __brunoTestResults.getResults()
86
+ envVariables: cleanJson(envVariables),
87
+ collectionVariables: cleanJson(collectionVariables),
88
+ results: cleanJson(__brunoTestResults.getResults())
75
89
  };
76
90
  }
77
91
  }
@@ -6,7 +6,7 @@ const { evaluateJsTemplateLiteral, evaluateJsExpression, createResponseParser }
6
6
  class VarsRuntime {
7
7
  runPreRequestVars(vars, request, envVariables, collectionVariables, collectionPath) {
8
8
  const enabledVars = _.filter(vars, (v) => v.enabled);
9
- if(!enabledVars.length) {
9
+ if (!enabledVars.length) {
10
10
  return;
11
11
  }
12
12
 
@@ -22,7 +22,7 @@ class VarsRuntime {
22
22
  ...envVariables,
23
23
  ...collectionVariables,
24
24
  ...bruContext
25
- }
25
+ };
26
26
 
27
27
  _.each(enabledVars, (v) => {
28
28
  const value = evaluateJsTemplateLiteral(v.value, context);
@@ -36,7 +36,7 @@ class VarsRuntime {
36
36
 
37
37
  runPostResponseVars(vars, request, response, envVariables, collectionVariables, collectionPath) {
38
38
  const enabledVars = _.filter(vars, (v) => v.enabled);
39
- if(!enabledVars.length) {
39
+ if (!enabledVars.length) {
40
40
  return;
41
41
  }
42
42
 
@@ -54,7 +54,7 @@ class VarsRuntime {
54
54
  ...envVariables,
55
55
  ...collectionVariables,
56
56
  ...bruContext
57
- }
57
+ };
58
58
 
59
59
  _.each(enabledVars, (v) => {
60
60
  const value = evaluateJsExpression(v.value, context);
package/src/test.js CHANGED
@@ -1,14 +1,14 @@
1
1
  const Test = (__brunoTestResults, chai) => (description, callback) => {
2
2
  try {
3
3
  callback();
4
- __brunoTestResults.addResult({ description, status: "pass" });
4
+ __brunoTestResults.addResult({ description, status: 'pass' });
5
5
  } catch (error) {
6
6
  console.log(chai.AssertionError);
7
7
  if (error instanceof chai.AssertionError) {
8
8
  const { message, actual, expected } = error;
9
9
  __brunoTestResults.addResult({
10
10
  description,
11
- status: "fail",
11
+ status: 'fail',
12
12
  error: message,
13
13
  actual,
14
14
  expected
@@ -16,12 +16,12 @@ const Test = (__brunoTestResults, chai) => (description, callback) => {
16
16
  } else {
17
17
  __brunoTestResults.addResult({
18
18
  description,
19
- status: "fail",
19
+ status: 'fail',
20
20
  error: error.message || 'An unexpected error occurred.'
21
21
  });
22
22
  }
23
23
  console.log(error);
24
24
  }
25
- }
25
+ };
26
26
 
27
- module.exports = Test;
27
+ module.exports = Test;
package/src/utils.js CHANGED
@@ -1,21 +1,23 @@
1
1
  const jsonQuery = require('json-query');
2
- const { get } = require("@usebruno/query");
2
+ const { get } = require('@usebruno/query');
3
3
 
4
4
  const JS_KEYWORDS = `
5
5
  break case catch class const continue debugger default delete do
6
6
  else export extends false finally for function if import in instanceof
7
7
  new null return super switch this throw true try typeof var void while with
8
8
  undefined let static yield arguments of
9
- `.split(/\s+/).filter(word => word.length > 0);
9
+ `
10
+ .split(/\s+/)
11
+ .filter((word) => word.length > 0);
10
12
 
11
13
  /**
12
14
  * Creates a function from a Javascript expression
13
- *
15
+ *
14
16
  * When the function is called, the variables used in this expression are picked up from the context
15
- *
17
+ *
16
18
  * ```js
17
19
  * res.data.pets.map(pet => pet.name.toUpperCase())
18
- *
20
+ *
19
21
  * function(context) {
20
22
  * const { res, pet } = context;
21
23
  * return res.data.pets.map(pet => pet.name.toUpperCase())
@@ -29,25 +31,23 @@ const compileJsExpression = (expr) => {
29
31
  // get valid js identifiers (foo, bar)
30
32
  const vars = new Set(
31
33
  matches
32
- .filter(match => /^[a-zA-Z$_]/.test(match)) // starts with valid js identifier (foo.bar)
33
- .map(match => match.split('.')[0]) // top level identifier (foo)
34
- .filter(name => !JS_KEYWORDS.includes(name)) // exclude js keywords
34
+ .filter((match) => /^[a-zA-Z$_]/.test(match)) // starts with valid js identifier (foo.bar)
35
+ .map((match) => match.split('.')[0]) // top level identifier (foo)
36
+ .filter((name) => !JS_KEYWORDS.includes(name)) // exclude js keywords
35
37
  );
36
38
 
37
39
  // globals such as Math
38
- const globals = [...vars].filter(name => name in globalThis);
40
+ const globals = [...vars].filter((name) => name in globalThis);
39
41
 
40
42
  const code = {
41
- vars: [...vars].join(", "),
43
+ vars: [...vars].join(', '),
42
44
  // pick global from context or globalThis
43
- globals: globals
44
- .map(name => ` ${name} = ${name} ?? globalThis.${name};`)
45
- .join('')
45
+ globals: globals.map((name) => ` ${name} = ${name} ?? globalThis.${name};`).join('')
46
46
  };
47
47
 
48
48
  const body = `let { ${code.vars} } = context; ${code.globals}; return ${expr}`;
49
49
 
50
- return new Function("context", body);
50
+ return new Function('context', body);
51
51
  };
52
52
 
53
53
  const internalExpressionCache = new Map();
@@ -55,47 +55,47 @@ const internalExpressionCache = new Map();
55
55
  const evaluateJsExpression = (expression, context) => {
56
56
  let fn = internalExpressionCache.get(expression);
57
57
  if (fn == null) {
58
- internalExpressionCache.set(expression, fn = compileJsExpression(expression));
58
+ internalExpressionCache.set(expression, (fn = compileJsExpression(expression)));
59
59
  }
60
60
  return fn(context);
61
61
  };
62
62
 
63
63
  const evaluateJsTemplateLiteral = (templateLiteral, context) => {
64
- if(!templateLiteral || !templateLiteral.length || typeof templateLiteral !== 'string') {
64
+ if (!templateLiteral || !templateLiteral.length || typeof templateLiteral !== 'string') {
65
65
  return templateLiteral;
66
66
  }
67
67
 
68
68
  templateLiteral = templateLiteral.trim();
69
69
 
70
- if(templateLiteral === 'true') {
70
+ if (templateLiteral === 'true') {
71
71
  return true;
72
72
  }
73
73
 
74
- if(templateLiteral === 'false') {
74
+ if (templateLiteral === 'false') {
75
75
  return false;
76
76
  }
77
77
 
78
- if(templateLiteral === 'null') {
78
+ if (templateLiteral === 'null') {
79
79
  return null;
80
80
  }
81
81
 
82
- if(templateLiteral === 'undefined') {
82
+ if (templateLiteral === 'undefined') {
83
83
  return undefined;
84
84
  }
85
85
 
86
- if(templateLiteral.startsWith('"') && templateLiteral.endsWith('"')) {
86
+ if (templateLiteral.startsWith('"') && templateLiteral.endsWith('"')) {
87
87
  return templateLiteral.slice(1, -1);
88
88
  }
89
89
 
90
- if(templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) {
90
+ if (templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) {
91
91
  return templateLiteral.slice(1, -1);
92
92
  }
93
93
 
94
- if(!isNaN(templateLiteral)) {
94
+ if (!isNaN(templateLiteral)) {
95
95
  return Number(templateLiteral);
96
96
  }
97
97
 
98
- templateLiteral = "`" + templateLiteral + "`";
98
+ templateLiteral = '`' + templateLiteral + '`';
99
99
 
100
100
  return evaluateJsExpression(templateLiteral, context);
101
101
  };
@@ -118,9 +118,28 @@ const createResponseParser = (response = {}) => {
118
118
  return res;
119
119
  };
120
120
 
121
+ /**
122
+ * Objects that are created inside vm2 execution context result in an serilaization error when sent to the renderer process
123
+ * Error sending from webFrameMain: Error: Failed to serialize arguments
124
+ * at s.send (node:electron/js2c/browser_init:169:631)
125
+ * at g.send (node:electron/js2c/browser_init:165:2156)
126
+ * How to reproduce
127
+ * Remove the cleanJson fix and execute the below post response script
128
+ * bru.setVar("a", {b:3});
129
+ * Todo: Find a better fix
130
+ */
131
+ const cleanJson = (data) => {
132
+ try {
133
+ return JSON.parse(JSON.stringify(data));
134
+ } catch (e) {
135
+ return data;
136
+ }
137
+ };
138
+
121
139
  module.exports = {
122
140
  evaluateJsExpression,
123
141
  evaluateJsTemplateLiteral,
124
142
  createResponseParser,
125
- internalExpressionCache
126
- };
143
+ internalExpressionCache,
144
+ cleanJson
145
+ };