runner-runtime 1.0.8

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/events/api.js ADDED
@@ -0,0 +1,2280 @@
1
+ const FileType = require("file-type"),
2
+ contentDisposition = require("content-disposition"),
3
+ aTools = require("apipost-tools"),
4
+ isSvg = require("is-svg"),
5
+ JSONbig = require("json-bigint")({ storeAsString: true }),
6
+ stripJsonComments = require("strip-json-comments"),
7
+ mime = require("mime"),
8
+ { mockExp } = require('exp-mock'),
9
+ tough = require("tough-cookie"),
10
+ Buffer = require("buffer/").Buffer,
11
+ isImage = require("is-image");
12
+ const { getAPIFromCollection, smartUrlJoin, replace2RegExp, getParentTargetIDs, base64toCacheFile, getInsideVariables, getCaseInsensitive } = require('../libs/utils'),
13
+ _ = require('lodash');
14
+ const sdk = require("postman-collection"),
15
+ Url = sdk.Url,
16
+ PostmanEvent = sdk.Event;
17
+ const Mock = require('mockjs5-pro');
18
+ const { v4: uuidv4 } = require("uuid");
19
+
20
+ const fs = require("fs");
21
+ const { minimatch } = require("minimatch");
22
+ const runtime = require("postman-runtime-pro");
23
+
24
+ // 将api转postman请求参数
25
+ const convert2PostmanRequest = (request, option) => {
26
+ const pmRequest = {};
27
+ const { systemConfigs } = _.get(option, 'system_configs', {});
28
+
29
+ // 自动识别请求参数的Mock变量
30
+ const autoReplaceMockVar = (para) => {
31
+ try {
32
+ return _.toInteger(systemConfigs?.auto_gen_mock_url) > 0 ? Mock.mock(para) : para;
33
+ } catch (e) {
34
+ return para;
35
+ }
36
+ };
37
+
38
+ // 处理 url
39
+ const raw = autoReplaceMockVar(_.get(request, "request.url") || _.get(request, "url"));
40
+ const uri = new Url(raw);
41
+
42
+ // 清除原有query参数
43
+ try {
44
+ uri?.query.clear();
45
+ } catch (e) { }
46
+
47
+ // 遍历重置query参数
48
+ const queryAddEqual = _.toInteger(
49
+ _.get(request, "request.query.query_add_equal") || -1
50
+ );
51
+ _.forEach(_.get(request, "request.query.parameter"), (item) => {
52
+ if (_.isObject(item) && item?.is_checked > 0) {
53
+ let { key, value } = item;
54
+ key = String(autoReplaceMockVar(_.trim(key)));
55
+ value = String(autoReplaceMockVar(value));
56
+
57
+ if (key != "") {
58
+ if (value == "" && queryAddEqual < 1) {
59
+ // 不拼接 = 号
60
+ uri?.query?.members?.push(new sdk.QueryParam({ key, value: null }));
61
+ } else {
62
+ uri?.query?.members?.push(new sdk.QueryParam({ key, value, }));
63
+ }
64
+ }
65
+ }
66
+ }
67
+ );
68
+
69
+ // path 参数
70
+ const uriVariable = [];
71
+
72
+ if (_.isArray(_.get(uri, "path"))) {
73
+ const transformed = _.map(_.get(uri, "path"), (item) => {
74
+ if (_.startsWith(item, "{") && !_.startsWith(item, "{{") && _.endsWith(item, "}") && !_.endsWith(item, "}}")) {
75
+ return ":" + item.slice(1, -1);
76
+ }
77
+ return item; // 不需要替换的元素直接返回
78
+ });
79
+
80
+ _.set(uri, "path", transformed);
81
+ }
82
+ _.forEach(
83
+ _.get(request, "request.restful.parameter"), (item) => {
84
+ if (_.isObject(item) && item?.is_checked > 0) {
85
+ let { key, value } = item;
86
+ key = autoReplaceMockVar(_.trim(key));
87
+ value = autoReplaceMockVar(value);
88
+
89
+ if (key != "") {
90
+ uriVariable.push({ key, value });
91
+ }
92
+ }
93
+ }
94
+ );
95
+
96
+ if (_.isUndefined(uri?.protocol)) {
97
+ const varPattern = /^{{.*}}/;
98
+ if (!_.startsWith(_.first(uri?.host), "{{") && !varPattern.test(_.first(uri?.host))) {
99
+ _.set(uri, "protocol", "http");
100
+ }
101
+ }
102
+
103
+ const rawUrl = String(uri);
104
+
105
+ if (uri?.query?.members?.length > 0) {
106
+ try {
107
+ _.set(uri, "query", uri?.query?.toJSON());
108
+ } catch (e) {
109
+ _.set(uri, "query", uri?.query?.toObject());
110
+ }
111
+ } else {
112
+ _.set(uri, "query", undefined);
113
+ }
114
+
115
+ _.set(pmRequest, "url", {
116
+ raw: rawUrl,
117
+ variable: uriVariable,
118
+ ...uri,
119
+ });
120
+
121
+ // 处理协议
122
+ _.set(pmRequest, "protocol", _.get(request, "protocol") || "http/1.1");
123
+
124
+ // 处理 method
125
+ _.set(pmRequest, "method", _.get(request, "method") || "GET");
126
+
127
+ // 处理认证
128
+ const auth = {};
129
+ const authType = _.get(request, "request.auth.type") || "noauth";
130
+
131
+ if (_.isString(authType) && authType != "noauth" && authType != "inherit") {
132
+ switch (authType) {
133
+ case "kv":
134
+ _.assign(auth, {
135
+ type: "apikey",
136
+ apikey: [
137
+ {
138
+ key: "in",
139
+ value: _.get(request, `request.auth.kv.in`) || "header",
140
+ type: "string",
141
+ },
142
+ {
143
+ key: "value",
144
+ value:
145
+ autoReplaceMockVar(_.get(request, `request.auth.kv.value`)) || "",
146
+ type: "string",
147
+ },
148
+ {
149
+ key: "key",
150
+ value:
151
+ autoReplaceMockVar(_.get(request, `request.auth.kv.key`)) || "",
152
+ type: "string",
153
+ },
154
+ ],
155
+ });
156
+ break;
157
+ case "basic":
158
+ _.assign(auth, {
159
+ type: "basic",
160
+ basic: [
161
+ {
162
+ key: "password",
163
+ value:
164
+ autoReplaceMockVar(_.get(request, `request.auth.basic.password`)) || "",
165
+ type: "string",
166
+ },
167
+ {
168
+ key: "username",
169
+ value:
170
+ autoReplaceMockVar(_.get(request, `request.auth.basic.username`)) || "",
171
+ type: "string",
172
+ },
173
+ ],
174
+ });
175
+ break;
176
+ case "bearer":
177
+ _.assign(auth, {
178
+ type: "bearer",
179
+ bearer: [
180
+ {
181
+ key: "token",
182
+ value:
183
+ autoReplaceMockVar(_.get(request, `request.auth.bearer.key`)) ||
184
+ "",
185
+ type: "string",
186
+ },
187
+ ],
188
+ });
189
+ break;
190
+ case "digest":
191
+ const keyMap = {
192
+ username: "username",
193
+ password: "password",
194
+ realm: "realm",
195
+ nonce: "nonce",
196
+ algorithm: "algorithm",
197
+ qop: "qop",
198
+ opaque: "opaque",
199
+ nc: "nonceCount",
200
+ cnonce: "clientNonce",
201
+ disableRetryRequest: "disableRetryRequest",
202
+ };
203
+ _.set(auth, "type", authType);
204
+ _.set(auth, authType, []);
205
+
206
+ _.forEach(_.get(request, `request.auth.${authType}`), (val, key) => {
207
+ key = keyMap[autoReplaceMockVar(key)];
208
+ if (_.isString(val)) {
209
+ val = autoReplaceMockVar(val);
210
+ }
211
+
212
+ const value = _.isBoolean(val) ? val : (_.isInteger(val) ? !!val : _.isString(val) ? val : "");
213
+ const type = (_.isInteger(val) || _.isBoolean(val)) ? "boolean" : "string";
214
+ auth[authType].push({ key, value, type });
215
+ }
216
+ );
217
+
218
+ if (_.keys(_.get(request, `request.auth.${authType}`)).indexOf("disableRetryRequest") == -1) {
219
+ auth[authType].push({
220
+ key: "disableRetryRequest",
221
+ value: false,
222
+ type: "boolean",
223
+ });
224
+ }
225
+ break;
226
+ case "hawk":
227
+ case "oauth1":
228
+ case "oauth2":
229
+ case "awsv4":
230
+ case "ntlm":
231
+ case "jwt":
232
+ case "asap":
233
+ case "edgegrid": // TODO 将增加 asap和jwt,需前端增加相关参数
234
+ _.set(auth, "type", authType);
235
+ _.set(auth, authType, []);
236
+ _.forEach(_.get(request, `request.auth.${authType}`), (val, key) => {
237
+ if (_.isString(val)) {
238
+ val = autoReplaceMockVar(val);
239
+ }
240
+
241
+ key = autoReplaceMockVar(key);
242
+ const value = _.isBoolean(val) ? val : (_.isInteger(val) ? !!val : _.isString(val) ? val : "");
243
+ const type = (_.isInteger(val) || _.isBoolean(val)) ? "boolean" : "string";
244
+ auth[authType].push({ key, value, type });
245
+ }
246
+ );
247
+ break;
248
+ }
249
+ }
250
+
251
+ !_.isEmpty(auth) && _.set(pmRequest, "auth", auth);
252
+
253
+ // 处理 header
254
+ const header = [];
255
+ _.forEach(_.get(request, "request.header.parameter"), (item) => {
256
+ if (_.isObject(item) && item?.is_checked > 0) {
257
+ let disabled = item?.is_checked > 0 ? false : true;
258
+ let { key, value } = item;
259
+ key = autoReplaceMockVar(_.trim(key));
260
+ value = autoReplaceMockVar(value);
261
+ key != "" && header.push({ key, value, disabled });
262
+ }
263
+ }
264
+ );
265
+
266
+ let accessToken = ""; // 用于oauth2的access_token
267
+ if (auth?.type == "oauth2") {
268
+ if (_.isArray(auth?.oauth2)) {
269
+ const addTokenItem = _.find(auth.oauth2, { key: "addTokenTo" });
270
+ const headerPrefixItem = _.find(auth.oauth2, { key: "headerPrefix" });
271
+ const accessTokenItem = _.find(auth.oauth2, { key: "access_token" });
272
+ if (accessTokenItem?.value) {
273
+ accessToken = accessTokenItem.value;
274
+ if (headerPrefixItem?.value) {
275
+ accessToken = headerPrefixItem.value + " " + accessToken;
276
+ } else {
277
+ accessToken = "Bearer " + accessToken;
278
+ }
279
+ if (addTokenItem?.value == "header") {
280
+ header.push({ key: "Authorization", value: accessToken, disabled: false });
281
+ accessToken = ""; //设置完成自动清空
282
+ } else if (addTokenItem?.value == "queryParams") {
283
+ accessToken = accessTokenItem.value; //重置为最新
284
+ const oldUri = pmRequest.url.raw;
285
+ const urlObj = new URL(oldUri);
286
+ urlObj.searchParams.set('access_token', accessToken);
287
+ const query = pmRequest.url.query || [];
288
+ query.push({ key: "access_token", value: accessToken });
289
+ _.set(pmRequest, "url", {
290
+ ...pmRequest.url,
291
+ raw: urlObj.toString(),
292
+ query: query,
293
+ });
294
+ accessToken = ""; //设置完成自动清空
295
+ } else {
296
+ accessToken = ""; //不添加
297
+ }
298
+ }
299
+ }
300
+ }
301
+
302
+ const keyMap = new Map();
303
+ const duplicates = [];
304
+
305
+ // 遍历header数组,记录每个key的最新item
306
+ _.forEach(header, (item, index) => {
307
+ const lowerKey = item.key.toLowerCase();
308
+ if (keyMap.has(lowerKey)) {
309
+ duplicates.push(keyMap.get(lowerKey));
310
+ }
311
+ keyMap.set(lowerKey, index);
312
+ });
313
+
314
+ // 如果有重复项,倒序剔除这些index的值
315
+ if (duplicates.length > 0) {
316
+ _.forEachRight(duplicates, (dupIndex) => {
317
+ if (dupIndex > -1) {
318
+ header.splice(dupIndex, 1);
319
+ }
320
+ });
321
+ }
322
+
323
+ _.set(pmRequest, "header", header);
324
+
325
+ // 处理 cookie
326
+ try {
327
+ if (pmRequest?.url?.raw != "") {
328
+ let cookieUrlParse = {};
329
+
330
+ if (_.isString(_.get(request, 'initVarReplacedUrl')) && !_.isEmpty(_.get(request, 'initVarReplacedUrl'))) {
331
+ cookieUrlParse = new Url(_.get(request, 'initVarReplacedUrl'))
332
+ }
333
+
334
+ const cookieStr = [];
335
+
336
+ _.forEach(_.get(request, "request.cookie.parameter"), (item) => {
337
+ if (_.isObject(item)) {
338
+ let name = encodeURIComponentUnique(
339
+ autoReplaceMockVar(item.key || item.name)
340
+ );
341
+
342
+ let value = autoReplaceMockVar(item.value);
343
+
344
+ if (_.isUndefined(_.get(request, "request.cookie.cookie_encode")) || _.parseInt(_.get(request, "request.cookie.cookie_encode")) > 0) {
345
+ value = encodeURIComponentUnique(value);
346
+ }
347
+
348
+ let cookie = _.assign(item, { key: name, name, value });
349
+ let host = !_.isEmpty(pmRequest?.url?.host) ? _.join(pmRequest?.url?.host, ".") : pmRequest?.url?.raw;
350
+ let urlPath = pmRequest?.url?.path;
351
+
352
+ if (!_.isEmpty(cookieUrlParse)) {
353
+ host = !_.isEmpty(cookieUrlParse.host) ? _.join(cookieUrlParse.host, ".") : _.get(request, 'initVarReplacedUrl');
354
+ urlPath = cookieUrlParse.path
355
+ }
356
+
357
+ let pathStr = _.join(urlPath, "/");
358
+
359
+ if (!_.startsWith(pathStr, '/') && _.startsWith(cookie?.path, '/')) {
360
+ pathStr = `/${pathStr}`;
361
+ }
362
+
363
+ if (!_.endsWith(pathStr, '/') && _.endsWith(cookie?.path, '/')) {
364
+ pathStr = `${pathStr}/`;
365
+ }
366
+
367
+ if ((_.isUndefined(cookie?.domain) || minimatch(host, cookie?.domain) || _.endsWith(host, cookie?.domain)) && (_.isUndefined(cookie?.path) || cookie?.path == '/' || _.startsWith(pathStr || "/", cookie?.path)) && (_.isUndefined(cookie?.expires) || _.gt(new Date(String(cookie?.expires)), new Date()))) {
368
+ cookieStr.push(`${cookie.name}=${cookie.value}`);
369
+ }
370
+ }
371
+ }
372
+ );
373
+
374
+ if (!_.isEmpty(cookieStr)) {
375
+ const foundItem = _.find(
376
+ pmRequest.header,
377
+ (item) => _.toLower(item.key) === _.toLower("cookie")
378
+ );
379
+
380
+ if (foundItem) {
381
+ foundItem.value = _.join(cookieStr, ";");
382
+ } else {
383
+ pmRequest.header.push({
384
+ key: "Cookie",
385
+ value: _.join(cookieStr, ";"),
386
+ });
387
+ }
388
+ }
389
+ }
390
+ } catch (e) { }
391
+
392
+ // 处理body
393
+ const body = {};
394
+ const bodyMode = _.get(request, "request.body.mode") || "none";
395
+
396
+ if (_.isString(bodyMode) && bodyMode != "none") {
397
+ const modeMap = {
398
+ "form-data": "formdata",
399
+ plain: "text",
400
+ binary: "file",
401
+ msgpack: "msgpack",
402
+ };
403
+
404
+ switch (bodyMode) {
405
+ case "form-data":
406
+ case "urlencoded":
407
+ _.set(body, "mode", modeMap[bodyMode] ? modeMap[bodyMode] : bodyMode);
408
+ _.set(body, body.mode, []);
409
+
410
+ const parameter = _.get(request, `request.body.parameter`);
411
+
412
+ _.forEach(parameter, (item) => {
413
+ if (_.isObject(item)) {
414
+ if (item.is_checked > 0 && autoReplaceMockVar(item.key) != '') {
415
+ if (bodyMode == "form-data" && item.field_type == "File") {
416
+ const src = base64toCacheFile(
417
+ item.key,
418
+ item.value,
419
+ item.file_base64,
420
+ request?.target_id
421
+ );
422
+ body[body.mode].push({
423
+ key: autoReplaceMockVar(item.key),
424
+ src,
425
+ type: "file",
426
+ disabled: false,
427
+ });
428
+ } else {
429
+ if (bodyMode == "form-data" && item.content_type != "") {
430
+ body[body.mode].push({
431
+ key: autoReplaceMockVar(item.key),
432
+ value: autoReplaceMockVar(item.value),
433
+ type: "text",
434
+ disabled: false,
435
+ contentType: item.content_type,
436
+ });
437
+ } else {
438
+ body[body.mode].push({
439
+ key: autoReplaceMockVar(item.key),
440
+ value: autoReplaceMockVar(item.value),
441
+ type: "text",
442
+ disabled: false,
443
+ });
444
+ }
445
+ }
446
+ }
447
+ }
448
+ }
449
+ );
450
+ break;
451
+ case "binary":
452
+ const src = base64toCacheFile(
453
+ "binary",
454
+ _.get(request, `request.body.binary.file_path`),
455
+ _.get(request, `request.body.binary.data_url`),
456
+ request?.target_id
457
+ );
458
+ _.assign(body, {
459
+ mode: "file",
460
+ file: {
461
+ src,
462
+ },
463
+ });
464
+ break;
465
+ default:
466
+ let raw = autoReplaceMockVar(_.get(request, `request.body.raw`));
467
+
468
+ if (bodyMode == "msgpack") {
469
+ const msgpack = require("msgpack5")();
470
+ try {
471
+ raw = msgpack.encode(JSONbig.parse(stripJsonComments(raw))).slice();
472
+ Object.setPrototypeOf(raw, Object.getPrototypeOf({}));
473
+ } catch (e) { }
474
+
475
+ const foundItem = _.find(
476
+ pmRequest.header,
477
+ (item) => _.toLower(item.key) === _.toLower("content-type")
478
+ );
479
+
480
+ if (foundItem) {
481
+ foundItem.value = "application/msgpack";
482
+ } else {
483
+ pmRequest.header.push({
484
+ key: "content-type",
485
+ value: "application/msgpack",
486
+ });
487
+ }
488
+ } else if (bodyMode == "json" && option?.request_param_auto_json > 0) {
489
+ try {
490
+ raw = JSONbig.stringify(JSONbig.parse(stripJsonComments(raw)));
491
+ Object.setPrototypeOf(raw, Object.getPrototypeOf({}));
492
+ } catch (e) { }
493
+ }
494
+
495
+ _.assign(body, {
496
+ mode: "raw",
497
+ raw,
498
+ options: {
499
+ raw: {
500
+ language: modeMap[bodyMode] ? modeMap[bodyMode] : bodyMode,
501
+ },
502
+ },
503
+ });
504
+ break;
505
+ }
506
+ }
507
+
508
+ !_.isEmpty(body) && _.set(pmRequest, "body", body);
509
+
510
+ return pmRequest;
511
+ }
512
+
513
+ // 转postman请求选项
514
+ const convert2PostmanOptions = (request, option, variables) => {
515
+ // 请求信息
516
+ const { requestJson } = request;
517
+
518
+ // 创建迭代数据
519
+ const iterationData = _.get(variables, 'iterationData');
520
+ const data = [iterationData];
521
+
522
+ // 初始化 environment
523
+ const envVariables = [];
524
+ _.forEach(_.get(variables, "environment"), (value, key) => {
525
+ envVariables.push({
526
+ value,
527
+ key,
528
+ type: "any",
529
+ enabled: true,
530
+ });
531
+ });
532
+
533
+ const environment = new sdk.VariableScope({
534
+ values: envVariables,
535
+ });
536
+
537
+ // 初始化 globals
538
+ const globalsVariables = [];
539
+ _.forEach(_.defaults(_.get(variables, "globals") || {}, getInsideVariables()), (value, key) => {
540
+ globalsVariables.push({
541
+ value,
542
+ key,
543
+ type: "any",
544
+ enabled: true,
545
+ });
546
+ }
547
+ );
548
+
549
+ // 创建一个全局变量对象
550
+ const globals = new sdk.VariableScope({
551
+ values: globalsVariables,
552
+ });
553
+
554
+ const requester = {
555
+ strictSSL: false,
556
+ protocolVersion: requestJson?.protocol == 'http/1.1' ? 'http1' : 'http2',
557
+ timings: true,
558
+ verbose: false,
559
+ implicitCacheControl: true,
560
+ implicitTraceHeader: false,
561
+ followOriginalHttpMethod: _.get(option, "system_configs.follow_original_method") > 0 ? true : false,
562
+ followRedirects: _.get(option, "system_configs.auto_redirect") > 0 ? true : false,
563
+ maxRedirects: _.max([_.toInteger(_.get(option, "system_configs.max_redirect_time")), 5])
564
+ };
565
+
566
+ // 设置extendedRootCA证书
567
+ if (_.get(option, "system_configs.ca_cert.open") > 0 && _.trim(_.get(option, "system_configs.ca_cert.path")) != "") {
568
+ _.set(requester, `extendedRootCA`, _.trim(_.get(option, "system_configs.ca_cert.path")));
569
+ }
570
+
571
+ // 设置客户端证书
572
+ const certificates = [];
573
+ _.forEach(_.get(option, "system_configs.client_cert"), (cert, host) => {
574
+ const uri = new Url(host);
575
+ if (_.isObject(cert)) {
576
+ if (uri.port <= 0) {
577
+ host = `${uri.protocol}://${_.join(uri.host, ".")}:443`;
578
+ }
579
+
580
+ ['key', 'crt', 'pfx'].forEach((type) => {
581
+ let fileUrl = _.get(cert, `${type}.file_url`);
582
+
583
+ if (_.isEmpty(fileUrl)) {
584
+ if (!_.isEmpty(_.get(cert, `${type}.file_base64`))) {
585
+ fileUrl = base64toCacheFile(
586
+ _.get(cert, `${type}.file_name`),
587
+ _.get(cert, `${type}.file_name`),
588
+ _.get(cert, `${type}.file_base64`),
589
+ uuidv4()
590
+ )
591
+ }
592
+ }
593
+
594
+ if (!_.isEmpty(fileUrl)) {
595
+ try {
596
+ fs.statSync(fileUrl);
597
+ _.set(cert, `${type}.file_url`, fileUrl);
598
+ } catch (e) { }
599
+ }
600
+ })
601
+
602
+ const certObj = {
603
+ name: `Client cert for ${host}`,
604
+ matches: [host, `${host}/*`],
605
+ passphrase: cert?.password,
606
+ };
607
+
608
+ ['key', 'crt', 'pfx'].forEach((type) => {
609
+ if (!_.isEmpty(_.get(cert, `${type}.file_url`))) {
610
+ _.set(certObj, type == 'crt' ? "cert" : type, { src: _.get(cert, `${type}.file_url`) })
611
+ }
612
+ })
613
+
614
+ certificates.push(certObj);
615
+ }
616
+ }
617
+ );
618
+ let requestTimeout = _.toInteger(_.get(option, "system_configs.send_timeout"));
619
+
620
+ // fix 请求超时时间除0外,最大值为一周,0为永不超时
621
+ if (!_.inRange(requestTimeout, 0, 604800)) {
622
+ requestTimeout = 0;
623
+ }
624
+
625
+ const options = {
626
+ timeout: {
627
+ request: requestTimeout,
628
+ script: 0,
629
+ global: 0,
630
+ },
631
+ delay: {
632
+ item: 0,
633
+ iteration: 0,
634
+ },
635
+ iterationCount: 1,
636
+ fileResolver: require("fs"),
637
+ data,
638
+ environment,
639
+ globals,
640
+ requester,
641
+ systemProxy: async function (url, callback) {
642
+ try {
643
+ // 设置代理
644
+ const proxy = {}, urlParsed = new Url(url), uriHost = _.toLower(_.join(urlParsed?.host, "."));
645
+
646
+ if (_.get(option, "system_configs.proxy.type") == 1) {
647
+ // 自定义代理
648
+ const match = _.get(option, "system_configs.proxy.auth.host").match(
649
+ /(([^:]+):(\d+))/
650
+ );
651
+
652
+ if (_.isArray(match) && _.toInteger(match[3]) > 0) {
653
+ // 检查当前host是否匹配 bypass
654
+ let bypass = _.get(option, "system_configs.proxy.bypass");
655
+
656
+ if (_.isString(bypass)) {
657
+ bypass = bypass.split(",");
658
+ }
659
+
660
+ let bypassMatch = _.find(bypass, (o) => {
661
+ return minimatch(uriHost, o);
662
+ });
663
+
664
+ // 检查当前协议是否匹配 protocol
665
+ let protocols = _.get(option, "system_configs.proxy.protocols");
666
+
667
+ if (_.isString(protocols)) {
668
+ protocols = protocols.split(",");
669
+ }
670
+
671
+ let protocolMatch = _.find(protocols, (o) => {
672
+ return (_.toLower(urlParsed?.protocol) || "http") == _.toLower(o);
673
+ });
674
+
675
+ // 不匹配 bypass 且 匹配 protocol
676
+ if (!bypassMatch && protocolMatch) {
677
+ _.set(proxy, "host", match[2]);
678
+ _.set(proxy, "port", _.toInteger(match[3]));
679
+ }
680
+ }
681
+ } else if (_.get(option, "system_configs.proxy.type") == -1) {
682
+ // 获取系统代理
683
+ let noProxy = _.isString(_.get(process, "env.NO_PROXY")) && _.get(option, "system_configs.proxy.envfirst") > 0 ? String(_.get(process, "env.NO_PROXY")).split(",") : [];
684
+
685
+ let unNoProxyMatch = _.isEmpty(noProxy) || _.isUndefined(_.find(noProxy, (o) => { return minimatch(uriHost, o); }));
686
+
687
+ if (unNoProxyMatch) {
688
+ const env_proxy = String(urlParsed?.protocol == "https" ? _.get(process, "env.HTTPS_PROXY") : _.get(process, "env.HTTP_PROXY"));
689
+
690
+ if ((_.get(option, "system_configs.proxy.envfirst") > 0 || _.isEmpty(_.get(process, "versions.electron"))) && !_.isEmpty(env_proxy) && env_proxy != "undefined") {
691
+ let env_proxy_parse = new Url(env_proxy);
692
+ _.set(proxy, "host", _.join(env_proxy_parse?.host, ".") || "");
693
+ _.set(proxy, "port", _.toInteger(env_proxy_parse?.port) > 0 ? _.toInteger(env_proxy_parse?.port) : 0);
694
+ } else if (!_.isEmpty(_.get(process, "versions.electron"))) {
695
+ try {
696
+ const electronProxy = await require("electron").session.defaultSession.resolveProxy(url);
697
+ const match = electronProxy.match(/PROXY (([^:]+):(\d+))/);
698
+
699
+ if (_.isObject(match) && _.isString(match[2]) && !_.isEmpty(match[2]) && _.toInteger(match[3]) > 0
700
+ ) {
701
+ _.set(proxy, "host", match[2]);
702
+ _.set(proxy, "port", _.toInteger(match[3]));
703
+ }
704
+ } catch (e) { }
705
+ }
706
+ }
707
+ }
708
+
709
+ if (_.isString(proxy.host) && proxy.host != "") {
710
+ _.set(proxy, "tunnel", _.toLower(urlParsed?.protocol) == "http" ? false : true);
711
+ _.set(proxy, "authenticate", _.get(option, "system_configs.proxy.auth.authenticate") > 0 ? true : false);
712
+
713
+ if (proxy.authenticate) {
714
+ _.set(proxy, "username", _.get(option, "system_configs.proxy.auth.username"));
715
+ _.set(proxy, "password", _.get(option, "system_configs.proxy.auth.password"));
716
+ }
717
+ }
718
+
719
+ if (!_.isEmpty(proxy) && _.isString(proxy.host) && proxy.host != "" && proxy.host != "undefined") {
720
+ return callback(null, proxy)
721
+ } else {
722
+ return callback(null, null)
723
+ }
724
+ } catch (e) {
725
+ return callback(null, null)
726
+ }
727
+ }
728
+ };
729
+
730
+ // 证书
731
+ if (!_.isEmpty(certificates)) {
732
+ _.assign(options, {
733
+ certificates: new sdk.CertificateList(
734
+ {},
735
+ certificates
736
+ )
737
+ })
738
+ }
739
+
740
+ return options;
741
+ }
742
+
743
+ // 转 postman 事件
744
+ const convert2PostmanEvent = (request, listen, option) => {
745
+ const { requestJson } = request;
746
+ const { database_configs, env, dynamic_option, custom_functions } = option;
747
+
748
+ let customFuncScript = '';
749
+ _.forEach(custom_functions, (script, name) => {
750
+ name = _.trim(name);
751
+ if (name != '') {
752
+ customFuncScript = `
753
+ ${customFuncScript}
754
+
755
+ function ${name}(text) {
756
+ try{
757
+ ${script}
758
+ }catch(e){
759
+ return text;
760
+ }
761
+ }
762
+ `;
763
+ }
764
+ })
765
+
766
+ const sysScript = [
767
+ // "(async function(){",
768
+ "const response = {};",
769
+ `
770
+ const splitCookieString = (input)=> {
771
+ let index = input.indexOf('=');
772
+ if (index === -1) {
773
+ return [input];
774
+ }
775
+ return [input.slice(0, index), input.slice(index + 1)];
776
+ }
777
+ `,
778
+
779
+ `
780
+ const getMainProcessSocketPath = ()=>{
781
+ return "${_.get(process, 'env.main_process_socket_path')}"
782
+ }
783
+ `,
784
+
785
+ "let lodashv4 = require('lodash');",
786
+ "let { mockExp } = require('exp-mock');",
787
+ "let Mock = require('mockjs');",
788
+ "let xml2json = xml2Json;",
789
+ "let JSON5 = require('json5');",
790
+ "let aTools = require('apipost-tools');",
791
+ "let jsonpath = require('jsonpath');",
792
+ `let _envTmpVariablesData = ${JSON.stringify(env)}`,
793
+ `let _dynamicValueOptions = ${JSON.stringify(dynamic_option)}`,
794
+ "let $ = {}; $.md5 = function(str){return CryptoJS.MD5(str).toString()};$.ajax = pm.ajaxSendRequest;",
795
+ `pm.environment.getPreUrl = function(){return _.get(_envTmpVariablesData, "env_pre_url");}`,
796
+ `pm.environment.getName = function(){return _.get(_envTmpVariablesData, "env_name");}`,
797
+ "pm.environment.getCollection = function(){return pm.environment.toObject();}",
798
+ `pm.variables.getPreUrl = function(){return _.get(_envTmpVariablesData, "env_pre_url");}`,
799
+ `pm.variables.getName = function(){return _.get(_envTmpVariablesData, "env_name");}`,
800
+ "pm.variables.getCollection = function(){return pm.environment.toObject();}",
801
+ "pm.environment.delete = pm.environment.unset;",
802
+ "pm.variables.delete = pm.variables.unset;",
803
+ "pm.globals.delete = pm.globals.unset;",
804
+ "pm.Visualizing = pm.visualizer.set", // 兼容旧版本的可视化
805
+ `
806
+ // Database
807
+ pm.queryDatabase = async (dbconfig) => {
808
+ const { query } = dbconfig;
809
+ const { createUnixClient } = require('net'),
810
+ socketPath = getMainProcessSocketPath();
811
+
812
+ try{
813
+ const result = await createUnixClient(socketPath, JSON.stringify({
814
+ action: 'queryDatabase',
815
+ data: { dbconfig, query }
816
+ }));
817
+
818
+ return JSON.parse(Buffer.from(JSON.parse(result.toString())).toString());
819
+ }catch(e){
820
+ return { err: 'error', result:String(e)}
821
+ }
822
+ };
823
+
824
+ // pm.execute
825
+ pm.execute = async (file, args, option) => {
826
+ const { createUnixClient } = require('net'),
827
+ socketPath = getMainProcessSocketPath();
828
+
829
+ try {
830
+ const result = await createUnixClient(socketPath, JSON.stringify({
831
+ action: 'execute',
832
+ data: { file, args, option }
833
+ }));
834
+
835
+ const resultObj = JSON.parse(Buffer.from(JSON.parse(result.toString())).toString());
836
+
837
+ if(resultObj?.err == 'success'){
838
+ return resultObj?.result
839
+ }else{
840
+ throw new Error(resultObj?.result);
841
+ }
842
+ }
843
+ catch (e) {
844
+ throw new Error(e);
845
+ }
846
+ };
847
+ `,
848
+ `
849
+ let _requestTmpBodyObject = request?.data
850
+ try{
851
+ _requestTmpBodyObject = JSON.stringify(JSON5.parse(request?.data));
852
+ }catch(e){}
853
+
854
+ try{
855
+ let _requestTmpVariablesData = ${JSON.stringify({ name: requestJson?.name })}
856
+ _.assign(request, {
857
+ request_headers: pm.request?.headers?.toObject(),
858
+ request_bodys: _requestTmpBodyObject,
859
+ request_querys: pm.request?.url?.query?.toObject(),
860
+ request_variables: pm.request?.url?.variables?.toObject(),
861
+ mode: "${_.get(requestJson, "request.body.mode")}",
862
+ contentType: pm.request?.headers?.get('content-type'),
863
+ id: "${requestJson?.sample_id || requestJson?.target_id}",
864
+ name: _.get(_requestTmpVariablesData, "name") || "HTTP request",
865
+ url: String(pm.request?.url),
866
+ uri: pm.request?.url
867
+ });
868
+ }catch(e){}
869
+
870
+ // 获取最终请求body
871
+ try{
872
+ pm.getFinalRequestRawBody = () => {
873
+ let requestBody = pm.variables.replaceIn(request.request_bodys);
874
+
875
+ if(lodashv4.isString(requestBody)){
876
+ const regex = /{{([^}]+)}}/g;
877
+ const matches = requestBody.match(regex);
878
+ if (!lodashv4.isEmpty(matches)) {
879
+ lodashv4.forEach(matches, (match) => {
880
+ try {
881
+ const tmpVal = mockExp(match, _dynamicValueOptions?.all_vars || {}, _dynamicValueOptions?.lang || 'en', _dynamicValueOptions?.custom_functions || {});
882
+
883
+ if (tmpVal != match && !lodashv4.isUndefined(tmpVal)) {
884
+ requestBody = lodashv4.replace(requestBody, match, tmpVal);
885
+ }
886
+ } catch (e) { }
887
+ })
888
+ }
889
+
890
+ pm.setRequestBody(requestBody);
891
+ }
892
+
893
+ return requestBody;
894
+ }
895
+ }catch(e){
896
+ pm.getFinalRequestRawBody = () => {}
897
+ }
898
+
899
+ // 变量替换(含动态值)
900
+ try{
901
+ pm.mock = (str) => {
902
+ if(lodashv4.isString(str)){
903
+ const regex = /{{([^}]+)}}/g;
904
+ const matches = str.match(regex);
905
+ if (!lodashv4.isEmpty(matches)) {
906
+ lodashv4.forEach(matches, (match) => {
907
+ try {
908
+ const tmpVal = mockExp(match, _dynamicValueOptions?.all_vars || {}, _dynamicValueOptions?.lang || 'en', _dynamicValueOptions?.custom_functions || {});
909
+
910
+ if (tmpVal != match && !lodashv4.isUndefined(tmpVal)) {
911
+ str = lodashv4.replace(str, match, tmpVal);
912
+ }
913
+ } catch (e) { }
914
+ })
915
+ }
916
+
917
+ }
918
+ return str;
919
+ }
920
+ }catch(e){
921
+ pm.mock = (str) => {return str}
922
+ }
923
+ `,
924
+ "if(_.isObject(pm.response)){",
925
+ "try{",
926
+ "_.set(response, 'headers', pm.response.headers?.toObject());",
927
+ "}catch(e){}",
928
+ `try{ // 设置cookie
929
+ response.cookies = {};
930
+ const responseCookies = lodashv4.get(pm.response.headers.toObject(), 'set-cookie');
931
+ lodashv4.forEach(lodashv4.isArray(responseCookies)?responseCookies:[responseCookies], (cookieStr) => {
932
+ let cookieArr = splitCookieString(lodashv4.head(lodashv4.split(cookieStr, ';')));
933
+ let cookieValue = lodashv4.join(lodashv4.tail(cookieArr),'');
934
+
935
+ if(cookieArr[0] && cookieValue){
936
+ try{
937
+ _.set(response.cookies, cookieArr[0], decodeURIComponent(cookieValue))
938
+ }catch(e){
939
+ _.set(response.cookies, cookieArr[0], cookieValue)
940
+ }
941
+ }
942
+ })
943
+ }catch(e){}
944
+ `,
945
+ "_.set(pm, 'response.raw.responseText', pm.response.text());",
946
+ "_.set(response, 'raw.responseText', pm.response.text());",
947
+ "try{",
948
+ "_.set(response, 'json', pm.response.json());",
949
+ "_.set(response, 'raw.json', pm.response.json());",
950
+ "}catch(e){_.set(response, 'raw.json', {})}",
951
+ "_.set(response, 'raw.status', pm.response.code);",
952
+ "_.set(response, 'raw.responseTime', pm.response.responseTime);",
953
+ " pm.response.setBody = function (body) {",
954
+ " if (typeof body !== 'string') {",
955
+ " body = JSON.stringify(body);",
956
+ " }",
957
+ " if (typeof body === 'string') {",
958
+ " const originalText = _.cloneDeep(pm.response.text());",
959
+ " try {",
960
+ " const originalJson = _.cloneDeep(pm.response.json());",
961
+ " pm.response.originalJson = function () {",
962
+ " return originalJson;",
963
+ " };",
964
+ " }",
965
+ " catch (e) {",
966
+ " pm.response.originalJson = function () {",
967
+ " return null;",
968
+ " };",
969
+ " }",
970
+ " pm.response.originalText = function () {",
971
+ " return originalText;",
972
+ " };",
973
+ " pm.response.stream = Buffer.from(body);",
974
+ ` pm.variables.set("_pm.response.setBody", body);`,
975
+ " }",
976
+ " };",
977
+ "",
978
+ " pm.response.setCode = function (code) {",
979
+ " if (typeof code === 'number') {",
980
+ " pm.response.originalCode = function () {",
981
+ " return pm.response.code;",
982
+ " };",
983
+ "",
984
+ " pm.response.code = code;",
985
+ ` pm.variables.set("_pm.response.code", code);`,
986
+ " }",
987
+ " };",
988
+ "}",
989
+ "const apipost = postman;",
990
+ "const apt = fox = ea = echoapi = insomnia = pm;", // TODO 兼容旧版本apipost的语法、增加更多三方库
991
+ `
992
+ // Compatible with tc
993
+ const expect = pm.expect;
994
+ const assert = pm.assert;
995
+ assert.equal = (source, dist) => { return source === dist }
996
+ const tc = {};
997
+ try {
998
+ // global
999
+ tc.loadModule = require;
1000
+ tc.info = {};
1001
+ tc.delay = sleep;
1002
+
1003
+ // Ignored library
1004
+ tc.exec = () => { console.warn("The tc.exec script syntax of Thunder client is not supported.") }
1005
+ tc.runRequest = () => { console.warn("The tc.runRequest script syntax of Thunder client is not supported, Please use pm.sendRequest() instead.") }
1006
+ tc.skipRequest = () => { console.warn("The tc.skipRequest script syntax of Thunder client is not supported.") }
1007
+ tc.chartHTML = () => { console.warn("The tc.chartHTML script syntax of Thunder client is not supported.") }
1008
+ tc.retryRequest = () => { console.warn("The tc.retryRequest script syntax of Thunder client is not supported.") }
1009
+ tc.runRequest = () => { console.warn("The tc.runRequest script syntax of Thunder client is not supported.") }
1010
+ tc.setCookie = () => { console.warn("The tc.setCookie script syntax of Thunder client is not supported.") }
1011
+ tc.clearCookies = () => { console.warn("The tc.clearCookies script syntax of Thunder client is not supported.") }
1012
+ tc.getCookies = () => { console.warn("The tc.getCookies script syntax of Thunder client is not supported.") }
1013
+ tc.readFile = () => { console.warn("The tc.readFile script syntax of Thunder client is not supported.") }
1014
+ tc.loadFromPath = () => { console.warn("The tc.loadFromPath script syntax of Thunder client is not supported.") }
1015
+
1016
+ // test
1017
+ tc.test = (name, func) => {
1018
+ if (lodashv4.isFunction(func)) {
1019
+ if(!lodashv4.isUndefined(func())){
1020
+ try{
1021
+ pm.test(name, func)
1022
+ }catch(e){}
1023
+ }else{
1024
+ pm.test(name, pm.expect(func()).to.equal(true))
1025
+ }
1026
+ } else {
1027
+ pm.test(name, pm.expect(lodashv4.toInteger(func) > 0 ? true : false).to.equal(true))
1028
+ }
1029
+ }
1030
+
1031
+ // var
1032
+ tc.setVar = (key, value) => { pm.environment.set(key, value) };
1033
+ tc.getVar = (key) => { return pm.environment.get(key) };
1034
+
1035
+ // Param
1036
+ tc.setParam = (key, value) => { pm.setRequestQuery(key, value) };
1037
+
1038
+ // request
1039
+ tc.request = lodashv4.cloneDeep(request);
1040
+ tc.request.body = {};
1041
+ tc.request.name = request.name;
1042
+ tc.request.id = request.id;
1043
+ tc.request.name = request.name;
1044
+ tc.request.setHeader = (key, value) => { pm.setRequestHeader(key, value) };
1045
+ tc.request.getHeader = (key) => { return pm.request.headers.get(key) };
1046
+ tc.request.setBody = (key, value) => { pm.setRequestBody(key, value) };
1047
+
1048
+ // response
1049
+ if (lodashv4.isObject(pm.response)) {
1050
+ tc.response = lodashv4.cloneDeep(response);
1051
+ tc.response.size = pm.response.responseSize;
1052
+ tc.response.status = pm.response.code;
1053
+ tc.response.time = pm.response.responseTime;
1054
+ tc.response.text = response?.raw?.responseText;
1055
+ tc.response.contentType = lodashv4.get(response, 'headers.content-type');
1056
+ tc.response.cookies = lodashv4.toPairs(lodashv4.get(tc, 'response.cookies')).map(([key, value]) => ({ key, value }));
1057
+ tc.response.headers = lodashv4.cloneDeep(lodashv4.cloneDeep(pm.response.headers.toJSON()));
1058
+ tc.response.getHeader = (key) => { return lodashv4.get(response.headers, lodashv4.toLower(key)) };
1059
+ tc.response.getBinary = () => { console.warn("The tc.getBinary script syntax of Thunder client is not supported.") }
1060
+ }
1061
+ } catch (e) {
1062
+ console.warn("Thunder Client script has an issue; please check manually. EchoAPI is fully compatible with Postman.")
1063
+ }
1064
+
1065
+ // 自定义函数
1066
+ ${customFuncScript}
1067
+ `, // 兼容 thuner client
1068
+ ];
1069
+
1070
+ const pmEvent = {
1071
+ prerequest: [],
1072
+ test: [],
1073
+ };
1074
+ const eventMap = {
1075
+ pre_tasks: "prerequest",
1076
+ post_tasks: "test",
1077
+ };
1078
+
1079
+ _.forEach(_.keys(eventMap), (type) => {
1080
+ let exec = _.join(sysScript, "\n");
1081
+ _.forEach(_.get(requestJson, `request.${type}`), (item) => {
1082
+ if (_.isObject(item)) {
1083
+ if (item.enabled > 0) {
1084
+ switch (item.type) {
1085
+ case "customScript": // done
1086
+ if (!_.isEmpty(item?.data) && _.isString(item?.data) && item?.data != 'undefined') {
1087
+ exec = `${exec}\n${_.trim(item?.data)}\n`;
1088
+ }
1089
+ break;
1090
+ case "database": // done
1091
+ let dbconfig = database_configs[item.data?.connectionId] || {};
1092
+
1093
+ if (!_.isEmpty(dbconfig)) {
1094
+ dbconfig = JSON.stringify(dbconfig, null, "\t");
1095
+ exec = `${exec}
1096
+ ! await (async function(){
1097
+ const dbData = ${JSON.stringify(item.data || { query: '' })}
1098
+ const query = pm.variables.replaceIn(_.get(dbData, "query"));
1099
+ const method = pm.variables.replaceIn(_.get(dbData, "method") || "");
1100
+
1101
+ try{
1102
+ let dbResultList = await pm.queryDatabase(_.assign(${dbconfig},{
1103
+ method:method,
1104
+ query:query
1105
+ }));
1106
+
1107
+ let {err, result} = dbResultList;
1108
+
1109
+ if(err == 'success'){
1110
+ if(${item.data?.isConsoleOutput} > 0){
1111
+ console.log(query, result)
1112
+ }
1113
+ if(_.isObject(result)){
1114
+ _.forEach(${JSON.stringify(item.data?.variables || [])}, (item) => {
1115
+ let extra_value = jsonpath.value(result, _.trim(item?.pattern));
1116
+ pm[item?.type].set(item?.name, extra_value);
1117
+ });
1118
+ }else{
1119
+ if(!_.isObject(result)){
1120
+ _.forEach(${JSON.stringify(item.data?.variables || [])}, (item) => {
1121
+ let extra_value = result;
1122
+ pm[item?.type].set(item?.name, extra_value);
1123
+ });
1124
+ }
1125
+ }
1126
+ }else{
1127
+ console.error(query, String(result))
1128
+ }
1129
+ }catch(e){};
1130
+ })();`;
1131
+ }
1132
+ break;
1133
+ case "wait": // done
1134
+ const timeout = _.toInteger(item?.data);
1135
+
1136
+ if (timeout > 0) {
1137
+ exec = `${exec}\nsleep(${timeout});`;
1138
+ }
1139
+ break;
1140
+ case "assert": //done
1141
+ exec = `${exec}
1142
+ !(function(){
1143
+ let assertObjectData = ${JSON.stringify(item)};
1144
+ let responseData = '';
1145
+ let expertData = null;
1146
+ let expertExpression = '';
1147
+ let expertValue = null;
1148
+
1149
+ if(_.get(assertObjectData, "data.type") == 'responseJson'){
1150
+ try{
1151
+ responseData = pm.response.json();
1152
+ }catch(e){
1153
+ responseData = xml2Json(pm.response.text())
1154
+ }
1155
+
1156
+ expertData = jsonpath.value(responseData, _.get(assertObjectData, "data.expression.path"));
1157
+ }else if(_.get(assertObjectData, "data.type") == 'responseXml'){
1158
+ try{
1159
+ responseData = pm.response.text();
1160
+ var xpath = require('xpath');
1161
+ var dom = require('xmldom').DOMParser;
1162
+ expertData = String(xpath.select(_.get(assertObjectData, "data.expression.path"), new dom().parseFromString(responseData, 'text/xml')));
1163
+ }catch(e){}
1164
+ }else if(_.get(assertObjectData, "data.type") == 'responseText'){
1165
+ expertData = pm.response.text();
1166
+ }else if(_.get(assertObjectData, "data.type") == 'responseHeader'){
1167
+ expertData = pm.response.headers.get(_.get(assertObjectData, "data.expression.path"));
1168
+ }else if(_.get(assertObjectData, "data.type") == 'responseCookie'){
1169
+ expertData = _.get(response.cookies, _.get(assertObjectData, "data.expression.path"));
1170
+ }else if(_.get(assertObjectData, "data.type") == 'responseCode'){
1171
+ expertData = pm.response.code;
1172
+ }else if(_.get(assertObjectData, "data.type") == 'responseTime'){
1173
+ expertData = pm.response.responseTime;
1174
+ }else if(_.get(assertObjectData, "data.type") == 'responseSize'){
1175
+ expertData = pm.response.responseSize;
1176
+ }else if(_.get(assertObjectData, "data.type") == 'tempVars'){
1177
+ expertData = pm.variables.get(_.get(assertObjectData, "data.expression.path"));
1178
+ }else if(_.get(assertObjectData, "data.type") == 'envVars'){
1179
+ expertData = pm.environment.get(_.get(assertObjectData, "data.expression.path"));
1180
+ }else if(_.get(assertObjectData, "data.type") == 'globalVars'){
1181
+ expertData = pm.globals.get(_.get(assertObjectData, "data.expression.path"));
1182
+ }
1183
+
1184
+ expertValue = pm.variables.replaceIn(_.get(assertObjectData, "data.expression.compareValue"));
1185
+
1186
+ if(_.get(assertObjectData, "data.expression.compareType") == "eq"){
1187
+ expertExpression = null;
1188
+ pm.test(_.get(assertObjectData, "name"), function () {
1189
+ pm.expect(String(expertData)).to.eql(String(expertValue));
1190
+ });
1191
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "uneq"){
1192
+ expertExpression = null;
1193
+ pm.test(_.get(assertObjectData, "name"), function () {
1194
+ pm.expect(String(expertData)).to.not.eql(String(expertValue));
1195
+ });
1196
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "lt"){
1197
+ expertExpression = null;
1198
+ pm.test(_.get(assertObjectData, "name"), function () {
1199
+ pm.expect(lodashv4.toNumber(expertData)).to.be.below(lodashv4.toNumber(expertValue));
1200
+ });
1201
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "lte"){
1202
+ expertExpression = null;
1203
+ pm.test(_.get(assertObjectData, "name"), function () {
1204
+ pm.expect(lodashv4.toNumber(expertData)).to.be.at.most(lodashv4.toNumber(expertValue));
1205
+ });
1206
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "gt"){
1207
+ expertExpression = null;
1208
+ pm.test(_.get(assertObjectData, "name"), function () {
1209
+ pm.expect(lodashv4.toNumber(expertData)).to.be.above(lodashv4.toNumber(expertValue));
1210
+ });
1211
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "gte"){
1212
+ expertExpression = null;
1213
+ pm.test(_.get(assertObjectData, "name"), function () {
1214
+ pm.expect(lodashv4.toNumber(expertData)).to.be.at.least(lodashv4.toNumber(expertValue));
1215
+ });
1216
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "includes"){
1217
+ expertExpression = null;
1218
+ pm.test(_.get(assertObjectData, "name"), function () {
1219
+ pm.expect(String(expertData)).to.include(String(expertValue));
1220
+ });
1221
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "unincludes"){
1222
+ expertExpression = null;
1223
+ pm.test(_.get(assertObjectData, "name"), function () {
1224
+ pm.expect(String(expertData)).to.not.include(String(expertValue));
1225
+ });
1226
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "null"){
1227
+ expertExpression = null;
1228
+ pm.test(_.get(assertObjectData, "name"), function () {
1229
+ pm.expect(expertData).to.be.empty;
1230
+ });
1231
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "notnull"){
1232
+ expertExpression = null;
1233
+ pm.test(_.get(assertObjectData, "name"), function () {
1234
+ pm.expect(String(expertData)).to.not.be.empty;
1235
+ });
1236
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "exist"){
1237
+ expertExpression = null;
1238
+ pm.test(_.get(assertObjectData, "name"), function () {
1239
+ pm.expect(expertData).to.exist;
1240
+ });
1241
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "notexist"){
1242
+ expertExpression = null;
1243
+ pm.test(_.get(assertObjectData, "name"), function () {
1244
+ pm.expect(expertData).to.not.exist;
1245
+ });
1246
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "regularmatch"){
1247
+ expertExpression = null;
1248
+
1249
+ if(!lodashv4.isEmpty(expertValue)){
1250
+ expertValue = new RegExp(lodashv4.trim(expertValue, '/'));
1251
+
1252
+ pm.test(_.get(assertObjectData, "name"), function () {
1253
+ pm.expect(expertData).to.match(expertValue);
1254
+ });
1255
+ }
1256
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "belongscollection"){
1257
+ expertExpression = null;
1258
+ pm.test(_.get(assertObjectData, "name"), function () {
1259
+ pm.expect(String(expertData)).to.be.oneOf(lodashv4.split(expertValue, ","));
1260
+ });
1261
+ }else if(_.get(assertObjectData, "data.expression.compareType") == "notbelongscollection"){
1262
+ expertExpression = null;
1263
+ pm.test(_.get(assertObjectData, "name"), function () {
1264
+ pm.expect(String(expertData)).to.not.be.oneOf(lodashv4.split(expertValue, ","));
1265
+ });
1266
+ }
1267
+ })();
1268
+ `;
1269
+ break;
1270
+ case "pickVars": //done
1271
+ const varTypeMap = {
1272
+ tempVars: "variables",
1273
+ envVars: "environment",
1274
+ globalVars: "globals",
1275
+ };
1276
+ exec = `${exec}\n
1277
+ !(function(){
1278
+ `
1279
+ switch (item.data?.source) {
1280
+ case "responseJson":
1281
+ exec = `${exec}\n
1282
+ let varSource = '';
1283
+
1284
+ try{
1285
+ varSource = pm.response.json();
1286
+ }catch(e){
1287
+ varSource = xml2Json(pm.response.text())
1288
+ }
1289
+ `;
1290
+ break;
1291
+ case "responseXml":
1292
+ case "responseText":
1293
+ exec = `${exec}\n
1294
+ let varSource = pm.response.text();
1295
+ `;
1296
+ break;
1297
+ case "responseHeader":
1298
+ exec = `${exec}\n
1299
+ let varSource = pm.response.headers;
1300
+ `;
1301
+ break;
1302
+ case "responseCookie":
1303
+ exec = `${exec}\n
1304
+ let varSource = response.cookies;
1305
+ `;
1306
+ break;
1307
+ case "responseCode":
1308
+ exec = `${exec}\n
1309
+ let varSource = pm.response.code;
1310
+ `;
1311
+ break;
1312
+ case "responseTime":
1313
+ exec = `${exec}\n
1314
+ let varSource = pm.response.responseTime;
1315
+ `;
1316
+ break;
1317
+ case "responseSize":
1318
+ exec = `${exec}\n
1319
+ let varSource = pm.response.responseSize;
1320
+ `;
1321
+ break;
1322
+ }
1323
+
1324
+ _.forEach(item.data?.variables, (varItem) => {
1325
+ if (_.isObject(varItem) && varItem?.name != "" && !_.isUndefined(varTypeMap[varItem?.type])) {
1326
+ switch (item.data?.source) {
1327
+ case "responseJson":
1328
+ exec = `${exec}\n
1329
+ !(function(){
1330
+ let pickVars = ${JSON.stringify(varItem)};
1331
+ pm[${JSON.stringify(varTypeMap[varItem?.type])}].set(_.get(pickVars,"name"), jsonpath.value(varSource, _.trim(_.get(pickVars,"expression"))));
1332
+ })();
1333
+ `;
1334
+ break;
1335
+ case "responseXml":
1336
+ exec = `${exec}\n
1337
+ !(function(){
1338
+ let pickVars = ${JSON.stringify(varItem)};
1339
+ let xmlValue = '';
1340
+ var xpath = require('xpath');
1341
+ var dom = require('xmldom').DOMParser;
1342
+
1343
+ try{
1344
+ xmlValue = String(xpath.select(_.trim(_.get(pickVars,"expression")), new dom().parseFromString(varSource, 'text/xml')));
1345
+ }catch(e){}
1346
+
1347
+ pm[${JSON.stringify(varTypeMap[varItem?.type])}].set(_.get(pickVars, "name"), xmlValue);
1348
+ })();
1349
+ `;
1350
+ break;
1351
+ case "responseHeader":
1352
+ exec = `${exec}\n
1353
+ !(function(){
1354
+ let pickVars = ${JSON.stringify(varItem)};
1355
+ try{
1356
+ pm[${JSON.stringify(varTypeMap[varItem?.type])}].set(_.get(pickVars,"name"), varSource.get(_.trim(_.get(pickVars,"expression"))));
1357
+ }catch(e){}
1358
+ })();
1359
+ `;
1360
+ break;
1361
+ case "responseCookie":
1362
+ exec = `${exec}\n
1363
+ !(function(){
1364
+ let pickVars = ${JSON.stringify(varItem)};
1365
+ pm[${JSON.stringify(varTypeMap[varItem?.type])}].set(_.get(pickVars,"name"), _.get(varSource, _.trim(_.get(pickVars,"expression"))));
1366
+ })();
1367
+ `;
1368
+ break;
1369
+ case "responseText":
1370
+ case "responseCode":
1371
+ case "responseTime":
1372
+ case "responseSize":
1373
+ exec = `${exec}\n
1374
+ !(function(){
1375
+ let pickVars = ${JSON.stringify(varItem)};
1376
+ pm[${JSON.stringify(varTypeMap[varItem?.type])}].set(_.trim(_.get(pickVars, "name")), varSource);
1377
+ })();
1378
+ `;
1379
+ break;
1380
+ }
1381
+ }
1382
+ }
1383
+ );
1384
+ exec = `${exec}
1385
+ })();`
1386
+ break;
1387
+ }
1388
+ }
1389
+ }
1390
+ }
1391
+ );
1392
+
1393
+ exec = `${exec}\n
1394
+ if(_.isObject(pm.response)){
1395
+ if(!_.isFunction(pm.response.originalText) || pm.response.originalText() == pm.response.text()){
1396
+ if(response?.raw?.responseText != pm.response.text()){
1397
+ pm.response.setBody(response?.raw?.responseText);
1398
+ }else if(pm.response?.raw?.responseText != pm.response.text()){
1399
+ pm.response.setBody(pm.response?.raw?.responseText);
1400
+ }
1401
+ }
1402
+ }
1403
+ `;
1404
+ let execArr = _.split(exec, "\n");
1405
+ // execArr.push("})()");
1406
+ pmEvent[eventMap[type]].push({
1407
+ listen: eventMap[type],
1408
+ script: {
1409
+ exec: execArr,
1410
+ type: "text/javascript",
1411
+ },
1412
+ });
1413
+ });
1414
+
1415
+ return pmEvent[listen];
1416
+ }
1417
+
1418
+ // 转换pm request为输出的request
1419
+ function convert2EchoRequest(request, requestJson, postmanJSON, history) {
1420
+ const cloneRequest = _.assign(_.cloneDeep(request), _.pick(requestJson, ['project_id', 'target_id', 'name']));
1421
+
1422
+ // 请求体类型
1423
+ cloneRequest.mode = _.get(requestJson, "request.body.mode");
1424
+
1425
+ // 其他请求参数
1426
+ try {
1427
+ cloneRequest.paths = _.fromPairs((_.get(postmanJSON, "url.variable") || []).map((item) => [item.key, item.value,])) || {};
1428
+ } catch (e) { }
1429
+
1430
+ try {
1431
+ const allRequestHeaders = _.mapValues(_.keyBy(_.get(history, 'execution.data[0].request.headers') || {}, 'key'), 'value');
1432
+
1433
+ if (!_.isEmpty(allRequestHeaders) && _.isObject(allRequestHeaders)) {
1434
+ cloneRequest.headers = allRequestHeaders;
1435
+ } else {
1436
+ cloneRequest.headers = _.reduce(cloneRequest.headers?.toJSON(), (obj, item) => {
1437
+ obj[item.key] = item.value;
1438
+ return obj;
1439
+ }, {}
1440
+ );
1441
+ }
1442
+ } catch (e) { }
1443
+
1444
+ try {
1445
+ cloneRequest.querys = cloneRequest.url?.query?.toObject();
1446
+ cloneRequest.url = String(cloneRequest.url);
1447
+ } catch (e) { }
1448
+
1449
+ try {
1450
+ cloneRequest.body = _.get(request, `body.${_.get(request, "body.mode")}`);
1451
+
1452
+ if (cloneRequest.mode == "msgpack") {
1453
+ const msgpack = require("msgpack5")();
1454
+ try {
1455
+ cloneRequest.body = JSON.stringify(msgpack.decode(Buffer.from(_.values(cloneRequest.body))));
1456
+ } catch (e) { }
1457
+ }
1458
+
1459
+ try {
1460
+ cloneRequest.body = cloneRequest.body.toObject();
1461
+ } catch (e) { }
1462
+ } catch (e) { }
1463
+
1464
+ try {
1465
+ cloneRequest.uri = request?.url.toJSON();
1466
+ _.forEach(cloneRequest.uri, (value, key) => {
1467
+ if (key == "query") {
1468
+ cloneRequest.uri[key] = value.toObject();
1469
+ } else if (key == "host") {
1470
+ cloneRequest.uri[key] = _.join(value, ".");
1471
+ } else if (key == "path") {
1472
+ cloneRequest.uri[key] = _.join(value, "/");
1473
+ } else {
1474
+ if (_.isArray(value)) {
1475
+ cloneRequest.uri[key] = _.join(value, "");
1476
+ }
1477
+ }
1478
+ });
1479
+ } catch (e) { }
1480
+
1481
+ // 获取cookies
1482
+ cloneRequest.cookies = {};
1483
+
1484
+ try {
1485
+ const cookiesString = cloneRequest.headers?.cookie;
1486
+ if (!_.isEmpty(cookiesString) && _.isString(cookiesString)) {
1487
+ _.forEach(_.split(cookiesString, ";"), (cookie) => {
1488
+ const { key, value } = tough.Cookie.parse(cookie).toJSON();
1489
+ cloneRequest.cookies[key] = value;
1490
+ });
1491
+ }
1492
+ } catch (e) { }
1493
+
1494
+ return cloneRequest;
1495
+ }
1496
+
1497
+ // 转换pm response为输出的response
1498
+ async function convert2EchoResponse(response, history) {
1499
+ const cloneResponse = _.cloneDeep(response);
1500
+ _.unset(cloneResponse, "_details");
1501
+
1502
+ // 响应体
1503
+ try {
1504
+ _.assign(cloneResponse, {
1505
+ body: String(cloneResponse.stream),
1506
+ });
1507
+ } catch (e) { }
1508
+
1509
+ // 判断适合什么格式输出
1510
+ try {
1511
+ let fitForShow = "Monaco";
1512
+ let mimeType = {
1513
+ ext: "json",
1514
+ mime: "application/json",
1515
+ };
1516
+
1517
+ if (isSvg(cloneResponse.body)) {
1518
+ _.assign(mimeType, {
1519
+ ext: "svg",
1520
+ mime: "image/svg+xml",
1521
+ });
1522
+ fitForShow = "Image";
1523
+ } else {
1524
+ const fileType = await FileType.fromBuffer(cloneResponse.stream);
1525
+
1526
+ if (_.isObject(fileType)) {
1527
+ _.assign(mimeType, fileType);
1528
+ if (isImage(`test.${mimeType?.ext}`)) {
1529
+ fitForShow = "Image";
1530
+ } else if (mimeType?.ext == "pdf") {
1531
+ fitForShow = "Pdf";
1532
+ } else if (mimeType?.ext == "xml") {
1533
+ fitForShow = "Monaco";
1534
+ } else {
1535
+ fitForShow = "Other";
1536
+ }
1537
+ } else {
1538
+ const contentType = getCaseInsensitive(cloneResponse?.headers || {}, "content-type") || "";
1539
+ if (!_.isEmpty(contentType)) {
1540
+ mimeType = {
1541
+ ext: mime.getExtension(contentType),
1542
+ mime: mime.getType(mime.getExtension(contentType)),
1543
+ };
1544
+ } else {
1545
+ const ext = aTools.isJson(cloneResponse.body) ? "json" : aTools.isJsonp(cloneResponse.body) ? "jsonp" : "html";
1546
+ mimeType = {
1547
+ ext: ext,
1548
+ mime: mime.getType(ext) || "application/jsonp",
1549
+ };
1550
+ }
1551
+ }
1552
+ }
1553
+
1554
+ _.assign(cloneResponse, { mimeType, fitForShow });
1555
+ } catch (e) { }
1556
+
1557
+ // 响应头对象
1558
+ const responseHeader = {};
1559
+ try {
1560
+ _.assign(
1561
+ responseHeader,
1562
+ _.reduce(
1563
+ response.headers?.toJSON(),
1564
+ (obj, item) => {
1565
+ if (obj[item.key]) {
1566
+ if (!Array.isArray(obj[item.key])) {
1567
+ obj[item.key] = [obj[item.key]];
1568
+ }
1569
+ obj[item.key].push(item.value);
1570
+ } else {
1571
+ obj[item.key] = item.value;
1572
+ }
1573
+ return obj;
1574
+ },
1575
+ {}
1576
+ )
1577
+ );
1578
+ } catch (e) { }
1579
+
1580
+ // 响应头
1581
+ try {
1582
+ _.assign(cloneResponse, {
1583
+ headers: responseHeader,
1584
+ });
1585
+ } catch (e) { }
1586
+
1587
+ // 缓存文件名
1588
+ let cacheFileName = `${cloneResponse?.id}.${cloneResponse?.mimeType?.ext}`;
1589
+ try {
1590
+ cacheFileName = _.get(contentDisposition.parse(getCaseInsensitive(responseHeader || {}, "content-disposition")), "parameters.filename");
1591
+
1592
+ if (_.isString(cacheFileName)) {
1593
+ try {
1594
+ cacheFileName = decodeURIComponent(cacheFileName);
1595
+ } catch (e) { }
1596
+ }
1597
+ } catch (e) { }
1598
+
1599
+ cloneResponse.filename = cacheFileName;
1600
+
1601
+ // cookie
1602
+ cloneResponse.cookies = {};
1603
+ cloneResponse.arrCookies = [];
1604
+
1605
+ let cookieArrs = getCaseInsensitive(responseHeader || {}, "set-cookie");
1606
+ if (_.isString(cookieArrs)) {
1607
+ cookieArrs = [cookieArrs];
1608
+ }
1609
+
1610
+ try {
1611
+ _.forEach(cookieArrs, (cookie) => {
1612
+ const cookieJson = tough.Cookie.parse(cookie).toJSON();
1613
+ _.assign(cookieJson, {
1614
+ name: cookieJson?.key,
1615
+ cookie_id: aTools.snowflakeId(`cookie_id_${uuidv4()}`),
1616
+ });
1617
+ cloneResponse.arrCookies.push(cookieJson);
1618
+ const { key, value } = cookieJson;
1619
+ cloneResponse.cookies[key] = value;
1620
+ });
1621
+ } catch (e) { }
1622
+
1623
+ const requestStart =
1624
+ _.get(history, "execution.data.0.timings.requestStart") || Date.now();
1625
+ _.assign(cloneResponse, {
1626
+ proxy: _.get(history, "execution.data.0.request.proxy") || {},
1627
+ timings: _.mapKeys(
1628
+ _.get(history, "execution.data.0.timings.offset") || {},
1629
+ (value, key) => _.snakeCase(key)
1630
+ ),
1631
+ requestStart,
1632
+ response_at: requestStart,
1633
+ });
1634
+
1635
+ return cloneResponse;
1636
+ }
1637
+
1638
+ const preProcessMockExp = (request, requestPara, AllVars, option) => {
1639
+ const { postmanJSON } = requestPara;
1640
+ const { lang, customFunctions } = option;
1641
+
1642
+ // 识别变量
1643
+ const regex = /{{([^}]+)}}/g;
1644
+
1645
+ // 替换 URL 中可能的变量
1646
+ let url = String(request?.url || '');
1647
+ if (!_.isEmpty(url)) {
1648
+ const matches = url.match(regex);
1649
+ if (!_.isEmpty(matches)) {
1650
+ _.forEach(matches, (match) => {
1651
+ try {
1652
+ const tmpVal = mockExp(match, AllVars, lang, customFunctions);
1653
+
1654
+ if (tmpVal != match && !_.isUndefined(tmpVal)) {
1655
+ url = _.replace(url, match, tmpVal);
1656
+ }
1657
+ } catch (e) { }
1658
+ })
1659
+
1660
+ _.set(request, 'url', new sdk.Url(url));
1661
+ }
1662
+ }
1663
+
1664
+ // 重置 restful
1665
+ _.forEach(_.get(postmanJSON, 'url.path'), (item, key) => { //variable
1666
+ // console.log(item)
1667
+ if (_.startsWith(item, ":")) {
1668
+ const pathVarKey = _.findKey(_.get(postmanJSON, 'url.variable'), (vars) => {
1669
+ return vars?.key == _.trimStart(item, ':')
1670
+ });
1671
+
1672
+ if (_.startsWith(_.get(postmanJSON, `url.variable.${pathVarKey}.value`), '{{') && _.endsWith(_.get(postmanJSON, `url.variable.${pathVarKey}.value`), '}}') && !_.isUndefined(_.get(request, `url.path.${key}`))) {
1673
+ _.set(postmanJSON, `url.variable.${pathVarKey}.value`, _.get(request, `url.path.${key}`));
1674
+ }
1675
+ }
1676
+ })
1677
+
1678
+ // 替换 Header 中可能的变量
1679
+ if (!_.isEmpty(request.headers)) {
1680
+ request?.headers?.each((item) => {
1681
+ if (!item?.disabled) {
1682
+ ['key', 'value'].forEach((type) => {
1683
+ let currentPara = String(_.get(item, type));
1684
+ const matches = currentPara.match(regex);
1685
+ if (!_.isEmpty(matches)) {
1686
+ _.forEach(matches, (match) => {
1687
+ try {
1688
+ const tmpVal = mockExp(match, AllVars, lang, customFunctions);
1689
+ if (tmpVal != match && !_.isUndefined(tmpVal)) {
1690
+ currentPara = _.replace(currentPara, match, tmpVal);
1691
+
1692
+ }
1693
+ } catch (e) { }
1694
+ })
1695
+
1696
+ _.set(item, type, currentPara)
1697
+ }
1698
+ })
1699
+ }
1700
+ })
1701
+ }
1702
+
1703
+ // 替换 body 中可能的变量
1704
+ const bodyMode = _.get(request, 'body.mode');
1705
+ switch (bodyMode) {
1706
+ case 'urlencoded':
1707
+ case 'formdata':
1708
+ if (!_.isEmpty(request?.body[bodyMode])) {
1709
+ request?.body[bodyMode].each((item, key) => {
1710
+ if (!item?.disabled) {
1711
+ ['key', 'value'].forEach((type) => {
1712
+ let currentPara = _.get(item, type);
1713
+ if (_.isString(currentPara)) {
1714
+ const matches = currentPara.match(regex);
1715
+
1716
+ if (!_.isEmpty(matches)) {
1717
+ _.forEach(matches, (match) => {
1718
+ try {
1719
+ const tmpVal = mockExp(match, AllVars, lang, customFunctions);
1720
+ if (tmpVal != match && !_.isUndefined(tmpVal)) {
1721
+ currentPara = _.replace(currentPara, match, tmpVal);
1722
+ }
1723
+ } catch (e) { }
1724
+ })
1725
+
1726
+ _.set(item, type, currentPara);
1727
+ }
1728
+ }
1729
+ })
1730
+ }
1731
+ })
1732
+ }
1733
+ break;
1734
+ default:
1735
+ let rawBody = _.get(request, 'body.raw');
1736
+ if (_.isString(rawBody) && !_.isEmpty(rawBody)) {
1737
+ const matches = rawBody.match(regex);
1738
+ if (!_.isEmpty(matches)) {
1739
+ _.forEach(matches, (match) => {
1740
+ try {
1741
+ const tmpVal = mockExp(match, AllVars, lang, customFunctions);
1742
+ if (tmpVal != match && !_.isUndefined(tmpVal)) {
1743
+ rawBody = _.replace(rawBody, match, tmpVal);
1744
+ }
1745
+ } catch (e) { }
1746
+ })
1747
+
1748
+ _.set(request, 'body.raw', rawBody);
1749
+ }
1750
+ }
1751
+ break;
1752
+ }
1753
+
1754
+ return request;
1755
+ }
1756
+
1757
+ // 初始化api请求参数
1758
+ const initRequestJson = (event, option) => {
1759
+ // 获取具体的请求详情
1760
+ const requestJson = _.assign(_.pick(event, ['event_id', 'test_id']), _.pick(event?.data, ['target_id', 'project_id']));
1761
+
1762
+ if (_.includes(['api', 'sample', 'sse', 'request'], event?.type)) {
1763
+ // 原接口信息
1764
+ if (_.toInteger(event?.auto_sync) > 0 || _.includes(['http_request', 'get_parsed_request'], option?.scene)) {
1765
+ _.assign(requestJson, getAPIFromCollection(option?.collection, _.get(event, `data.target_id`)));
1766
+ } else { // 从 data的 apiData 获取
1767
+ _.assign(requestJson, _.get(event, `data.apiData`));
1768
+ }
1769
+
1770
+ // 向上查询获取最终参数
1771
+ const parentIDs = [];
1772
+
1773
+ // 为向上查询获取最终参数做准备,获取正确的 parent_id
1774
+ if (_.includes(['sample'], event?.type)) {
1775
+ const sampleTargetID = _.get(getAPIFromCollection(option?.collection, _.get(event, `data.parent_id`)), 'target_id');
1776
+
1777
+ if (_.isString(sampleTargetID) && sampleTargetID) {
1778
+ getParentTargetIDs(option?.collection, requestJson?.sampleTargetID, parentIDs);
1779
+ }
1780
+ }
1781
+
1782
+ if (!_.includes(parentIDs, "0")) {
1783
+ parentIDs.push("0");
1784
+ }
1785
+
1786
+ // 设置 ["header", "body", "query", "cookie"]
1787
+ _.forEach(parentIDs, (parent_id) => {
1788
+ const request = {};
1789
+ if (parent_id == "0") {
1790
+ _.assign(request, _.get(option, "project.request"));
1791
+ } else {
1792
+ // 目录参数
1793
+ _.assign(request, _.get(getAPIFromCollection(option?.collection, parent_id), "request"));
1794
+ }
1795
+
1796
+ if (_.isObject(request) && !_.isEmpty(request)) {
1797
+ ["header", "body", "query", "cookie"].forEach((parameter) => {
1798
+ let arrPara = _.filter(_.get(request, `${parameter}.parameter`), (item) => { return _.toInteger(item.is_system) > 0 || item.is_checked > 0 });
1799
+
1800
+ if (!_.isEmpty(arrPara) && _.isArray(arrPara)) {
1801
+ const filterOrginParaArr = _.filter(_.get(requestJson, `request.${parameter}.parameter`), item => item.is_checked > 0) || []
1802
+ const orginPara = _.chain(filterOrginParaArr)
1803
+ .groupBy('key')
1804
+ .map((group) => _.reduce(group, (acc, item) => item.is_checked > 0 ? item : acc, group[group.length - 1]))
1805
+ .value();
1806
+
1807
+ const mergePara = _.chain(arrPara)
1808
+ .groupBy('key')
1809
+ .map((group) => _.reduce(group, (acc, item) => item.is_checked > 0 ? item : acc, group[group.length - 1]))
1810
+ .value();
1811
+
1812
+ if (parameter == 'header') {
1813
+ _.set(
1814
+ requestJson,
1815
+ `request.${parameter}.parameter`,
1816
+ _.unionBy(
1817
+ orginPara,
1818
+ mergePara,
1819
+ (value) => {
1820
+ return _.toLower(value['key']);
1821
+ }
1822
+ )
1823
+ );
1824
+ } else {
1825
+ _.set(
1826
+ requestJson,
1827
+ `request.${parameter}.parameter`,
1828
+ _.unionBy(
1829
+ orginPara,
1830
+ mergePara,
1831
+ "key"
1832
+ )
1833
+ );
1834
+ }
1835
+ }
1836
+ })
1837
+ }
1838
+ });
1839
+
1840
+ // 设置 ['auth,pre_script,test,pre_tasks,post_tasks']
1841
+ let commPara = {}, envServerID = _.get(requestJson, 'server_id');
1842
+ _.forEach(_.reverse(parentIDs), (parent_id) => {
1843
+ const request = {};
1844
+ if (parent_id == "0") {
1845
+ // 全局参数
1846
+ _.assign(request, _.get(option, "project.request"));
1847
+ } else {
1848
+ // 目录参数
1849
+ const parentEnvServerID = _.get(getAPIFromCollection(option?.collection, parent_id), "server_id");
1850
+ if (_.isUndefined(envServerID) && !_.isString(parentEnvServerID)) {
1851
+ envServerID = parentEnvServerID;
1852
+ }
1853
+
1854
+ _.assign(request, _.get(getAPIFromCollection(option?.collection, parent_id), "request"));
1855
+ }
1856
+
1857
+ if (_.isObject(request) && !_.isEmpty(request)) {
1858
+ ["auth", "pre_script", "test", "pre_tasks", "post_tasks",].forEach((parameter) => {
1859
+ const tmpPara = _.get(request, `${parameter}`);
1860
+
1861
+ if (!_.isEmpty(tmpPara)) {
1862
+ if (_.isArray(tmpPara)) {
1863
+ commPara[parameter] = _.union(commPara[parameter], tmpPara);
1864
+ } else if (_.isObject(tmpPara)) {
1865
+ if (parameter == "auth" && _.get(tmpPara, "type") != "inherit") {
1866
+ _.set(commPara, "auth.type", _.get(tmpPara, "type"));
1867
+ _.set(commPara, `auth.${_.get(tmpPara, "type")}`, _.get(tmpPara, `${_.get(tmpPara, "type")}`));
1868
+ }
1869
+ } else if (_.isString(tmpPara)) {
1870
+ commPara[parameter] = `${commPara[parameter]}\n${tmpPara}`;
1871
+ }
1872
+ }
1873
+ });
1874
+ }
1875
+ });
1876
+
1877
+ _.forEach(commPara, (paras, key) => {
1878
+ if (!_.isEmpty(paras)) {
1879
+ if (_.isArray(paras)) {
1880
+ _.set(requestJson, `request.${key}`, _.union(paras, _.get(requestJson, `request.${key}`)));
1881
+ } else if (_.isObject(paras)) {
1882
+ if (key == "auth" && _.get(requestJson, "request.auth.type") == "inherit") {
1883
+ _.set(requestJson, "request.auth.type", _.get(paras, "type"));
1884
+ _.set(requestJson, `request.auth.${_.get(paras, "type")}`, _.get(paras, `${_.get(paras, "type")}`));
1885
+ }
1886
+ } else if (_.isString(paras)) {
1887
+ _.set(requestJson, `request.${key}`, `${paras}\n${_.get(requestJson, `request.${key}`)}`);
1888
+ }
1889
+ }
1890
+ });
1891
+
1892
+ _.unset(commPara);
1893
+
1894
+ // 处理 cookie 控制器传来的cookie,并将其他cookie参数一并转为 cookieArr 数组
1895
+ const cookieArr = [];
1896
+ if (_.get(option, "cookies.switch") > 0 && _.isArray(_.get(option, "cookies.data"))) {
1897
+ // 先处理管理器的cookie
1898
+ _.forEach(_.get(option, "cookies.data"), (item) => {
1899
+ let key = _.trim(item?.key);
1900
+ if (_.isObject(item) && !_.isEmpty(key)) {
1901
+ let currentKey = _.find(cookieArr, _.matchesProperty("key", key));
1902
+
1903
+ // Fixed an issue where cookies do not take effect when domain input is irregular
1904
+ let cookieDomain = item?.domain;
1905
+ try {
1906
+ const domainParse = new Url(item?.domain);
1907
+ cookieDomain = _.join(domainParse?.host, '.')
1908
+ } catch (e) { }
1909
+
1910
+
1911
+ const currentCookie = {
1912
+ key: key,
1913
+ value: item?.value,
1914
+ domain: cookieDomain,
1915
+ path: (item?.path != 'undefined' ? item?.path : '/') || "/",
1916
+ expires: item?.expires || new Date(new Date().getTime() + 3600 * 1000),
1917
+ maxAge: item?.maxAge || 3600,
1918
+ secure: !!_.toInteger(item?.secure),
1919
+ httpOnly: !!_.toInteger(item?.httpOnly),
1920
+ sameSite: item?.sameSite || "strict",
1921
+ };
1922
+
1923
+ if (currentKey > -1) {
1924
+ cookieArr[currentKey] = currentCookie;
1925
+ } else {
1926
+ cookieArr.push(currentCookie);
1927
+ }
1928
+ }
1929
+ }
1930
+ );
1931
+ }
1932
+
1933
+ if (_.isArray(_.get(requestJson, "request.cookie.parameter"))) {
1934
+ // 处理接口中的cookie
1935
+ _.forEach(_.get(requestJson, "request.cookie.parameter"), (item) => {
1936
+ let key = _.trim(item?.key);
1937
+ if (_.isObject(item) && !_.isEmpty(key) && item?.is_checked > 0) {
1938
+ let currentKey = _.find(cookieArr, _.matchesProperty("key", key));
1939
+ let currentCookie = {
1940
+ key: key,
1941
+ value: item?.value,
1942
+ };
1943
+ if (currentKey > -1) {
1944
+ cookieArr[currentKey] = currentCookie;
1945
+ } else {
1946
+ cookieArr.push(currentCookie);
1947
+ }
1948
+ }
1949
+ }
1950
+ );
1951
+ }
1952
+
1953
+ _.set(requestJson, "request.cookie.parameter", cookieArr);
1954
+ _.unset(cookieArr);
1955
+
1956
+ // 前置URL
1957
+ if (!_.isString(envServerID)) {
1958
+ envServerID = "1";
1959
+ }
1960
+
1961
+ const requestUrl = _.isString(_.get(requestJson, 'url')) ? _.get(requestJson, 'url') : _.get(requestJson, 'request.url');
1962
+ const { globals, env } = option;
1963
+
1964
+ if (_.get(option, "env.env_id") == "2") {
1965
+ let requestUrlVarReplace = requestUrl;
1966
+
1967
+ try {
1968
+ _.forEach(_.assign({}, globals, _.get(env, 'environment')), (value, key) => {
1969
+ requestUrlVarReplace = replace2RegExp(requestUrlVarReplace, `{{${key}}}`, String(value))
1970
+ })
1971
+ requestUrlVarReplace = new Url(requestUrlVarReplace)
1972
+ _.unset(requestUrlVarReplace, 'host')
1973
+ } catch (e) { }
1974
+
1975
+ let mockID = requestJson?.target_id;
1976
+
1977
+ if (requestJson?.type == 'sample') {
1978
+ mockID = _.get(getAPIFromCollection(option?.collection, _.get(event, `data.parent_id`)), 'target_id') || mockID;
1979
+ }
1980
+
1981
+
1982
+ if (process && process?.IS_ECHOAPI) {
1983
+ requestUrlVarReplace.query.add({
1984
+ key: "echoapi_id",
1985
+ value: mockID
1986
+ });
1987
+ _.set(requestJson, "url", smartUrlJoin(`https://mock.echoapi.com/mock/${_.get(event, 'data.project_id')}/`, `${String(requestUrlVarReplace)}`));
1988
+ } else {
1989
+ requestUrlVarReplace.query.add({
1990
+ key: "apipost_id",
1991
+ value: mockID
1992
+ });
1993
+
1994
+ _.set(requestJson, "url", smartUrlJoin(`https://mock.apipost.net/mock/${_.get(event, 'data.project_id')}/`, `${String(requestUrlVarReplace)}`));
1995
+ }
1996
+ } else {
1997
+ const envPreUrl = _.trim(_.get(_.find(_.get(option, `env.env_pre_urls`), (server) => {
1998
+ return server?.server_id == envServerID;
1999
+ }), 'uri'));
2000
+
2001
+ if (envPreUrl != '') {
2002
+ if (!_.startsWith(envPreUrl, '{{') && !_.startsWith(_.toLower(envPreUrl), 'http://') && !_.startsWith(_.toLower(envPreUrl), 'https://')) {
2003
+ _.set(requestJson, "url", smartUrlJoin('http://', envPreUrl, requestUrl));
2004
+ } else {
2005
+ _.set(requestJson, "url", smartUrlJoin(envPreUrl, requestUrl));
2006
+ }
2007
+ }
2008
+ }
2009
+
2010
+ // 设置 initVarReplacedUrl
2011
+ let initVarReplacedUrl = requestJson?.url;
2012
+ _.forEach(_.assign({}, globals, _.get(env, 'environment')), (value, key) => {
2013
+ initVarReplacedUrl = replace2RegExp(initVarReplacedUrl, `{{${key}}}`, String(value))
2014
+ })
2015
+
2016
+ _.set(requestJson, "initVarReplacedUrl", initVarReplacedUrl);
2017
+ } else if (_.includes(['script', 'assert'], event?.type)) { // 脚本、断言 todo... 断言需要做成可视化的
2018
+ _.set(requestJson, "request.pre_tasks", [
2019
+ {
2020
+ type: "customScript",
2021
+ enabled: 1,
2022
+ data: event?.data?.content,
2023
+ },
2024
+ ]);
2025
+ } else if (_.includes(['sql'], event?.type)) { // 数据库
2026
+ _.set(requestJson, "request.pre_tasks", [
2027
+ {
2028
+ "type": "database",
2029
+ "id": event?.event_id,
2030
+ "name": "Database",
2031
+ "enabled": 1,
2032
+ "data": _.assign({
2033
+ "connectionId": "",
2034
+ "query": "",
2035
+ "isConsoleOutput": -1,
2036
+ "variables": []
2037
+ }, event?.data)
2038
+ }
2039
+ ])
2040
+ } else if (_.includes(['assert_visual'], event?.type)) {
2041
+ const { type, expression } = event?.data || {};
2042
+
2043
+ if (_.isString(type) && !_.isEmpty(expression)) {
2044
+ _.set(requestJson, "request.pre_tasks", [
2045
+ {
2046
+ "type": "assert",
2047
+ "id": event?.event_id,
2048
+ "name": "Visual assertion",
2049
+ "enabled": 1,
2050
+ "data": {
2051
+ type,
2052
+ "expression": _.assign({
2053
+ "compareType": "eq",
2054
+ "compareValue": "",
2055
+ "path": ""
2056
+ }, expression)
2057
+ }
2058
+ }
2059
+ ])
2060
+ }
2061
+ }
2062
+
2063
+ const postmanJSON = convert2PostmanRequest(requestJson, option);
2064
+ return { requestJson, postmanJSON };
2065
+ }
2066
+
2067
+ // module exports
2068
+ module.exports = (event, option, callback, eventRuntimeData, eventResultList) => {
2069
+ const { scene } = option;
2070
+ return new Promise((resolve) => {
2071
+ try {
2072
+ const { requestJson, postmanJSON } = initRequestJson(event, option)
2073
+ const collection = new sdk.Item({
2074
+ name: _.get(requestJson, "name") || "New request", request: postmanJSON, event: [], protocolProfileBehavior: {
2075
+ disableBodyPruning: true,
2076
+ disabledSystemHeaders: {
2077
+ 'accept': true,
2078
+ 'accept-encoding': true,
2079
+ 'connection': true
2080
+ }
2081
+ }
2082
+ });
2083
+ const options = convert2PostmanOptions({ requestJson, postmanJSON }, option, eventRuntimeData?.variables || {});
2084
+ const runner = new runtime.Runner();
2085
+
2086
+ runner.run(
2087
+ new sdk.Collection({
2088
+ info: {
2089
+ name: _.get(requestJson, "name") || "New request",
2090
+ },
2091
+ item: [collection]
2092
+ }), options, (err, run) => {
2093
+ if (err) {
2094
+ return;
2095
+ }
2096
+ run.start({
2097
+ // script error
2098
+ exception(cursor, err) {
2099
+ if (err) {
2100
+ const scriptType = _.get(cursor, cursor?.scriptId);
2101
+ _.set(eventRuntimeData, [event?.event_id, "exception", scriptType], err);
2102
+ _.set(eventRuntimeData, [event?.event_id, 'error'], {
2103
+ error_type: scriptType,
2104
+ message: err?.message
2105
+ })
2106
+ if (scriptType === 'prerequest') {
2107
+ run.abort();
2108
+ }
2109
+ }
2110
+ },
2111
+
2112
+ // script print
2113
+ console(cursor, level, ...args) {
2114
+ if (_.isUndefined(_.get(eventRuntimeData, [event?.event_id, "console"]))) {
2115
+ _.set(eventRuntimeData, [event?.event_id, "console"], []);
2116
+ }
2117
+
2118
+ eventRuntimeData[event?.event_id].console.push({ level, args })
2119
+ },
2120
+
2121
+ // Called just before sending a request
2122
+ beforeRequest(err, cursor, request, item) {
2123
+ const AllVars = getInsideVariables();
2124
+ ["variables", "globals", "environment"].forEach((varName) => {
2125
+ _.assign(AllVars, _.get(eventRuntimeData, `variables.${varName}`))
2126
+ })
2127
+ preProcessMockExp(request, postmanJSON, AllVars, _.pick(option, ['lang', 'custom_functions']))
2128
+ },
2129
+
2130
+ beforePrerequest(err, cursor, events, item) {
2131
+ if (!err) {
2132
+ const pmEvent = convert2PostmanEvent({ requestJson, postmanJSON }, "prerequest", option);
2133
+
2134
+ _.forEach(pmEvent, (event) => {
2135
+ const script = new PostmanEvent(event);
2136
+ events.push(script);
2137
+ _.set(cursor, script?.script?.id, script?.listen);
2138
+ });
2139
+ }
2140
+ },
2141
+
2142
+ prerequest(err, cursor, results, item) {
2143
+ if (!err) {
2144
+ _.forEach(results, (result) => {
2145
+ _.forEach(['_variables', 'environment', 'globals'], (varType) => {
2146
+ const currentVar = _.get(result, `result.${varType}`);
2147
+ try {
2148
+ _.forEach(currentVar.toObject(), (val, key) => {
2149
+ _.set(eventRuntimeData, ["variables", varType === '_variables' ? 'variables' : varType, key], val)
2150
+ })
2151
+ } catch (e) { }
2152
+ })
2153
+ })
2154
+ }
2155
+ },
2156
+
2157
+ response: async (err, cursor, response, request, item, cookies, history) => {
2158
+ if (!err) {
2159
+ if (!_.includes(['get_parsed_request'], scene)) {
2160
+ _.set(eventRuntimeData, [event?.event_id, "response"], await convert2EchoResponse(response, history));
2161
+ }
2162
+ } else {
2163
+ if (!_.includes(['script', 'sql'], event?.type)) {
2164
+ _.set(eventRuntimeData, [event?.event_id, "exception", 'prerequest'], String(err));
2165
+ _.set(eventRuntimeData, [event?.event_id, 'error'], {
2166
+ error_type: 'prerequest',
2167
+ message: String(err)
2168
+ })
2169
+ }
2170
+ }
2171
+
2172
+ _.set(eventRuntimeData, [event?.event_id, "request"], convert2EchoRequest(request, requestJson, postmanJSON, history));
2173
+ },
2174
+
2175
+ beforeTest(err, cursor, events, item) {
2176
+ if (!err) {
2177
+ if (!_.includes(['get_parsed_request'], scene)) {
2178
+ const pmEvent = convert2PostmanEvent({ requestJson, postmanJSON }, "test", option);
2179
+ _.forEach(pmEvent, (event) => {
2180
+ const script = new PostmanEvent(event);
2181
+ events.push(script);
2182
+ _.set(cursor, script?.script?.id, script?.listen);
2183
+ });
2184
+ }
2185
+ }
2186
+ },
2187
+
2188
+ test(err, cursor, results, item) {
2189
+ if (!err) {
2190
+ if (!_.includes(['get_parsed_request'], scene)) {
2191
+ _.forEach(results, (result) => {
2192
+ _.forEach(['_variables', 'environment', 'globals'], (varType) => {
2193
+ const currentVar = _.get(result, `result.${varType}`);
2194
+ try {
2195
+ _.forEach(currentVar.toObject(), (val, key) => {
2196
+ _.set(eventRuntimeData, ["variables", varType === '_variables' ? 'variables' : varType, key], val)
2197
+ })
2198
+ } catch (e) { }
2199
+ })
2200
+ })
2201
+ }
2202
+ }
2203
+ },
2204
+
2205
+ assertion(cursor, assertions) {
2206
+ if (!_.includes(['get_parsed_request'], scene)) {
2207
+ if (!_.isEmpty(assertions) && _.isArray(assertions)) {
2208
+ if (_.isUndefined(_.get(eventRuntimeData, [event?.event_id, "assertions"]))) {
2209
+ _.set(eventRuntimeData, [event?.event_id, "assertions"], []);
2210
+ }
2211
+
2212
+ eventRuntimeData[event?.event_id].assertions = _.unionWith(_.concat(_.get(eventRuntimeData, event?.event_id, "assertions"), assertions), _.isEqual);
2213
+ }
2214
+ }
2215
+ },
2216
+
2217
+ item(err, cursor, item, visualizer, result) {
2218
+ if (!err && _.isObject(visualizer)) {
2219
+ const { error, processed_template } = visualizer;
2220
+ _.set(eventRuntimeData[event?.event_id], "visualizer", { error, processed_template });
2221
+ } else {
2222
+ _.set(eventRuntimeData[event?.event_id], "visualizer", { error: null, processed_template: "" });
2223
+ }
2224
+ },
2225
+
2226
+ responseData(cursor, data) {
2227
+ callback({
2228
+ action: "sse",
2229
+ data: {
2230
+ stream: data,
2231
+ size: _.size(data),
2232
+ time: Date.now()
2233
+ },
2234
+ msg: "success",
2235
+ error: null,
2236
+ })
2237
+ },
2238
+
2239
+ done(err, summary) {
2240
+ if (!_.includes(['get_parsed_request'], scene)) {
2241
+ if (!err) {
2242
+ const success_assert = _.map(_.get(eventRuntimeData, [event?.event_id, "assertions"]), (item) => {
2243
+ return item?.passed === false
2244
+ })
2245
+
2246
+ _.set(eventRuntimeData, [event?.event_id, "status"], {
2247
+ assert: [event?.event_id, "assertions"],
2248
+ success_assert,
2249
+ http: _.get(eventRuntimeData, [event?.event_id, 'response', 'status']) || _.get(eventRuntimeData, [event?.event_id, 'error', 'message'])
2250
+ });
2251
+ }
2252
+
2253
+ // 写入到自动化测试结果
2254
+ if (scene === 'auto_test' && _.includes(['assert', 'assert_visual', 'api', 'sample'], event?.type)) {
2255
+ eventResultList.push(_.assign(_.get(eventRuntimeData, event?.event_id), _.pick(event, ['type', 'event_id', 'test_id']), {
2256
+ iteration_id: aTools.snowflakeId()
2257
+ }))
2258
+ }
2259
+ }
2260
+
2261
+ resolve({
2262
+ action: 'httpRequestCompleted',
2263
+ data: _.get(eventRuntimeData, event?.event_id),
2264
+ error: _.get(eventRuntimeData, [event?.event_id, 'error', 'message']) || null,
2265
+ event_id: event?.event_id,
2266
+ target_id: requestJson?.target_id
2267
+ })
2268
+ }
2269
+ })
2270
+ }
2271
+ );
2272
+ } catch (e) {
2273
+ resolve({
2274
+ action: 'stystemError',
2275
+ message: String(e),
2276
+ current_event_id: event?.event_id
2277
+ })
2278
+ }
2279
+ });
2280
+ }