runner-runtime 1.0.14 → 1.0.17
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 +29 -13
- package/events/index.js +11 -5
- package/index.js +20 -16
- package/libs/2har.js +148 -0
- package/package.json +5 -3
- package/test.js +2 -2
- package/tmp/request.js +1 -1
package/events/api.js
CHANGED
|
@@ -10,6 +10,8 @@ const FileType = require("file-type"),
|
|
|
10
10
|
Buffer = require("buffer/").Buffer,
|
|
11
11
|
isImage = require("is-image");
|
|
12
12
|
const { getAPIFromCollection, smartUrlJoin, replace2RegExp, getParentTargetIDs, base64toCacheFile, getInsideVariables, getCaseInsensitive, camelCaseToSnakeCase } = require('../libs/utils'),
|
|
13
|
+
{ generateHarFromRequest } = require('../libs/2har'),
|
|
14
|
+
|
|
13
15
|
_ = require('lodash');
|
|
14
16
|
const sdk = require("postman-collection"),
|
|
15
17
|
Url = sdk.Url,
|
|
@@ -2172,7 +2174,15 @@ module.exports = (event, option, callback, eventRuntimeData, eventResultList) =>
|
|
|
2172
2174
|
}
|
|
2173
2175
|
}
|
|
2174
2176
|
|
|
2175
|
-
|
|
2177
|
+
const requestOptions = convert2EchoRequest(request, requestJson, postmanJSON, history);
|
|
2178
|
+
_.set(eventRuntimeData, [event?.event_id, "request"], requestOptions);
|
|
2179
|
+
|
|
2180
|
+
if (_.includes(['get_parsed_request'], scene)) {
|
|
2181
|
+
resolve(generateHarFromRequest(request));
|
|
2182
|
+
try {
|
|
2183
|
+
run.abort();
|
|
2184
|
+
} catch (e) { }
|
|
2185
|
+
}
|
|
2176
2186
|
},
|
|
2177
2187
|
|
|
2178
2188
|
beforeTest(err, cursor, events, item) {
|
|
@@ -2254,21 +2264,27 @@ module.exports = (event, option, callback, eventRuntimeData, eventResultList) =>
|
|
|
2254
2264
|
}
|
|
2255
2265
|
|
|
2256
2266
|
// 写入到自动化测试结果
|
|
2267
|
+
const finalRequestResult = _.assign({
|
|
2268
|
+
action: 'httpRequestCompleted',
|
|
2269
|
+
data: camelCaseToSnakeCase(_.get(eventRuntimeData, event?.event_id)),
|
|
2270
|
+
error: _.get(eventRuntimeData, [event?.event_id, 'error', 'message']) || null,
|
|
2271
|
+
event_id: event?.event_id,
|
|
2272
|
+
iteration_id: _.get(eventRuntimeData, [event?.event_id, 'iteration_id'])
|
|
2273
|
+
}, _.pick(requestJson, ['parent_id', 'project_id', 'test_id', 'target_id']));
|
|
2274
|
+
|
|
2257
2275
|
if (scene === 'auto_test' && _.includes(['assert', 'assert_visual', 'api', 'sample'], event?.type)) {
|
|
2258
|
-
eventResultList.push(_.assign(camelCaseToSnakeCase(_.get(eventRuntimeData, event?.event_id)), _.pick(event, ['type', 'event_id', 'test_id'])
|
|
2259
|
-
|
|
2260
|
-
|
|
2276
|
+
eventResultList.push(_.assign(camelCaseToSnakeCase(_.get(eventRuntimeData, event?.event_id)), _.pick(event, ['type', 'event_id', 'test_id', 'iteration_id'])));
|
|
2277
|
+
|
|
2278
|
+
resolve({
|
|
2279
|
+
action: 'request',
|
|
2280
|
+
data: _.assign(finalRequestResult, {
|
|
2281
|
+
type: 'request'
|
|
2282
|
+
})
|
|
2283
|
+
})
|
|
2284
|
+
} else {
|
|
2285
|
+
resolve(finalRequestResult)
|
|
2261
2286
|
}
|
|
2262
2287
|
}
|
|
2263
|
-
|
|
2264
|
-
resolve(_.assign({
|
|
2265
|
-
action: 'httpRequestCompleted',
|
|
2266
|
-
data: camelCaseToSnakeCase(_.get(eventRuntimeData, event?.event_id)),
|
|
2267
|
-
error: _.get(eventRuntimeData, [event?.event_id, 'error', 'message']) || null,
|
|
2268
|
-
event_id: event?.event_id,
|
|
2269
|
-
iteration_id: aTools.snowflakeId(),
|
|
2270
|
-
type: 'request'
|
|
2271
|
-
}, _.pick(requestJson, ['parent_id', 'project_id', 'test_id', 'target_id'])))
|
|
2272
2288
|
}
|
|
2273
2289
|
})
|
|
2274
2290
|
}
|
package/events/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const atomicSleep = require("atomic-sleep"),
|
|
2
2
|
jsonpath = require("jsonpath"),
|
|
3
|
+
aTools = require("apipost-tools"),
|
|
3
4
|
JSON5 = require('json5'),
|
|
4
5
|
_ = require('lodash'),
|
|
5
6
|
{ returnBoolean, variableReplace } = require('../libs/utils');
|
|
@@ -196,7 +197,9 @@ const events = {
|
|
|
196
197
|
const executeEvent = (event, option, callback, eventRuntimeData, eventResultList) => {
|
|
197
198
|
return new Promise((resolve, reject) => {
|
|
198
199
|
if (_.isUndefined(_.get(eventRuntimeData, event.event_id))) {
|
|
199
|
-
_.set(eventRuntimeData, event.event_id, {
|
|
200
|
+
_.set(eventRuntimeData, event.event_id, {
|
|
201
|
+
iteration_id: aTools.snowflakeId()
|
|
202
|
+
});
|
|
200
203
|
}
|
|
201
204
|
const eventCall = _.get(events, `${event?.type}`);
|
|
202
205
|
|
|
@@ -208,10 +211,13 @@ const executeEvent = (event, option, callback, eventRuntimeData, eventResultList
|
|
|
208
211
|
const { total, scene } = option;
|
|
209
212
|
if (scene == 'auto_test' && _.isInteger(event?.progress)) {
|
|
210
213
|
callback({
|
|
211
|
-
action: '
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
action: 'process',
|
|
215
|
+
data: {
|
|
216
|
+
processCurrentCount: event?.progress + 1,
|
|
217
|
+
processTotalCount: total,
|
|
218
|
+
event_id: event?.event_id,
|
|
219
|
+
testing_id: event?.test_id,
|
|
220
|
+
}
|
|
215
221
|
})
|
|
216
222
|
}
|
|
217
223
|
})
|
package/index.js
CHANGED
|
@@ -19,21 +19,6 @@ const run = async (events, option, callback) => {
|
|
|
19
19
|
if (scene == 'http_request') {
|
|
20
20
|
const event = _.first(tempEvents);
|
|
21
21
|
|
|
22
|
-
if (_.isObject(event) && _.has(event, 'type')) {
|
|
23
|
-
try {
|
|
24
|
-
const data = await executeEvent(event, _.assign(eventOptions, { iterationData: {} }), callback, eventRuntimeData, eventResultList);
|
|
25
|
-
callback(data)
|
|
26
|
-
} catch (e) {
|
|
27
|
-
callback(e);
|
|
28
|
-
|
|
29
|
-
if (_.includes(ABORT_RECURSION_ERROR, e?.action)) {
|
|
30
|
-
throw new Error(String(e?.message));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
} else if (scene == 'get_parsed_request') {
|
|
35
|
-
const event = _.first(tempEvents);
|
|
36
|
-
|
|
37
22
|
if (_.isObject(event) && _.has(event, 'type')) {
|
|
38
23
|
try {
|
|
39
24
|
const data = await executeEvent(event, _.assign(eventOptions, { iterationData: {} }), callback, eventRuntimeData, eventResultList);
|
|
@@ -72,4 +57,23 @@ const run = async (events, option, callback) => {
|
|
|
72
57
|
})
|
|
73
58
|
}
|
|
74
59
|
}
|
|
75
|
-
|
|
60
|
+
|
|
61
|
+
const request2HAR = async (events, option) => {
|
|
62
|
+
const eventOptions = _.pick(option, ["scene", "lang", "project", "env", "globals", "cookies", "system_configs", "custom_functions", "collection", "database_configs", "enable_sandbox", "sleep", "name", "testing_id"]);
|
|
63
|
+
const eventRuntimeData = {
|
|
64
|
+
variables: {}
|
|
65
|
+
};
|
|
66
|
+
const eventResultList = [];
|
|
67
|
+
const event = _.first(events);
|
|
68
|
+
|
|
69
|
+
if (_.isObject(event) && _.has(event, 'type')) {
|
|
70
|
+
try {
|
|
71
|
+
return await executeEvent(event, _.assign(eventOptions, { scene: 'get_parsed_request' }), () => { }, eventRuntimeData, eventResultList);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (_.includes(ABORT_RECURSION_ERROR, e?.action)) {
|
|
74
|
+
throw new Error(String(e?.message));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
module.exports = { run, request2HAR }
|
package/libs/2har.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a Postman-style request configuration into HAR format JSON.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} options - Request options based on Postman format.
|
|
5
|
+
* {
|
|
6
|
+
* url: string,
|
|
7
|
+
* method: string,
|
|
8
|
+
* headers: array,
|
|
9
|
+
* queryParams: array,
|
|
10
|
+
* body: {
|
|
11
|
+
* mode: string, // none | urlencoded | formdata | raw | json
|
|
12
|
+
* [urlencoded]: array, // For urlencoded form data
|
|
13
|
+
* [formdata]: array, // For multipart/form-data
|
|
14
|
+
* [raw]: string, // For raw (text or binary)
|
|
15
|
+
* [json]: object // For JSON body
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* @returns {Object} HAR format JSON object.
|
|
19
|
+
*/
|
|
20
|
+
function generateHarFromRequest(options) {
|
|
21
|
+
const {
|
|
22
|
+
url,
|
|
23
|
+
method = 'GET',
|
|
24
|
+
headers = [], // Array of { key, value }
|
|
25
|
+
queryParams = [], // Array of { key, value }
|
|
26
|
+
body = { mode: 'none' }, // Body in Postman format
|
|
27
|
+
} = options;
|
|
28
|
+
|
|
29
|
+
const har = {
|
|
30
|
+
log: {
|
|
31
|
+
version: '1.2',
|
|
32
|
+
creator: {
|
|
33
|
+
name: 'Custom Node Request to HAR Converter',
|
|
34
|
+
version: '1.0',
|
|
35
|
+
},
|
|
36
|
+
entries: [
|
|
37
|
+
{
|
|
38
|
+
request: {
|
|
39
|
+
method: method.toUpperCase(),
|
|
40
|
+
url: appendQueryParams(url, queryParams),
|
|
41
|
+
headers: processHeaders(headers),
|
|
42
|
+
queryString: processQueryString(queryParams),
|
|
43
|
+
postData: processBody(body),
|
|
44
|
+
headersSize: -1, // Optional, usually auto-calculated
|
|
45
|
+
bodySize: -1, // Optional, usually auto-calculated
|
|
46
|
+
},
|
|
47
|
+
startedDateTime: new Date().toISOString(),
|
|
48
|
+
time: 0, // Mock timing data (replace with actual timing if needed)
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return har;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Appends query parameters to a URL.
|
|
59
|
+
* @param {string} url - The base URL.
|
|
60
|
+
* @param {Array} queryParams - Array of { key: string, value: string }.
|
|
61
|
+
* @returns {string} URL with query parameters appended.
|
|
62
|
+
*/
|
|
63
|
+
function appendQueryParams(url, queryParams) {
|
|
64
|
+
if (!queryParams || queryParams.length === 0) return url;
|
|
65
|
+
|
|
66
|
+
const searchParams = new URLSearchParams();
|
|
67
|
+
queryParams.forEach(({ key, value }) => {
|
|
68
|
+
searchParams.append(key, value);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return `${url}?${searchParams.toString()}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Converts Postman-style headers into HAR format.
|
|
76
|
+
* @param {Array} headers - Array of { key: string, value: string }.
|
|
77
|
+
* @returns {Array} Array of HAR headers.
|
|
78
|
+
*/
|
|
79
|
+
function processHeaders(headers) {
|
|
80
|
+
return (headers || []).map(({ key, value }) => ({
|
|
81
|
+
name: key,
|
|
82
|
+
value: value,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Converts Postman-style query parameters into HAR format.
|
|
88
|
+
* @param {Array} queryParams - Array of { key: string, value: string }.
|
|
89
|
+
* @returns {Array} Array of HAR query parameters.
|
|
90
|
+
*/
|
|
91
|
+
function processQueryString(queryParams) {
|
|
92
|
+
return (queryParams || []).map(({ key, value }) => ({
|
|
93
|
+
name: key,
|
|
94
|
+
value: String(value),
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Processes the body into HAR format based on its mode.
|
|
100
|
+
* @param {Object} body - Postman-style body object with a defined mode.
|
|
101
|
+
* @returns {Object|undefined} HAR postData object.
|
|
102
|
+
*/
|
|
103
|
+
function processBody(body) {
|
|
104
|
+
const { mode } = body;
|
|
105
|
+
|
|
106
|
+
if (mode === 'none') {
|
|
107
|
+
return undefined; // No body
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (mode === 'urlencoded') {
|
|
111
|
+
return {
|
|
112
|
+
mimeType: 'application/x-www-form-urlencoded',
|
|
113
|
+
params: (body.urlencoded || []).map(({ key, value }) => ({
|
|
114
|
+
name: key,
|
|
115
|
+
value: String(value),
|
|
116
|
+
})),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (mode === 'formdata') {
|
|
121
|
+
return {
|
|
122
|
+
mimeType: 'multipart/form-data',
|
|
123
|
+
params: (body.formdata || []).map(({ key, value, type = 'text' }) => {
|
|
124
|
+
const param = { name: key, value: String(value) };
|
|
125
|
+
if (type === 'file') param.fileName = value; // File handling
|
|
126
|
+
return param;
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (mode === 'raw') {
|
|
132
|
+
return {
|
|
133
|
+
mimeType: 'text/plain',
|
|
134
|
+
text: String(body.raw),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (mode === 'json') {
|
|
139
|
+
return {
|
|
140
|
+
mimeType: 'application/json',
|
|
141
|
+
text: JSON.stringify(body.json || {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return undefined; // No body
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
module.exports = { generateHarFromRequest };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "runner-runtime",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.17",
|
|
4
|
+
"description": "runner-runtime.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "git+https://github.com/Apipost-Team/runner-runtime.git"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
|
-
"
|
|
14
|
+
"runner-runtime"
|
|
15
15
|
],
|
|
16
16
|
"author": "Daniel Anderson <support@echoapi.com> (https://github.com/Apipost-Team)",
|
|
17
17
|
"license": "MIT",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"apipost-tools": "^0.0.38",
|
|
25
25
|
"atomic-sleep": "^1.0.0",
|
|
26
26
|
"content-disposition": "^0.5.4",
|
|
27
|
+
"database-query": "^1.1.12",
|
|
27
28
|
"exp-mock": "^2.0.15",
|
|
28
29
|
"file-type": "^16.5.4",
|
|
29
30
|
"is-image": "^3.0.0",
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"net": "^1.0.2",
|
|
40
41
|
"postman-collection": "^5.0.2",
|
|
41
42
|
"postman-runtime-pro": "^7.43.13",
|
|
43
|
+
"request-har": "^1.0.0",
|
|
42
44
|
"strip-json-comments": "^5.0.1",
|
|
43
45
|
"tough": "^0.6.0",
|
|
44
46
|
"tough-cookie": "^5.1.2",
|
package/test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const _ =require('lodash');
|
|
2
|
-
const {
|
|
2
|
+
const { request2HAR } = require('./index');
|
|
3
3
|
|
|
4
4
|
// 以下为调用示例
|
|
5
5
|
const callback = (res) => {
|
|
@@ -121,4 +121,4 @@ const callback = (res) => {
|
|
|
121
121
|
})();
|
|
122
122
|
//pip end
|
|
123
123
|
const { option, test_events } = require('./tmp/request'); // tmp todo...
|
|
124
|
-
|
|
124
|
+
request2HAR(test_events, option, callback);
|