@midscene/cli 1.8.7 → 1.8.8-beta-20260601092817.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/dist/es/framework/index.mjs +3880 -0
- package/dist/es/framework/index.mjs.map +1 -0
- package/dist/es/index.mjs +368 -1155
- package/dist/es/index.mjs.map +1 -1
- package/dist/lib/framework/index.js +3989 -0
- package/dist/lib/framework/index.js.map +1 -0
- package/dist/lib/index.js +400 -1153
- package/dist/lib/index.js.map +1 -1
- package/dist/types/framework/index.d.ts +152 -0
- package/package.json +8 -7
package/dist/lib/index.js
CHANGED
|
@@ -3007,1152 +3007,375 @@ var __webpack_modules__ = {
|
|
|
3007
3007
|
};
|
|
3008
3008
|
module.exports = (string, columns, options)=>String(string).normalize().replace(/\r\n/g, '\n').split('\n').map((line)=>exec(line, columns, options)).join('\n');
|
|
3009
3009
|
},
|
|
3010
|
-
"./src/index.ts" (__unused_rspack_module,
|
|
3010
|
+
"./src/framework/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3011
3011
|
"use strict";
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
var
|
|
3016
|
-
|
|
3017
|
-
const cli_namespaceObject = require("@midscene/shared/cli");
|
|
3018
|
-
var main = __webpack_require__("../../node_modules/.pnpm/dotenv@16.4.5/node_modules/dotenv/lib/main.js");
|
|
3019
|
-
var main_default = /*#__PURE__*/ __webpack_require__.n(main);
|
|
3020
|
-
var package_namespaceObject = {
|
|
3021
|
-
rE: "1.8.7"
|
|
3022
|
-
};
|
|
3023
|
-
const yaml_namespaceObject = require("@midscene/core/yaml");
|
|
3012
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
3013
|
+
runFrameworkTestConfig: ()=>runFrameworkTestConfig
|
|
3014
|
+
});
|
|
3015
|
+
var external_node_fs_ = __webpack_require__("node:fs");
|
|
3016
|
+
var external_node_path_ = __webpack_require__("node:path");
|
|
3024
3017
|
const common_namespaceObject = require("@midscene/shared/common");
|
|
3025
|
-
const
|
|
3026
|
-
|
|
3027
|
-
var external_lodash_merge_default = /*#__PURE__*/ __webpack_require__.n(external_lodash_merge_namespaceObject);
|
|
3028
|
-
class Node {
|
|
3029
|
-
value;
|
|
3030
|
-
next;
|
|
3031
|
-
constructor(value){
|
|
3032
|
-
this.value = value;
|
|
3033
|
-
}
|
|
3034
|
-
}
|
|
3035
|
-
class Queue {
|
|
3036
|
-
#head;
|
|
3037
|
-
#tail;
|
|
3038
|
-
#size;
|
|
3039
|
-
constructor(){
|
|
3040
|
-
this.clear();
|
|
3041
|
-
}
|
|
3042
|
-
enqueue(value) {
|
|
3043
|
-
const node = new Node(value);
|
|
3044
|
-
if (this.#head) {
|
|
3045
|
-
this.#tail.next = node;
|
|
3046
|
-
this.#tail = node;
|
|
3047
|
-
} else {
|
|
3048
|
-
this.#head = node;
|
|
3049
|
-
this.#tail = node;
|
|
3050
|
-
}
|
|
3051
|
-
this.#size++;
|
|
3052
|
-
}
|
|
3053
|
-
dequeue() {
|
|
3054
|
-
const current = this.#head;
|
|
3055
|
-
if (!current) return;
|
|
3056
|
-
this.#head = this.#head.next;
|
|
3057
|
-
this.#size--;
|
|
3058
|
-
return current.value;
|
|
3059
|
-
}
|
|
3060
|
-
peek() {
|
|
3061
|
-
if (!this.#head) return;
|
|
3062
|
-
return this.#head.value;
|
|
3063
|
-
}
|
|
3064
|
-
clear() {
|
|
3065
|
-
this.#head = void 0;
|
|
3066
|
-
this.#tail = void 0;
|
|
3067
|
-
this.#size = 0;
|
|
3068
|
-
}
|
|
3069
|
-
get size() {
|
|
3070
|
-
return this.#size;
|
|
3071
|
-
}
|
|
3072
|
-
*[Symbol.iterator]() {
|
|
3073
|
-
let current = this.#head;
|
|
3074
|
-
while(current){
|
|
3075
|
-
yield current.value;
|
|
3076
|
-
current = current.next;
|
|
3077
|
-
}
|
|
3078
|
-
}
|
|
3079
|
-
*drain() {
|
|
3080
|
-
while(this.#head)yield this.dequeue();
|
|
3081
|
-
}
|
|
3082
|
-
}
|
|
3083
|
-
function pLimit(concurrency) {
|
|
3084
|
-
validateConcurrency(concurrency);
|
|
3085
|
-
const queue = new Queue();
|
|
3086
|
-
let activeCount = 0;
|
|
3087
|
-
const resumeNext = ()=>{
|
|
3088
|
-
if (activeCount < concurrency && queue.size > 0) {
|
|
3089
|
-
queue.dequeue()();
|
|
3090
|
-
activeCount++;
|
|
3091
|
-
}
|
|
3092
|
-
};
|
|
3093
|
-
const next = ()=>{
|
|
3094
|
-
activeCount--;
|
|
3095
|
-
resumeNext();
|
|
3096
|
-
};
|
|
3097
|
-
const run = async (function_, resolve, arguments_)=>{
|
|
3098
|
-
const result = (async ()=>function_(...arguments_))();
|
|
3099
|
-
resolve(result);
|
|
3100
|
-
try {
|
|
3101
|
-
await result;
|
|
3102
|
-
} catch {}
|
|
3103
|
-
next();
|
|
3104
|
-
};
|
|
3105
|
-
const enqueue = (function_, resolve, arguments_)=>{
|
|
3106
|
-
new Promise((internalResolve)=>{
|
|
3107
|
-
queue.enqueue(internalResolve);
|
|
3108
|
-
}).then(run.bind(void 0, function_, resolve, arguments_));
|
|
3109
|
-
(async ()=>{
|
|
3110
|
-
await Promise.resolve();
|
|
3111
|
-
if (activeCount < concurrency) resumeNext();
|
|
3112
|
-
})();
|
|
3113
|
-
};
|
|
3114
|
-
const generator = (function_, ...arguments_)=>new Promise((resolve)=>{
|
|
3115
|
-
enqueue(function_, resolve, arguments_);
|
|
3116
|
-
});
|
|
3117
|
-
Object.defineProperties(generator, {
|
|
3118
|
-
activeCount: {
|
|
3119
|
-
get: ()=>activeCount
|
|
3120
|
-
},
|
|
3121
|
-
pendingCount: {
|
|
3122
|
-
get: ()=>queue.size
|
|
3123
|
-
},
|
|
3124
|
-
clearQueue: {
|
|
3125
|
-
value () {
|
|
3126
|
-
queue.clear();
|
|
3127
|
-
}
|
|
3128
|
-
},
|
|
3129
|
-
concurrency: {
|
|
3130
|
-
get: ()=>concurrency,
|
|
3131
|
-
set (newConcurrency) {
|
|
3132
|
-
validateConcurrency(newConcurrency);
|
|
3133
|
-
concurrency = newConcurrency;
|
|
3134
|
-
queueMicrotask(()=>{
|
|
3135
|
-
while(activeCount < concurrency && queue.size > 0)resumeNext();
|
|
3136
|
-
});
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
});
|
|
3140
|
-
return generator;
|
|
3141
|
-
}
|
|
3142
|
-
function validateConcurrency(concurrency) {
|
|
3143
|
-
if (!((Number.isInteger(concurrency) || concurrency === 1 / 0) && concurrency > 0)) throw new TypeError('Expected `concurrency` to be a number from 1 and up');
|
|
3144
|
-
}
|
|
3145
|
-
const external_puppeteer_namespaceObject = require("puppeteer");
|
|
3146
|
-
var external_puppeteer_default = /*#__PURE__*/ __webpack_require__.n(external_puppeteer_namespaceObject);
|
|
3147
|
-
const external_http_server_namespaceObject = require("http-server");
|
|
3148
|
-
const external_node_assert_namespaceObject = require("node:assert");
|
|
3149
|
-
var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
|
|
3150
|
-
const agent_namespaceObject = require("@midscene/core/agent");
|
|
3151
|
-
const utils_namespaceObject = require("@midscene/core/utils");
|
|
3152
|
-
const logger_namespaceObject = require("@midscene/shared/logger");
|
|
3153
|
-
const bridge_mode_namespaceObject = require("@midscene/web/bridge-mode");
|
|
3154
|
-
const debug = (0, logger_namespaceObject.getDebug)('create-yaml-player');
|
|
3155
|
-
const launchServer = async (dir)=>new Promise((resolve)=>{
|
|
3156
|
-
const server = (0, external_http_server_namespaceObject.createServer)({
|
|
3157
|
-
root: dir
|
|
3158
|
-
});
|
|
3159
|
-
server.listen(0, '127.0.0.1', ()=>{
|
|
3160
|
-
resolve(server);
|
|
3161
|
-
});
|
|
3162
|
-
});
|
|
3163
|
-
function resolveReportFileName(yamlReportFileName, cliTestId, yamlTestId, fileName) {
|
|
3164
|
-
const baseName = yamlReportFileName ?? cliTestId ?? yamlTestId ?? fileName;
|
|
3165
|
-
return (0, agent_namespaceObject.getReportFileName)(baseName);
|
|
3166
|
-
}
|
|
3167
|
-
function buildAgentOptions(yamlAgent, reportFileName, fileName) {
|
|
3018
|
+
const notExecutedError = 'Not executed (previous task failed)';
|
|
3019
|
+
function execution_summary_createNotExecutedYamlResult(file) {
|
|
3168
3020
|
return {
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3021
|
+
file,
|
|
3022
|
+
success: false,
|
|
3023
|
+
executed: false,
|
|
3024
|
+
output: void 0,
|
|
3025
|
+
report: void 0,
|
|
3026
|
+
duration: 0,
|
|
3027
|
+
resultType: 'notExecuted',
|
|
3028
|
+
error: notExecutedError
|
|
3172
3029
|
};
|
|
3173
3030
|
}
|
|
3174
|
-
|
|
3175
|
-
const yamlScript = script || (0, yaml_namespaceObject.parseYamlScript)((0, external_node_fs_namespaceObject.readFileSync)(file, 'utf-8'), file);
|
|
3176
|
-
const clonedYamlScript = structuredClone(yamlScript);
|
|
3177
|
-
const fileName = (0, external_node_path_namespaceObject.basename)(file, (0, external_node_path_namespaceObject.extname)(file));
|
|
3178
|
-
const preference = {
|
|
3179
|
-
headed: options?.headed,
|
|
3180
|
-
keepWindow: options?.keepWindow,
|
|
3181
|
-
reportFileName: resolveReportFileName(clonedYamlScript.agent?.reportFileName, options?.testId, clonedYamlScript.agent?.testId, fileName)
|
|
3182
|
-
};
|
|
3183
|
-
const player = new yaml_namespaceObject.ScriptPlayer(clonedYamlScript, async ()=>{
|
|
3184
|
-
const freeFn = [];
|
|
3185
|
-
const webTarget = clonedYamlScript.web || clonedYamlScript.target;
|
|
3186
|
-
const targetCount = [
|
|
3187
|
-
void 0 !== webTarget,
|
|
3188
|
-
void 0 !== clonedYamlScript.android,
|
|
3189
|
-
void 0 !== clonedYamlScript.ios,
|
|
3190
|
-
void 0 !== clonedYamlScript.computer,
|
|
3191
|
-
void 0 !== clonedYamlScript.interface
|
|
3192
|
-
].filter(Boolean).length;
|
|
3193
|
-
if (targetCount > 1) {
|
|
3194
|
-
const specifiedTargets = [
|
|
3195
|
-
void 0 !== webTarget ? 'web' : null,
|
|
3196
|
-
void 0 !== clonedYamlScript.android ? 'android' : null,
|
|
3197
|
-
void 0 !== clonedYamlScript.ios ? 'ios' : null,
|
|
3198
|
-
void 0 !== clonedYamlScript.computer ? 'computer' : null,
|
|
3199
|
-
void 0 !== clonedYamlScript.interface ? 'interface' : null
|
|
3200
|
-
].filter(Boolean);
|
|
3201
|
-
throw new Error(`Only one target type can be specified, but found multiple: ${specifiedTargets.join(', ')}. Please specify only one of: web, android, ios, computer, or interface.`);
|
|
3202
|
-
}
|
|
3203
|
-
if (void 0 !== webTarget) {
|
|
3204
|
-
if (void 0 !== clonedYamlScript.target) console.warn("target is deprecated, please use web instead. See https://midscenejs.com/automate-with-scripts-in-yaml for more information. Sorry for the inconvenience.");
|
|
3205
|
-
let localServer;
|
|
3206
|
-
let urlToVisit;
|
|
3207
|
-
if (webTarget.serve) {
|
|
3208
|
-
external_node_assert_default()('string' == typeof webTarget.url, 'url is required in serve mode');
|
|
3209
|
-
localServer = await launchServer(webTarget.serve);
|
|
3210
|
-
const serverAddress = localServer.server.address();
|
|
3211
|
-
freeFn.push({
|
|
3212
|
-
name: 'local_server',
|
|
3213
|
-
fn: ()=>localServer?.server.close()
|
|
3214
|
-
});
|
|
3215
|
-
urlToVisit = webTarget.url.startsWith('/') ? `http://${serverAddress?.address}:${serverAddress?.port}${webTarget.url}` : `http://${serverAddress?.address}:${serverAddress?.port}/${webTarget.url}`;
|
|
3216
|
-
webTarget.url = urlToVisit;
|
|
3217
|
-
}
|
|
3218
|
-
if (webTarget.cdpEndpoint && webTarget.bridgeMode) throw new Error('cdpEndpoint and bridgeMode are mutually exclusive. Please specify only one.');
|
|
3219
|
-
if (webTarget.cdpEndpoint) {
|
|
3220
|
-
const cdpBrowser = options?.browser ?? await external_puppeteer_default().connect({
|
|
3221
|
-
browserWSEndpoint: webTarget.cdpEndpoint,
|
|
3222
|
-
defaultViewport: null
|
|
3223
|
-
});
|
|
3224
|
-
if (webTarget.chromeArgs) console.warn('chromeArgs are not supported in CDP mode (browser is already running). They will be ignored.');
|
|
3225
|
-
const { agent, freeFn: newFreeFn } = await (0, puppeteer_agent_launcher_namespaceObject.puppeteerAgentForTarget)(webTarget, {
|
|
3226
|
-
...preference,
|
|
3227
|
-
...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
|
|
3228
|
-
}, cdpBrowser, options?.page);
|
|
3229
|
-
const cleanFreeFn = newFreeFn.filter((f)=>'puppeteer_browser' !== f.name);
|
|
3230
|
-
if (!options?.browser) cleanFreeFn.push({
|
|
3231
|
-
name: 'cdp_browser_disconnect',
|
|
3232
|
-
fn: ()=>cdpBrowser.disconnect()
|
|
3233
|
-
});
|
|
3234
|
-
freeFn.push(...cleanFreeFn);
|
|
3235
|
-
return {
|
|
3236
|
-
agent,
|
|
3237
|
-
freeFn
|
|
3238
|
-
};
|
|
3239
|
-
}
|
|
3240
|
-
if (!webTarget.bridgeMode) {
|
|
3241
|
-
const { agent, freeFn: newFreeFn } = await (0, puppeteer_agent_launcher_namespaceObject.puppeteerAgentForTarget)(webTarget, {
|
|
3242
|
-
...preference,
|
|
3243
|
-
...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
|
|
3244
|
-
}, options?.browser, options?.page);
|
|
3245
|
-
freeFn.push(...newFreeFn);
|
|
3246
|
-
return {
|
|
3247
|
-
agent,
|
|
3248
|
-
freeFn
|
|
3249
|
-
};
|
|
3250
|
-
}
|
|
3251
|
-
external_node_assert_default()('newTabWithUrl' === webTarget.bridgeMode || 'currentTab' === webTarget.bridgeMode, `bridgeMode config value must be either "newTabWithUrl" or "currentTab", but got ${webTarget.bridgeMode}`);
|
|
3252
|
-
if (webTarget.userAgent || null != webTarget.viewportWidth || null != webTarget.viewportHeight || null != webTarget.deviceScaleFactor || webTarget.waitForNetworkIdle || webTarget.cookie || webTarget.chromeArgs) console.warn('puppeteer options (userAgent, viewportWidth, viewportHeight, deviceScaleFactor, waitForNetworkIdle, cookie, chromeArgs) are not supported in bridge mode. They will be ignored.');
|
|
3253
|
-
const agent = new bridge_mode_namespaceObject.AgentOverChromeBridge({
|
|
3254
|
-
closeNewTabsAfterDisconnect: webTarget.closeNewTabsAfterDisconnect,
|
|
3255
|
-
closeConflictServer: true,
|
|
3256
|
-
...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
|
|
3257
|
-
});
|
|
3258
|
-
if ('newTabWithUrl' === webTarget.bridgeMode) await agent.connectNewTabWithUrl(webTarget.url);
|
|
3259
|
-
else {
|
|
3260
|
-
if (webTarget.url) console.warn('url will be ignored in bridge mode with "currentTab"');
|
|
3261
|
-
await agent.connectCurrentTab();
|
|
3262
|
-
}
|
|
3263
|
-
freeFn.push({
|
|
3264
|
-
name: 'destroy_agent_over_chrome_bridge',
|
|
3265
|
-
fn: ()=>agent.destroy()
|
|
3266
|
-
});
|
|
3267
|
-
return {
|
|
3268
|
-
agent,
|
|
3269
|
-
freeFn
|
|
3270
|
-
};
|
|
3271
|
-
}
|
|
3272
|
-
if (void 0 !== clonedYamlScript.android) {
|
|
3273
|
-
const androidTarget = clonedYamlScript.android;
|
|
3274
|
-
const { agentFromAdbDevice } = await import("@midscene/android");
|
|
3275
|
-
const agent = await agentFromAdbDevice(androidTarget?.deviceId, {
|
|
3276
|
-
...androidTarget,
|
|
3277
|
-
...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
|
|
3278
|
-
});
|
|
3279
|
-
if (androidTarget?.launch) await agent.launch(androidTarget.launch);
|
|
3280
|
-
freeFn.push({
|
|
3281
|
-
name: 'destroy_android_agent',
|
|
3282
|
-
fn: ()=>agent.destroy()
|
|
3283
|
-
});
|
|
3284
|
-
return {
|
|
3285
|
-
agent,
|
|
3286
|
-
freeFn
|
|
3287
|
-
};
|
|
3288
|
-
}
|
|
3289
|
-
if (void 0 !== clonedYamlScript.ios) {
|
|
3290
|
-
const iosTarget = clonedYamlScript.ios;
|
|
3291
|
-
const { agentFromWebDriverAgent } = await import("@midscene/ios");
|
|
3292
|
-
const agent = await agentFromWebDriverAgent({
|
|
3293
|
-
...iosTarget,
|
|
3294
|
-
...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
|
|
3295
|
-
});
|
|
3296
|
-
if (iosTarget?.launch) await agent.launch(iosTarget.launch);
|
|
3297
|
-
freeFn.push({
|
|
3298
|
-
name: 'destroy_ios_agent',
|
|
3299
|
-
fn: ()=>agent.destroy()
|
|
3300
|
-
});
|
|
3301
|
-
return {
|
|
3302
|
-
agent,
|
|
3303
|
-
freeFn
|
|
3304
|
-
};
|
|
3305
|
-
}
|
|
3306
|
-
if (void 0 !== clonedYamlScript.computer) {
|
|
3307
|
-
const computerTarget = clonedYamlScript.computer;
|
|
3308
|
-
const { agentForComputer } = await import("@midscene/computer");
|
|
3309
|
-
const agent = await agentForComputer({
|
|
3310
|
-
...computerTarget,
|
|
3311
|
-
...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
|
|
3312
|
-
});
|
|
3313
|
-
freeFn.push({
|
|
3314
|
-
name: 'destroy_computer_agent',
|
|
3315
|
-
fn: ()=>agent.destroy()
|
|
3316
|
-
});
|
|
3317
|
-
return {
|
|
3318
|
-
agent,
|
|
3319
|
-
freeFn
|
|
3320
|
-
};
|
|
3321
|
-
}
|
|
3322
|
-
if (void 0 !== clonedYamlScript.interface) {
|
|
3323
|
-
const interfaceTarget = clonedYamlScript.interface;
|
|
3324
|
-
const moduleSpecifier = interfaceTarget.module;
|
|
3325
|
-
let finalModuleSpecifier;
|
|
3326
|
-
if (moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../') || external_node_path_default().isAbsolute(moduleSpecifier)) {
|
|
3327
|
-
const resolvedPath = (0, external_node_path_namespaceObject.join)(process.cwd(), moduleSpecifier);
|
|
3328
|
-
finalModuleSpecifier = resolvedPath;
|
|
3329
|
-
} else finalModuleSpecifier = moduleSpecifier;
|
|
3330
|
-
debug('importing module config', interfaceTarget.module, 'with export config', interfaceTarget.export, 'final module specifier', finalModuleSpecifier);
|
|
3331
|
-
const importedModule = await import(finalModuleSpecifier);
|
|
3332
|
-
const DeviceClass = interfaceTarget.export ? importedModule[interfaceTarget.export] : importedModule.default || importedModule;
|
|
3333
|
-
debug('DeviceClass', DeviceClass, 'with param', interfaceTarget.param);
|
|
3334
|
-
const device = new DeviceClass(interfaceTarget.param || {});
|
|
3335
|
-
debug('creating agent from device', device);
|
|
3336
|
-
const agent = (0, agent_namespaceObject.createAgent)(device, buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName));
|
|
3337
|
-
freeFn.push({
|
|
3338
|
-
name: 'destroy_general_interface_agent',
|
|
3339
|
-
fn: ()=>{
|
|
3340
|
-
agent.destroy();
|
|
3341
|
-
}
|
|
3342
|
-
});
|
|
3343
|
-
return {
|
|
3344
|
-
agent,
|
|
3345
|
-
freeFn
|
|
3346
|
-
};
|
|
3347
|
-
}
|
|
3348
|
-
throw new Error('No valid interface configuration found in the yaml script, should be either "web", "android", "ios", "computer", or "interface"');
|
|
3349
|
-
}, void 0, file);
|
|
3350
|
-
return player;
|
|
3351
|
-
}
|
|
3352
|
-
var chalk_source = __webpack_require__("../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/index.js");
|
|
3353
|
-
var source_default = /*#__PURE__*/ __webpack_require__.n(chalk_source);
|
|
3354
|
-
const isTTY = process.env.MIDSCENE_CLI_LOG_ON_NON_TTY ? false : process.stdout.isTTY;
|
|
3355
|
-
const printer_indent = ' ';
|
|
3356
|
-
const spinnerInterval = 80;
|
|
3357
|
-
const spinnerFrames = [
|
|
3358
|
-
'◰',
|
|
3359
|
-
'◳',
|
|
3360
|
-
'◲',
|
|
3361
|
-
'◱'
|
|
3362
|
-
];
|
|
3363
|
-
const currentSpinningFrame = ()=>spinnerFrames[Math.floor(Date.now() / spinnerInterval) % spinnerFrames.length];
|
|
3364
|
-
function indicatorForStatus(status) {
|
|
3365
|
-
if ('init' === status) return source_default().gray('◌');
|
|
3366
|
-
if ('running' === status) return source_default().yellowBright(currentSpinningFrame());
|
|
3367
|
-
if ('done' === status) return source_default().green('✔︎');
|
|
3368
|
-
if ('error' === status) return source_default().red('✘');
|
|
3369
|
-
}
|
|
3370
|
-
const contextInfo = (context)=>{
|
|
3371
|
-
const filePath = context.file;
|
|
3372
|
-
const filePathToShow = (0, external_node_path_namespaceObject.relative)(process.cwd(), filePath);
|
|
3373
|
-
const fileNameToPrint = `${source_default().gray(`${filePathToShow}`)}`;
|
|
3374
|
-
const fileStatusText = indicatorForStatus(context.player.status);
|
|
3375
|
-
const contextActionText = void 0 === context.player.currentTaskIndex && 'running' === context.player.status ? source_default().gray('(navigating)') : '';
|
|
3376
|
-
const errorText = context.player.errorInSetup ? `\n${printer_indent}${source_default().red('error:')} ${context.player.errorInSetup?.message}\n${printer_indent}${printer_indent}${context.player.errorInSetup?.stack}` : '';
|
|
3377
|
-
const outputFile = context.player.output;
|
|
3378
|
-
const outputText = outputFile && Object.keys(context.player.result || {}).length > 0 ? `\n${printer_indent}${source_default().gray(`output: ${outputFile}`)}` : '';
|
|
3379
|
-
const reportFile = context.player.reportFile;
|
|
3380
|
-
const reportText = reportFile ? `\n${printer_indent}${source_default().gray(`report: ${reportFile}`)}` : '';
|
|
3381
|
-
const agentStatusTip = context.player.agentStatusTip;
|
|
3382
|
-
const agentStatusText = agentStatusTip ? `\n${printer_indent}${source_default().gray(`agent status: ${agentStatusTip}`)}` : '';
|
|
3383
|
-
const mergedText = `${fileStatusText} ${fileNameToPrint} ${contextActionText}${outputText}${reportText}${errorText}${agentStatusText}`.trim();
|
|
3031
|
+
function getExecutionSummary(results) {
|
|
3384
3032
|
return {
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3033
|
+
total: results.length,
|
|
3034
|
+
successful: getResultsByType(results, 'success').length,
|
|
3035
|
+
failed: getResultsByType(results, 'failed').length,
|
|
3036
|
+
partialFailed: getResultsByType(results, 'partialFailed').length,
|
|
3037
|
+
notExecuted: getResultsByType(results, 'notExecuted').length,
|
|
3038
|
+
totalDuration: results.reduce((sum, r)=>sum + (r.duration || 0), 0)
|
|
3391
3039
|
};
|
|
3392
|
-
}
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
const
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
return {
|
|
3405
|
-
nameText: task.name,
|
|
3406
|
-
stepText,
|
|
3407
|
-
errorText,
|
|
3408
|
-
itemStatusText: statusText,
|
|
3409
|
-
mergedLine
|
|
3410
|
-
};
|
|
3411
|
-
};
|
|
3412
|
-
function paddingLines(lines) {
|
|
3413
|
-
return lines.map((line)=>`${printer_indent}${line}`);
|
|
3414
|
-
}
|
|
3415
|
-
const contextTaskListSummary = (taskStatusArray, context)=>{
|
|
3416
|
-
const prefixLines = [];
|
|
3417
|
-
const currentLine = [];
|
|
3418
|
-
const suffixText = [];
|
|
3419
|
-
const { mergedText: fileInfo } = contextInfo(context);
|
|
3420
|
-
if (!context.player.errorInSetup) for (const task of taskStatusArray){
|
|
3421
|
-
const { mergedLine } = singleTaskInfo(task);
|
|
3422
|
-
if ('init' === context.player.status) suffixText.push(mergedLine);
|
|
3423
|
-
else if ('running' === context.player.status) currentLine.push(mergedLine);
|
|
3424
|
-
else if ('done' === context.player.status) prefixLines.push(mergedLine);
|
|
3425
|
-
else if ('error' === context.player.status) prefixLines.push(mergedLine);
|
|
3426
|
-
}
|
|
3427
|
-
const lines = [
|
|
3428
|
-
fileInfo
|
|
3429
|
-
];
|
|
3430
|
-
if (prefixLines.length > 0) lines.push(...paddingLines(prefixLines));
|
|
3431
|
-
if (currentLine.length > 0) lines.push(...paddingLines(currentLine));
|
|
3432
|
-
if (suffixText.length > 0) lines.push(...paddingLines(suffixText));
|
|
3433
|
-
return lines.join('\n');
|
|
3434
|
-
};
|
|
3435
|
-
const external_node_util_namespaceObject = require("node:util");
|
|
3436
|
-
const external_node_process_namespaceObject = require("node:process");
|
|
3437
|
-
const copyProperty = (to, from, property, ignoreNonConfigurable)=>{
|
|
3438
|
-
if ('length' === property || 'prototype' === property) return;
|
|
3439
|
-
if ('arguments' === property || 'caller' === property) return;
|
|
3440
|
-
const toDescriptor = Object.getOwnPropertyDescriptor(to, property);
|
|
3441
|
-
const fromDescriptor = Object.getOwnPropertyDescriptor(from, property);
|
|
3442
|
-
if (!canCopyProperty(toDescriptor, fromDescriptor) && ignoreNonConfigurable) return;
|
|
3443
|
-
Object.defineProperty(to, property, fromDescriptor);
|
|
3444
|
-
};
|
|
3445
|
-
const canCopyProperty = function(toDescriptor, fromDescriptor) {
|
|
3446
|
-
return void 0 === toDescriptor || toDescriptor.configurable || toDescriptor.writable === fromDescriptor.writable && toDescriptor.enumerable === fromDescriptor.enumerable && toDescriptor.configurable === fromDescriptor.configurable && (toDescriptor.writable || toDescriptor.value === fromDescriptor.value);
|
|
3447
|
-
};
|
|
3448
|
-
const changePrototype = (to, from)=>{
|
|
3449
|
-
const fromPrototype = Object.getPrototypeOf(from);
|
|
3450
|
-
if (fromPrototype === Object.getPrototypeOf(to)) return;
|
|
3451
|
-
Object.setPrototypeOf(to, fromPrototype);
|
|
3452
|
-
};
|
|
3453
|
-
const wrappedToString = (withName, fromBody)=>`/* Wrapped ${withName}*/\n${fromBody}`;
|
|
3454
|
-
const toStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, 'toString');
|
|
3455
|
-
const toStringName = Object.getOwnPropertyDescriptor(Function.prototype.toString, 'name');
|
|
3456
|
-
const changeToString = (to, from, name)=>{
|
|
3457
|
-
const withName = '' === name ? '' : `with ${name.trim()}() `;
|
|
3458
|
-
const newToString = wrappedToString.bind(null, withName, from.toString());
|
|
3459
|
-
Object.defineProperty(newToString, 'name', toStringName);
|
|
3460
|
-
const { writable, enumerable, configurable } = toStringDescriptor;
|
|
3461
|
-
Object.defineProperty(to, 'toString', {
|
|
3462
|
-
value: newToString,
|
|
3463
|
-
writable,
|
|
3464
|
-
enumerable,
|
|
3465
|
-
configurable
|
|
3040
|
+
}
|
|
3041
|
+
function getResultsByType(results, resultType) {
|
|
3042
|
+
return results.filter((result)=>result.resultType === resultType);
|
|
3043
|
+
}
|
|
3044
|
+
function getSummaryAbsolutePath(summary) {
|
|
3045
|
+
return (0, external_node_path_.resolve)((0, common_namespaceObject.getMidsceneRunSubDir)('output'), summary);
|
|
3046
|
+
}
|
|
3047
|
+
function execution_summary_writeExecutionSummaryFile(summary, results) {
|
|
3048
|
+
const indexPath = getSummaryAbsolutePath(summary);
|
|
3049
|
+
const outputDir = (0, external_node_path_.dirname)(indexPath);
|
|
3050
|
+
(0, external_node_fs_.mkdirSync)(outputDir, {
|
|
3051
|
+
recursive: true
|
|
3466
3052
|
});
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
function_ = void 0;
|
|
3486
|
-
} else if (true === options.throw) throw new Error(`Function \`${functionName}\` can only be called once`);
|
|
3487
|
-
return returnValue;
|
|
3488
|
-
};
|
|
3489
|
-
mimicFunction(onetime, function_);
|
|
3490
|
-
calledFunctions.set(onetime, callCount);
|
|
3491
|
-
return onetime;
|
|
3492
|
-
};
|
|
3493
|
-
onetime_onetime.callCount = (function_)=>{
|
|
3494
|
-
if (!calledFunctions.has(function_)) throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`);
|
|
3495
|
-
return calledFunctions.get(function_);
|
|
3496
|
-
};
|
|
3497
|
-
const node_modules_onetime = onetime_onetime;
|
|
3498
|
-
const signals = [];
|
|
3499
|
-
signals.push('SIGHUP', 'SIGINT', 'SIGTERM');
|
|
3500
|
-
if ('win32' !== process.platform) signals.push('SIGALRM', 'SIGABRT', 'SIGVTALRM', 'SIGXCPU', 'SIGXFSZ', 'SIGUSR2', 'SIGTRAP', 'SIGSYS', 'SIGQUIT', 'SIGIOT');
|
|
3501
|
-
if ('linux' === process.platform) signals.push('SIGIO', 'SIGPOLL', 'SIGPWR', 'SIGSTKFLT');
|
|
3502
|
-
const processOk = (process1)=>!!process1 && 'object' == typeof process1 && 'function' == typeof process1.removeListener && 'function' == typeof process1.emit && 'function' == typeof process1.reallyExit && 'function' == typeof process1.listeners && 'function' == typeof process1.kill && 'number' == typeof process1.pid && 'function' == typeof process1.on;
|
|
3503
|
-
const kExitEmitter = Symbol.for('signal-exit emitter');
|
|
3504
|
-
const global = globalThis;
|
|
3505
|
-
const ObjectDefineProperty = Object.defineProperty.bind(Object);
|
|
3506
|
-
class Emitter {
|
|
3507
|
-
emitted = {
|
|
3508
|
-
afterExit: false,
|
|
3509
|
-
exit: false
|
|
3510
|
-
};
|
|
3511
|
-
listeners = {
|
|
3512
|
-
afterExit: [],
|
|
3513
|
-
exit: []
|
|
3053
|
+
const executionSummary = getExecutionSummary(results);
|
|
3054
|
+
const indexData = {
|
|
3055
|
+
summary: {
|
|
3056
|
+
...executionSummary,
|
|
3057
|
+
generatedAt: new Date().toLocaleString()
|
|
3058
|
+
},
|
|
3059
|
+
results: results.map((result)=>({
|
|
3060
|
+
script: (0, external_node_path_.relative)(outputDir, result.file),
|
|
3061
|
+
success: result.success,
|
|
3062
|
+
resultType: result.resultType,
|
|
3063
|
+
output: result.output ? (()=>{
|
|
3064
|
+
const relativePath = (0, external_node_path_.relative)(outputDir, result.output);
|
|
3065
|
+
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
|
|
3066
|
+
})() : void 0,
|
|
3067
|
+
report: result.report ? (0, external_node_path_.relative)(outputDir, result.report) : void 0,
|
|
3068
|
+
error: result.error,
|
|
3069
|
+
duration: result.duration
|
|
3070
|
+
}))
|
|
3514
3071
|
};
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3072
|
+
(0, external_node_fs_.writeFileSync)(indexPath, JSON.stringify(indexData, null, 2));
|
|
3073
|
+
return indexPath;
|
|
3074
|
+
}
|
|
3075
|
+
function execution_summary_printExecutionPlan(config) {
|
|
3076
|
+
console.log(' Scripts:');
|
|
3077
|
+
for (const file of config.files)console.log(` - ${file}`);
|
|
3078
|
+
console.log('📋 Execution plan');
|
|
3079
|
+
console.log(` Concurrency: ${config.concurrent}`);
|
|
3080
|
+
console.log(` Keep window: ${config.keepWindow}`);
|
|
3081
|
+
console.log(` Headed: ${config.headed}`);
|
|
3082
|
+
console.log(` Continue on error: ${config.continueOnError}`);
|
|
3083
|
+
console.log(` Share browser context: ${config.shareBrowserContext ?? false}`);
|
|
3084
|
+
console.log(` Summary output: ${config.summary}`);
|
|
3085
|
+
}
|
|
3086
|
+
function execution_summary_printExecutionFinished() {
|
|
3087
|
+
console.log('Execution finished:');
|
|
3088
|
+
}
|
|
3089
|
+
function printExecutionSummary(results, summaryPath) {
|
|
3090
|
+
const summary = getExecutionSummary(results);
|
|
3091
|
+
const successfulFiles = getResultsByType(results, 'success');
|
|
3092
|
+
const failedFiles = getResultsByType(results, 'failed');
|
|
3093
|
+
const partialFailedFiles = getResultsByType(results, 'partialFailed');
|
|
3094
|
+
const notExecutedFiles = getResultsByType(results, 'notExecuted');
|
|
3095
|
+
const success = 0 === summary.failed && 0 === summary.partialFailed && 0 === summary.notExecuted;
|
|
3096
|
+
console.log('\n📊 Execution Summary:');
|
|
3097
|
+
console.log(` Total files: ${summary.total}`);
|
|
3098
|
+
console.log(` Successful: ${summary.successful}`);
|
|
3099
|
+
console.log(` Failed: ${summary.failed}`);
|
|
3100
|
+
console.log(` Partial failed: ${summary.partialFailed}`);
|
|
3101
|
+
console.log(` Not executed: ${summary.notExecuted}`);
|
|
3102
|
+
console.log(` Duration: ${(summary.totalDuration / 1000).toFixed(2)}s`);
|
|
3103
|
+
console.log(` Summary: ${summaryPath}`);
|
|
3104
|
+
if (successfulFiles.length > 0) {
|
|
3105
|
+
console.log('\n✅ Successful files:');
|
|
3106
|
+
successfulFiles.forEach((result)=>{
|
|
3107
|
+
console.log(` ${result.file}`);
|
|
3524
3108
|
});
|
|
3525
3109
|
}
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
if (-1 === i) return;
|
|
3533
|
-
if (0 === i && 1 === list.length) list.length = 0;
|
|
3534
|
-
else list.splice(i, 1);
|
|
3535
|
-
}
|
|
3536
|
-
emit(ev, code, signal) {
|
|
3537
|
-
if (this.emitted[ev]) return false;
|
|
3538
|
-
this.emitted[ev] = true;
|
|
3539
|
-
let ret = false;
|
|
3540
|
-
for (const fn of this.listeners[ev])ret = true === fn(code, signal) || ret;
|
|
3541
|
-
if ('exit' === ev) ret = this.emit('afterExit', code, signal) || ret;
|
|
3542
|
-
return ret;
|
|
3110
|
+
if (failedFiles.length > 0) {
|
|
3111
|
+
console.log('\n❌ Failed files');
|
|
3112
|
+
failedFiles.forEach((result)=>{
|
|
3113
|
+
console.log(` ${result.file}`);
|
|
3114
|
+
if (result.error) console.log(` Error: ${result.error}`);
|
|
3115
|
+
});
|
|
3543
3116
|
}
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
},
|
|
3551
|
-
load () {
|
|
3552
|
-
return handler.load();
|
|
3553
|
-
},
|
|
3554
|
-
unload () {
|
|
3555
|
-
return handler.unload();
|
|
3556
|
-
}
|
|
3557
|
-
});
|
|
3558
|
-
class SignalExitFallback extends SignalExitBase {
|
|
3559
|
-
onExit() {
|
|
3560
|
-
return ()=>{};
|
|
3561
|
-
}
|
|
3562
|
-
load() {}
|
|
3563
|
-
unload() {}
|
|
3564
|
-
}
|
|
3565
|
-
class SignalExit extends SignalExitBase {
|
|
3566
|
-
#hupSig = 'win32' === mjs_process.platform ? 'SIGINT' : 'SIGHUP';
|
|
3567
|
-
#emitter = new Emitter();
|
|
3568
|
-
#process;
|
|
3569
|
-
#originalProcessEmit;
|
|
3570
|
-
#originalProcessReallyExit;
|
|
3571
|
-
#sigListeners = {};
|
|
3572
|
-
#loaded = false;
|
|
3573
|
-
constructor(process1){
|
|
3574
|
-
super();
|
|
3575
|
-
this.#process = process1;
|
|
3576
|
-
this.#sigListeners = {};
|
|
3577
|
-
for (const sig of signals)this.#sigListeners[sig] = ()=>{
|
|
3578
|
-
const listeners = this.#process.listeners(sig);
|
|
3579
|
-
let { count } = this.#emitter;
|
|
3580
|
-
const p = process1;
|
|
3581
|
-
if ('object' == typeof p.__signal_exit_emitter__ && 'number' == typeof p.__signal_exit_emitter__.count) count += p.__signal_exit_emitter__.count;
|
|
3582
|
-
if (listeners.length === count) {
|
|
3583
|
-
this.unload();
|
|
3584
|
-
const ret = this.#emitter.emit('exit', null, sig);
|
|
3585
|
-
const s = 'SIGHUP' === sig ? this.#hupSig : sig;
|
|
3586
|
-
if (!ret) process1.kill(process1.pid, s);
|
|
3587
|
-
}
|
|
3588
|
-
};
|
|
3589
|
-
this.#originalProcessReallyExit = process1.reallyExit;
|
|
3590
|
-
this.#originalProcessEmit = process1.emit;
|
|
3591
|
-
}
|
|
3592
|
-
onExit(cb, opts) {
|
|
3593
|
-
if (!processOk(this.#process)) return ()=>{};
|
|
3594
|
-
if (false === this.#loaded) this.load();
|
|
3595
|
-
const ev = opts?.alwaysLast ? 'afterExit' : 'exit';
|
|
3596
|
-
this.#emitter.on(ev, cb);
|
|
3597
|
-
return ()=>{
|
|
3598
|
-
this.#emitter.removeListener(ev, cb);
|
|
3599
|
-
if (0 === this.#emitter.listeners['exit'].length && 0 === this.#emitter.listeners['afterExit'].length) this.unload();
|
|
3600
|
-
};
|
|
3117
|
+
if (partialFailedFiles.length > 0) {
|
|
3118
|
+
console.log('\n⚠️ Partial failed files (some tasks failed with continueOnError)');
|
|
3119
|
+
partialFailedFiles.forEach((result)=>{
|
|
3120
|
+
console.log(` ${result.file}`);
|
|
3121
|
+
if (result.error) console.log(` Error: ${result.error}`);
|
|
3122
|
+
});
|
|
3601
3123
|
}
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
for (const sig of signals)try {
|
|
3607
|
-
const fn = this.#sigListeners[sig];
|
|
3608
|
-
if (fn) this.#process.on(sig, fn);
|
|
3609
|
-
} catch (_) {}
|
|
3610
|
-
this.#process.emit = (ev, ...a)=>this.#processEmit(ev, ...a);
|
|
3611
|
-
this.#process.reallyExit = (code)=>this.#processReallyExit(code);
|
|
3612
|
-
}
|
|
3613
|
-
unload() {
|
|
3614
|
-
if (!this.#loaded) return;
|
|
3615
|
-
this.#loaded = false;
|
|
3616
|
-
signals.forEach((sig)=>{
|
|
3617
|
-
const listener = this.#sigListeners[sig];
|
|
3618
|
-
if (!listener) throw new Error('Listener not defined for signal: ' + sig);
|
|
3619
|
-
try {
|
|
3620
|
-
this.#process.removeListener(sig, listener);
|
|
3621
|
-
} catch (_) {}
|
|
3124
|
+
if (notExecutedFiles.length > 0) {
|
|
3125
|
+
console.log('\n⏸️ Not executed files');
|
|
3126
|
+
notExecutedFiles.forEach((result)=>{
|
|
3127
|
+
console.log(` ${result.file}`);
|
|
3622
3128
|
});
|
|
3623
|
-
this.#process.emit = this.#originalProcessEmit;
|
|
3624
|
-
this.#process.reallyExit = this.#originalProcessReallyExit;
|
|
3625
|
-
this.#emitter.count -= 1;
|
|
3626
|
-
}
|
|
3627
|
-
#processReallyExit(code) {
|
|
3628
|
-
if (!processOk(this.#process)) return 0;
|
|
3629
|
-
this.#process.exitCode = code || 0;
|
|
3630
|
-
this.#emitter.emit('exit', this.#process.exitCode, null);
|
|
3631
|
-
return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode);
|
|
3632
|
-
}
|
|
3633
|
-
#processEmit(ev, ...args) {
|
|
3634
|
-
const og = this.#originalProcessEmit;
|
|
3635
|
-
if (!('exit' === ev && processOk(this.#process))) return og.call(this.#process, ev, ...args);
|
|
3636
|
-
{
|
|
3637
|
-
if ('number' == typeof args[0]) this.#process.exitCode = args[0];
|
|
3638
|
-
const ret = og.call(this.#process, ev, ...args);
|
|
3639
|
-
this.#emitter.emit('exit', this.#process.exitCode, null);
|
|
3640
|
-
return ret;
|
|
3641
|
-
}
|
|
3642
3129
|
}
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
const
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3130
|
+
if (success) console.log('\n🎉 All files executed successfully!');
|
|
3131
|
+
else console.log('\n⚠️ Some files failed or were not executed.');
|
|
3132
|
+
return success;
|
|
3133
|
+
}
|
|
3134
|
+
const DEFAULT_YAML_TEST_TIMEOUT = 0;
|
|
3135
|
+
const toPosixPath = (value)=>value.split(external_node_path_.sep).join('/');
|
|
3136
|
+
const toImportLiteral = (value)=>JSON.stringify(toPosixPath(value));
|
|
3137
|
+
const toVirtualModuleId = (fileStem)=>`virtual:midscene-yaml/${fileStem}.test.ts`;
|
|
3138
|
+
const safeFileStem = (file, index)=>{
|
|
3139
|
+
const base = (0, external_node_path_.basename)(file, (0, external_node_path_.extname)(file)).replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
3140
|
+
return `${String(index + 1).padStart(3, '0')}-${base || 'case'}`;
|
|
3141
|
+
};
|
|
3142
|
+
const resolveTestName = (projectDir, yamlFile)=>{
|
|
3143
|
+
const relativePath = (0, external_node_path_.relative)(projectDir, yamlFile);
|
|
3144
|
+
return toPosixPath(relativePath.startsWith('..') ? yamlFile : relativePath);
|
|
3145
|
+
};
|
|
3146
|
+
const createGeneratedTestContent = (options)=>{
|
|
3147
|
+
const testOptions = {
|
|
3148
|
+
testName: options.testName,
|
|
3149
|
+
yamlFile: options.yamlFile,
|
|
3150
|
+
resultFile: options.resultFile,
|
|
3151
|
+
...options.caseOptions ? {
|
|
3152
|
+
caseOptions: options.caseOptions
|
|
3153
|
+
} : {},
|
|
3154
|
+
...options.webRuntimeOptions ? {
|
|
3155
|
+
webRuntimeOptions: options.webRuntimeOptions
|
|
3156
|
+
} : {}
|
|
3157
|
+
};
|
|
3158
|
+
return `import { defineYamlCaseTest } from ${toImportLiteral(options.frameworkImport)};
|
|
3159
|
+
|
|
3160
|
+
defineYamlCaseTest(${JSON.stringify(testOptions, null, 2)});
|
|
3161
|
+
`;
|
|
3162
|
+
};
|
|
3163
|
+
const createGeneratedBatchTestContent = (options)=>{
|
|
3164
|
+
const testOptions = {
|
|
3165
|
+
testName: options.testName,
|
|
3166
|
+
config: options.config,
|
|
3167
|
+
resultFiles: options.resultFiles
|
|
3168
|
+
};
|
|
3169
|
+
return `import { defineYamlBatchTest } from ${toImportLiteral(options.frameworkImport)};
|
|
3170
|
+
|
|
3171
|
+
defineYamlBatchTest(${JSON.stringify(testOptions, null, 2)});
|
|
3172
|
+
`;
|
|
3173
|
+
};
|
|
3174
|
+
const resolveDefaultFrameworkImport = ()=>{
|
|
3175
|
+
const entry = process.argv[1] ? (0, external_node_path_.resolve)(process.argv[1]) : '';
|
|
3176
|
+
const candidates = [
|
|
3177
|
+
entry ? (0, external_node_path_.join)((0, external_node_path_.dirname)(entry), 'framework', 'index.js') : '',
|
|
3178
|
+
entry ? (0, external_node_path_.join)((0, external_node_path_.dirname)(entry), '..', 'dist', 'lib', 'framework', 'index.js') : ''
|
|
3179
|
+
].filter(Boolean);
|
|
3180
|
+
const matched = candidates.find((candidate)=>(0, external_node_fs_.existsSync)(candidate));
|
|
3181
|
+
return matched || '@midscene/cli/dist/lib/framework/index.js';
|
|
3182
|
+
};
|
|
3183
|
+
function createRstestYamlProject(options) {
|
|
3184
|
+
const projectDir = (0, external_node_path_.resolve)(options.projectDir || process.cwd());
|
|
3185
|
+
const outputDir = options.outputDir || (0, external_node_path_.join)((0, common_namespaceObject.getMidsceneRunSubDir)('tmp'), `rstest-yaml-${Date.now()}`);
|
|
3186
|
+
const resultDir = options.resultDir || (0, external_node_path_.join)(outputDir, 'results');
|
|
3187
|
+
const frameworkImport = options.frameworkImport || resolveDefaultFrameworkImport();
|
|
3188
|
+
const testTimeout = options.testTimeout ?? DEFAULT_YAML_TEST_TIMEOUT;
|
|
3189
|
+
(0, external_node_fs_.rmSync)(outputDir, {
|
|
3190
|
+
recursive: true,
|
|
3191
|
+
force: true
|
|
3661
3192
|
});
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
}
|
|
3665
|
-
const DEFAULT_RENDER_INTERVAL = 160;
|
|
3666
|
-
const ESC = '\x1B[';
|
|
3667
|
-
const CLEAR_LINE = `${ESC}K`;
|
|
3668
|
-
const MOVE_CURSOR_ONE_ROW_UP = `${ESC}1A`;
|
|
3669
|
-
const HIDE_CURSOR = `${ESC}?25l`;
|
|
3670
|
-
const SHOW_CURSOR = `${ESC}?25h`;
|
|
3671
|
-
const SYNC_START = `${ESC}?2026h`;
|
|
3672
|
-
const SYNC_END = `${ESC}?2026l`;
|
|
3673
|
-
class TTYWindowRenderer {
|
|
3674
|
-
start() {
|
|
3675
|
-
this.finished = false;
|
|
3676
|
-
this.renderInterval = setInterval(()=>this.flushBuffer(), this.options.interval);
|
|
3677
|
-
}
|
|
3678
|
-
stop() {
|
|
3679
|
-
this.flushBuffer();
|
|
3680
|
-
this.write(SHOW_CURSOR, 'output');
|
|
3681
|
-
this.cleanups.splice(0).map((fn)=>fn());
|
|
3682
|
-
clearInterval(this.renderInterval);
|
|
3683
|
-
}
|
|
3684
|
-
finish() {
|
|
3685
|
-
this.finished = true;
|
|
3686
|
-
this.flushBuffer();
|
|
3687
|
-
clearInterval(this.renderInterval);
|
|
3688
|
-
}
|
|
3689
|
-
flushBuffer() {
|
|
3690
|
-
if (0 === this.buffer.length) return this.render();
|
|
3691
|
-
let current;
|
|
3692
|
-
for (const next of this.buffer.splice(0)){
|
|
3693
|
-
if (!current) {
|
|
3694
|
-
current = next;
|
|
3695
|
-
continue;
|
|
3696
|
-
}
|
|
3697
|
-
if (current.type !== next.type) {
|
|
3698
|
-
this.render(current.message, current.type);
|
|
3699
|
-
current = next;
|
|
3700
|
-
continue;
|
|
3701
|
-
}
|
|
3702
|
-
current.message += next.message;
|
|
3703
|
-
}
|
|
3704
|
-
if (current) this.render(current?.message, current?.type);
|
|
3705
|
-
}
|
|
3706
|
-
render(message, type = 'output') {
|
|
3707
|
-
if (this.finished) {
|
|
3708
|
-
this.clearWindow();
|
|
3709
|
-
return this.write(message || '', type);
|
|
3710
|
-
}
|
|
3711
|
-
const windowContent = this.options.getWindow();
|
|
3712
|
-
const rowCount = getRenderedRowCount(windowContent, this.options.outputStream);
|
|
3713
|
-
let padding = this.windowHeight - rowCount;
|
|
3714
|
-
if (padding > 0 && message) padding -= getRenderedRowCount([
|
|
3715
|
-
message
|
|
3716
|
-
], this.options.outputStream);
|
|
3717
|
-
this.write(SYNC_START);
|
|
3718
|
-
this.clearWindow();
|
|
3719
|
-
if (message) this.write(message, type);
|
|
3720
|
-
if (padding > 0) this.write('\n'.repeat(padding));
|
|
3721
|
-
this.write(windowContent.join('\n'));
|
|
3722
|
-
this.write(SYNC_END);
|
|
3723
|
-
this.windowHeight = rowCount + Math.max(0, padding);
|
|
3724
|
-
}
|
|
3725
|
-
clearWindow() {
|
|
3726
|
-
if (0 === this.windowHeight) return;
|
|
3727
|
-
this.write(CLEAR_LINE);
|
|
3728
|
-
for(let i = 1; i < this.windowHeight; i++)this.write(`${MOVE_CURSOR_ONE_ROW_UP}${CLEAR_LINE}`);
|
|
3729
|
-
this.windowHeight = 0;
|
|
3730
|
-
}
|
|
3731
|
-
interceptStream(stream, type) {
|
|
3732
|
-
const original = stream.write;
|
|
3733
|
-
stream.write = (chunk, _, callback)=>{
|
|
3734
|
-
if (chunk) if (this.finished) this.write(chunk.toString(), type);
|
|
3735
|
-
else this.buffer.push({
|
|
3736
|
-
type,
|
|
3737
|
-
message: chunk.toString()
|
|
3738
|
-
});
|
|
3739
|
-
callback?.();
|
|
3740
|
-
};
|
|
3741
|
-
return function() {
|
|
3742
|
-
stream.write = original;
|
|
3743
|
-
};
|
|
3744
|
-
}
|
|
3745
|
-
write(message, type = 'output') {
|
|
3746
|
-
this.streams[type](message);
|
|
3747
|
-
}
|
|
3748
|
-
constructor(options){
|
|
3749
|
-
_define_property(this, "options", void 0);
|
|
3750
|
-
_define_property(this, "streams", void 0);
|
|
3751
|
-
_define_property(this, "buffer", []);
|
|
3752
|
-
_define_property(this, "renderInterval", void 0);
|
|
3753
|
-
_define_property(this, "windowHeight", 0);
|
|
3754
|
-
_define_property(this, "finished", false);
|
|
3755
|
-
_define_property(this, "cleanups", []);
|
|
3756
|
-
this.options = {
|
|
3757
|
-
interval: DEFAULT_RENDER_INTERVAL,
|
|
3758
|
-
...options
|
|
3759
|
-
};
|
|
3760
|
-
this.streams = {
|
|
3761
|
-
output: options.outputStream.write.bind(options.outputStream),
|
|
3762
|
-
error: options.errorStream.write.bind(options.errorStream)
|
|
3763
|
-
};
|
|
3764
|
-
this.cleanups.push(this.interceptStream(process.stdout, 'output'), this.interceptStream(process.stderr, 'error'));
|
|
3765
|
-
restore_cursor();
|
|
3766
|
-
this.write(HIDE_CURSOR, 'output');
|
|
3767
|
-
this.start();
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
function getRenderedRowCount(contents, stream) {
|
|
3771
|
-
let count = 0;
|
|
3772
|
-
const columns = 'columns' in stream ? stream.columns : 80;
|
|
3773
|
-
for (const content of contents){
|
|
3774
|
-
const rows = content.split('\n');
|
|
3775
|
-
for (const row of rows){
|
|
3776
|
-
const text = (0, external_node_util_namespaceObject.stripVTControlCharacters)(row);
|
|
3777
|
-
count += Math.max(1, Math.ceil(text.length / columns));
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
return count;
|
|
3781
|
-
}
|
|
3782
|
-
function batch_runner_define_property(obj, key, value) {
|
|
3783
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
3784
|
-
value: value,
|
|
3785
|
-
enumerable: true,
|
|
3786
|
-
configurable: true,
|
|
3787
|
-
writable: true
|
|
3193
|
+
(0, external_node_fs_.mkdirSync)(resultDir, {
|
|
3194
|
+
recursive: true
|
|
3788
3195
|
});
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
const
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
keepWindow
|
|
3805
|
-
});
|
|
3806
|
-
fileContextList.push(context);
|
|
3807
|
-
}
|
|
3808
|
-
const needsBrowser = fileContextList.some((ctx)=>Object.keys(ctx.executionConfig.web || ctx.executionConfig.target || {}).length > 0);
|
|
3809
|
-
if (needsBrowser && this.config.shareBrowserContext) {
|
|
3810
|
-
const globalWebConfig = this.config.globalConfig?.web;
|
|
3811
|
-
if (globalWebConfig?.cdpEndpoint) browser = await external_puppeteer_default().connect({
|
|
3812
|
-
browserWSEndpoint: globalWebConfig.cdpEndpoint,
|
|
3813
|
-
defaultViewport: null
|
|
3814
|
-
});
|
|
3815
|
-
else {
|
|
3816
|
-
const width = globalWebConfig?.viewportWidth ?? puppeteer_agent_launcher_namespaceObject.defaultViewportWidth;
|
|
3817
|
-
const height = globalWebConfig?.viewportHeight ?? puppeteer_agent_launcher_namespaceObject.defaultViewportHeight;
|
|
3818
|
-
const args = (0, puppeteer_agent_launcher_namespaceObject.buildChromeArgs)({
|
|
3819
|
-
userAgent: globalWebConfig?.userAgent,
|
|
3820
|
-
windowSize: headed ? {
|
|
3821
|
-
width,
|
|
3822
|
-
height
|
|
3823
|
-
} : void 0,
|
|
3824
|
-
chromeArgs: globalWebConfig?.chromeArgs
|
|
3825
|
-
});
|
|
3826
|
-
browser = await external_puppeteer_default().launch({
|
|
3827
|
-
headless: !headed,
|
|
3828
|
-
defaultViewport: headed ? null : {
|
|
3829
|
-
width,
|
|
3830
|
-
height
|
|
3831
|
-
},
|
|
3832
|
-
args,
|
|
3833
|
-
acceptInsecureCerts: globalWebConfig?.acceptInsecureCerts
|
|
3834
|
-
});
|
|
3835
|
-
}
|
|
3836
|
-
sharedPage = await browser.newPage();
|
|
3837
|
-
for (const context of fileContextList){
|
|
3838
|
-
context.options.browser = browser;
|
|
3839
|
-
context.options.page = sharedPage;
|
|
3840
|
-
}
|
|
3841
|
-
}
|
|
3842
|
-
const { executedResults, notExecutedContexts } = await this.executeFiles(fileContextList);
|
|
3843
|
-
this.results = await this.processResults(executedResults, notExecutedContexts);
|
|
3844
|
-
} finally{
|
|
3845
|
-
if (browser && !this.config.keepWindow) {
|
|
3846
|
-
const isCdp = !!this.config.globalConfig?.web?.cdpEndpoint;
|
|
3847
|
-
if (isCdp) browser.disconnect();
|
|
3848
|
-
else await browser.close();
|
|
3849
|
-
}
|
|
3850
|
-
await this.generateOutputIndex();
|
|
3851
|
-
}
|
|
3852
|
-
return this.results;
|
|
3853
|
-
}
|
|
3854
|
-
async createFileContext(file, fileConfig, options) {
|
|
3855
|
-
const { globalConfig } = this.config;
|
|
3856
|
-
const clonedFileConfig = JSON.parse(JSON.stringify(fileConfig));
|
|
3857
|
-
if (clonedFileConfig.target) {
|
|
3858
|
-
clonedFileConfig.web = {
|
|
3859
|
-
...clonedFileConfig.target,
|
|
3860
|
-
...clonedFileConfig.web
|
|
3861
|
-
};
|
|
3862
|
-
delete clonedFileConfig.target;
|
|
3863
|
-
}
|
|
3864
|
-
if (globalConfig?.target) {
|
|
3865
|
-
globalConfig.web = {
|
|
3866
|
-
...globalConfig.target,
|
|
3867
|
-
...globalConfig.web
|
|
3868
|
-
};
|
|
3869
|
-
delete globalConfig.target;
|
|
3870
|
-
}
|
|
3871
|
-
const executionConfig = external_lodash_merge_default()(clonedFileConfig, globalConfig);
|
|
3196
|
+
const virtualModules = {};
|
|
3197
|
+
const cases = options.files.map((file, index)=>{
|
|
3198
|
+
const yamlFile = (0, external_node_path_.resolve)(file);
|
|
3199
|
+
const testName = resolveTestName(projectDir, yamlFile);
|
|
3200
|
+
const fileStem = safeFileStem(yamlFile, index);
|
|
3201
|
+
const resultFile = (0, external_node_path_.join)(resultDir, `${fileStem}.json`);
|
|
3202
|
+
const testModule = toVirtualModuleId(fileStem);
|
|
3203
|
+
virtualModules[testModule] = createGeneratedTestContent({
|
|
3204
|
+
frameworkImport,
|
|
3205
|
+
yamlFile,
|
|
3206
|
+
resultFile,
|
|
3207
|
+
testName,
|
|
3208
|
+
caseOptions: options.caseOptions?.[yamlFile],
|
|
3209
|
+
webRuntimeOptions: options.webRuntimeOptions?.[yamlFile]
|
|
3210
|
+
});
|
|
3872
3211
|
return {
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3212
|
+
yamlFile,
|
|
3213
|
+
testModule,
|
|
3214
|
+
resultFile,
|
|
3215
|
+
testName
|
|
3876
3216
|
};
|
|
3877
|
-
}
|
|
3878
|
-
|
|
3879
|
-
const
|
|
3880
|
-
const
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
allFileContexts.push({
|
|
3885
|
-
file: context.file,
|
|
3886
|
-
player
|
|
3887
|
-
});
|
|
3888
|
-
}
|
|
3889
|
-
let ttyRenderer;
|
|
3890
|
-
if (isTTY) {
|
|
3891
|
-
const summaryContents = ()=>{
|
|
3892
|
-
const summary = [
|
|
3893
|
-
''
|
|
3894
|
-
];
|
|
3895
|
-
for (const context of allFileContexts)summary.push(contextTaskListSummary(context.player.taskStatusList, context));
|
|
3896
|
-
summary.push('');
|
|
3897
|
-
return summary;
|
|
3898
|
-
};
|
|
3899
|
-
ttyRenderer = new TTYWindowRenderer({
|
|
3900
|
-
outputStream: process.stdout,
|
|
3901
|
-
errorStream: process.stderr,
|
|
3902
|
-
getWindow: summaryContents,
|
|
3903
|
-
interval: spinnerInterval
|
|
3904
|
-
});
|
|
3905
|
-
ttyRenderer.start();
|
|
3906
|
-
}
|
|
3907
|
-
try {
|
|
3908
|
-
const executeFile = async (context)=>{
|
|
3909
|
-
const allFileContext = allFileContexts.find((c)=>c.file === context.file);
|
|
3910
|
-
if (!allFileContext) throw new Error(`Player not found for file: ${context.file}`);
|
|
3911
|
-
if (!isTTY) {
|
|
3912
|
-
const { mergedText } = contextInfo(allFileContext);
|
|
3913
|
-
console.log(mergedText);
|
|
3914
|
-
}
|
|
3915
|
-
if (context.outputPath) allFileContext.player.output = context.outputPath;
|
|
3916
|
-
const startTime = Date.now();
|
|
3917
|
-
await allFileContext.player.run();
|
|
3918
|
-
const endTime = Date.now();
|
|
3919
|
-
const duration = endTime - startTime;
|
|
3920
|
-
const executedContext = {
|
|
3921
|
-
file: context.file,
|
|
3922
|
-
player: allFileContext.player,
|
|
3923
|
-
duration
|
|
3924
|
-
};
|
|
3925
|
-
if (!isTTY) console.log(contextTaskListSummary(allFileContext.player.taskStatusList, executedContext));
|
|
3926
|
-
return executedContext;
|
|
3927
|
-
};
|
|
3928
|
-
await this.executeConcurrently(fileContextList, executeFile, executedResults, notExecutedContexts);
|
|
3929
|
-
if (!isTTY) {
|
|
3930
|
-
console.log('\n📋 Execution Results:');
|
|
3931
|
-
for (const context of executedResults)console.log(contextTaskListSummary(context.player.taskStatusList, context));
|
|
3932
|
-
}
|
|
3933
|
-
} finally{
|
|
3934
|
-
if (ttyRenderer) ttyRenderer.stop();
|
|
3935
|
-
}
|
|
3217
|
+
});
|
|
3218
|
+
if (options.batchConfig) {
|
|
3219
|
+
const batchModule = 'virtual:midscene-yaml/batch.test.ts';
|
|
3220
|
+
const resultFiles = Object.fromEntries(cases.map((item)=>[
|
|
3221
|
+
item.yamlFile,
|
|
3222
|
+
item.resultFile
|
|
3223
|
+
]));
|
|
3936
3224
|
return {
|
|
3937
|
-
|
|
3938
|
-
|
|
3225
|
+
projectDir,
|
|
3226
|
+
outputDir,
|
|
3227
|
+
resultDir,
|
|
3228
|
+
include: [
|
|
3229
|
+
batchModule
|
|
3230
|
+
],
|
|
3231
|
+
virtualModules: {
|
|
3232
|
+
[batchModule]: createGeneratedBatchTestContent({
|
|
3233
|
+
frameworkImport,
|
|
3234
|
+
testName: 'midscene yaml batch',
|
|
3235
|
+
config: options.batchConfig,
|
|
3236
|
+
resultFiles
|
|
3237
|
+
})
|
|
3238
|
+
},
|
|
3239
|
+
cases,
|
|
3240
|
+
maxConcurrency: 1,
|
|
3241
|
+
testTimeout,
|
|
3242
|
+
bail: options.bail
|
|
3939
3243
|
};
|
|
3940
3244
|
}
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3245
|
+
return {
|
|
3246
|
+
projectDir,
|
|
3247
|
+
outputDir,
|
|
3248
|
+
resultDir,
|
|
3249
|
+
include: cases.map((item)=>item.testModule),
|
|
3250
|
+
virtualModules,
|
|
3251
|
+
cases,
|
|
3252
|
+
maxConcurrency: options.maxConcurrency,
|
|
3253
|
+
testTimeout,
|
|
3254
|
+
bail: options.bail
|
|
3255
|
+
};
|
|
3256
|
+
}
|
|
3257
|
+
const external_node_module_namespaceObject = require("node:module");
|
|
3258
|
+
var external_node_url_ = __webpack_require__("node:url");
|
|
3259
|
+
const requireFromCliEntry = ()=>{
|
|
3260
|
+
const entry = process.argv[1] ? (0, external_node_path_.resolve)(process.argv[1]) : (0, external_node_path_.join)(process.cwd(), 'midscene-cli.js');
|
|
3261
|
+
return (0, external_node_module_namespaceObject.createRequire)(entry);
|
|
3262
|
+
};
|
|
3263
|
+
const resolvePackageFromRstestCore = (packageName)=>{
|
|
3264
|
+
const require1 = requireFromCliEntry();
|
|
3265
|
+
const rstestPackageJsonPath = require1.resolve('@rstest/core/package.json');
|
|
3266
|
+
return (0, external_node_module_namespaceObject.createRequire)(rstestPackageJsonPath).resolve(packageName);
|
|
3267
|
+
};
|
|
3268
|
+
const formatRunError = (error)=>error.stack || `${error.name}: ${error.message}`;
|
|
3269
|
+
async function runRstestYamlProject(options) {
|
|
3270
|
+
const [{ runRstest }, { rspack }] = await Promise.all([
|
|
3271
|
+
import("@rstest/core/api"),
|
|
3272
|
+
import((0, external_node_url_.pathToFileURL)(resolvePackageFromRstestCore('@rsbuild/core')).href)
|
|
3273
|
+
]);
|
|
3274
|
+
const { project } = options;
|
|
3275
|
+
const maxConcurrency = void 0 !== project.maxConcurrency ? Math.max(1, project.maxConcurrency) : void 0;
|
|
3276
|
+
const inlineConfig = {
|
|
3277
|
+
root: project.projectDir,
|
|
3278
|
+
include: project.include,
|
|
3279
|
+
testEnvironment: 'node',
|
|
3280
|
+
testTimeout: project.testTimeout,
|
|
3281
|
+
...void 0 !== maxConcurrency ? {
|
|
3282
|
+
maxConcurrency
|
|
3283
|
+
} : {},
|
|
3284
|
+
...void 0 !== maxConcurrency ? {
|
|
3285
|
+
pool: {
|
|
3286
|
+
maxWorkers: maxConcurrency,
|
|
3287
|
+
minWorkers: maxConcurrency
|
|
3288
|
+
}
|
|
3289
|
+
} : {},
|
|
3290
|
+
...void 0 !== project.bail ? {
|
|
3291
|
+
bail: project.bail
|
|
3292
|
+
} : {},
|
|
3293
|
+
reporters: [],
|
|
3294
|
+
tools: {
|
|
3295
|
+
rspack: (_config, { appendPlugins })=>{
|
|
3296
|
+
appendPlugins(new rspack.experiments.VirtualModulesPlugin(project.virtualModules));
|
|
3972
3297
|
}
|
|
3973
3298
|
}
|
|
3974
|
-
}
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
let success;
|
|
3982
|
-
let resultType;
|
|
3983
|
-
if (hasPlayerError) {
|
|
3984
|
-
success = false;
|
|
3985
|
-
resultType = 'failed';
|
|
3986
|
-
} else if (hasFailedTasks) {
|
|
3987
|
-
success = false;
|
|
3988
|
-
resultType = 'partialFailed';
|
|
3989
|
-
} else {
|
|
3990
|
-
success = true;
|
|
3991
|
-
resultType = 'success';
|
|
3992
|
-
}
|
|
3993
|
-
let reportFile;
|
|
3994
|
-
if (player.reportFile) reportFile = player.reportFile;
|
|
3995
|
-
let outputPath = player.output || void 0;
|
|
3996
|
-
if (outputPath && !(0, external_node_fs_namespaceObject.existsSync)(outputPath)) outputPath = void 0;
|
|
3997
|
-
let errorMessage;
|
|
3998
|
-
if (player.errorInSetup?.message) errorMessage = player.errorInSetup.message;
|
|
3999
|
-
else if (hasPlayerError || hasFailedTasks) {
|
|
4000
|
-
const taskErrors = player.taskStatusList?.filter((task)=>'error' === task.status && task.error?.message).map((task)=>task.error.message);
|
|
4001
|
-
errorMessage = taskErrors && taskErrors.length > 0 ? taskErrors.join('; ') : hasPlayerError ? 'Execution failed' : 'Some tasks failed';
|
|
4002
|
-
}
|
|
4003
|
-
results.push({
|
|
4004
|
-
file,
|
|
4005
|
-
success,
|
|
4006
|
-
executed: true,
|
|
4007
|
-
output: outputPath,
|
|
4008
|
-
report: reportFile,
|
|
4009
|
-
duration,
|
|
4010
|
-
resultType,
|
|
4011
|
-
error: errorMessage
|
|
4012
|
-
});
|
|
4013
|
-
}
|
|
4014
|
-
for (const context of notExecutedContexts)results.push({
|
|
4015
|
-
file: context.file,
|
|
4016
|
-
success: false,
|
|
4017
|
-
executed: false,
|
|
4018
|
-
output: void 0,
|
|
4019
|
-
report: void 0,
|
|
4020
|
-
duration: 0,
|
|
4021
|
-
resultType: 'notExecuted',
|
|
4022
|
-
error: 'Not executed (previous task failed)'
|
|
4023
|
-
});
|
|
4024
|
-
return results;
|
|
4025
|
-
}
|
|
4026
|
-
async loadFileConfig(file) {
|
|
4027
|
-
const content = (0, external_node_fs_namespaceObject.readFileSync)(file, 'utf8');
|
|
4028
|
-
return (0, yaml_namespaceObject.parseYamlScript)(content, file);
|
|
4029
|
-
}
|
|
4030
|
-
getSummaryAbsolutePath() {
|
|
4031
|
-
return (0, external_node_path_namespaceObject.resolve)((0, common_namespaceObject.getMidsceneRunSubDir)('output'), this.config.summary);
|
|
4032
|
-
}
|
|
4033
|
-
printExecutionPlan() {
|
|
4034
|
-
console.log(' Scripts:');
|
|
4035
|
-
for (const file of this.config.files)console.log(` - ${file}`);
|
|
4036
|
-
console.log('📋 Execution plan');
|
|
4037
|
-
console.log(` Concurrency: ${this.config.concurrent}`);
|
|
4038
|
-
console.log(` Keep window: ${this.config.keepWindow}`);
|
|
4039
|
-
console.log(` Headed: ${this.config.headed}`);
|
|
4040
|
-
console.log(` Continue on error: ${this.config.continueOnError}`);
|
|
4041
|
-
console.log(` Share browser context: ${this.config.shareBrowserContext ?? false}`);
|
|
4042
|
-
console.log(` Summary output: ${this.config.summary}`);
|
|
4043
|
-
}
|
|
4044
|
-
async generateOutputIndex() {
|
|
4045
|
-
const indexPath = (0, external_node_path_namespaceObject.resolve)((0, common_namespaceObject.getMidsceneRunSubDir)('output'), this.config.summary);
|
|
4046
|
-
const outputDir = (0, external_node_path_namespaceObject.dirname)(indexPath);
|
|
4047
|
-
try {
|
|
4048
|
-
(0, external_node_fs_namespaceObject.mkdirSync)(outputDir, {
|
|
4049
|
-
recursive: true
|
|
4050
|
-
});
|
|
4051
|
-
const indexData = {
|
|
4052
|
-
summary: {
|
|
4053
|
-
total: this.results.length,
|
|
4054
|
-
successful: this.results.filter((r)=>'success' === r.resultType).length,
|
|
4055
|
-
failed: this.results.filter((r)=>'failed' === r.resultType).length,
|
|
4056
|
-
partialFailed: this.results.filter((r)=>'partialFailed' === r.resultType).length,
|
|
4057
|
-
notExecuted: this.results.filter((r)=>'notExecuted' === r.resultType).length,
|
|
4058
|
-
totalDuration: this.results.reduce((sum, r)=>sum + (r.duration || 0), 0),
|
|
4059
|
-
generatedAt: new Date().toLocaleString()
|
|
4060
|
-
},
|
|
4061
|
-
results: this.results.map((result)=>({
|
|
4062
|
-
script: (0, external_node_path_namespaceObject.relative)(outputDir, result.file),
|
|
4063
|
-
success: result.success,
|
|
4064
|
-
resultType: result.resultType,
|
|
4065
|
-
output: result.output ? (()=>{
|
|
4066
|
-
const relativePath = (0, external_node_path_namespaceObject.relative)(outputDir, result.output);
|
|
4067
|
-
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
|
|
4068
|
-
})() : void 0,
|
|
4069
|
-
report: result.report ? (0, external_node_path_namespaceObject.relative)(outputDir, result.report) : void 0,
|
|
4070
|
-
error: result.error,
|
|
4071
|
-
duration: result.duration
|
|
4072
|
-
}))
|
|
4073
|
-
};
|
|
4074
|
-
(0, external_node_fs_namespaceObject.writeFileSync)(indexPath, JSON.stringify(indexData, null, 2));
|
|
4075
|
-
console.log('Execution finished:');
|
|
4076
|
-
} catch (error) {
|
|
4077
|
-
console.error('Failed to generate output index:', error);
|
|
4078
|
-
}
|
|
4079
|
-
}
|
|
4080
|
-
getExecutionSummary() {
|
|
4081
|
-
const successful = this.results.filter((r)=>'success' === r.resultType).length;
|
|
4082
|
-
const failed = this.results.filter((r)=>'failed' === r.resultType).length;
|
|
4083
|
-
const partialFailed = this.results.filter((r)=>'partialFailed' === r.resultType).length;
|
|
4084
|
-
const notExecuted = this.results.filter((r)=>'notExecuted' === r.resultType).length;
|
|
4085
|
-
return {
|
|
4086
|
-
total: this.results.length,
|
|
4087
|
-
successful,
|
|
4088
|
-
failed,
|
|
4089
|
-
partialFailed,
|
|
4090
|
-
notExecuted,
|
|
4091
|
-
totalDuration: this.results.reduce((sum, r)=>sum + (r.duration || 0), 0)
|
|
4092
|
-
};
|
|
4093
|
-
}
|
|
4094
|
-
getFailedFiles() {
|
|
4095
|
-
return this.results.filter((r)=>'failed' === r.resultType).map((r)=>r.file);
|
|
4096
|
-
}
|
|
4097
|
-
getPartialFailedFiles() {
|
|
4098
|
-
return this.results.filter((r)=>'partialFailed' === r.resultType).map((r)=>r.file);
|
|
4099
|
-
}
|
|
4100
|
-
getNotExecutedFiles() {
|
|
4101
|
-
return this.results.filter((r)=>'notExecuted' === r.resultType).map((r)=>r.file);
|
|
4102
|
-
}
|
|
4103
|
-
getSuccessfulFiles() {
|
|
4104
|
-
return this.results.filter((r)=>'success' === r.resultType).map((r)=>r.file);
|
|
4105
|
-
}
|
|
4106
|
-
getResults() {
|
|
4107
|
-
return [
|
|
4108
|
-
...this.results
|
|
4109
|
-
];
|
|
4110
|
-
}
|
|
4111
|
-
printExecutionSummary() {
|
|
4112
|
-
const summary = this.getExecutionSummary();
|
|
4113
|
-
const success = 0 === summary.failed && 0 === summary.partialFailed && 0 === summary.notExecuted;
|
|
4114
|
-
console.log('\n📊 Execution Summary:');
|
|
4115
|
-
console.log(` Total files: ${summary.total}`);
|
|
4116
|
-
console.log(` Successful: ${summary.successful}`);
|
|
4117
|
-
console.log(` Failed: ${summary.failed}`);
|
|
4118
|
-
console.log(` Partial failed: ${summary.partialFailed}`);
|
|
4119
|
-
console.log(` Not executed: ${summary.notExecuted}`);
|
|
4120
|
-
console.log(` Duration: ${(summary.totalDuration / 1000).toFixed(2)}s`);
|
|
4121
|
-
console.log(` Summary: ${this.getSummaryAbsolutePath()}`);
|
|
4122
|
-
if (summary.successful > 0) {
|
|
4123
|
-
console.log('\n✅ Successful files:');
|
|
4124
|
-
this.getSuccessfulFiles().forEach((file)=>{
|
|
4125
|
-
console.log(` ${file}`);
|
|
4126
|
-
});
|
|
4127
|
-
}
|
|
4128
|
-
if (summary.failed > 0) {
|
|
4129
|
-
console.log('\n❌ Failed files');
|
|
4130
|
-
this.getFailedFiles().forEach((file)=>{
|
|
4131
|
-
console.log(` ${file}`);
|
|
4132
|
-
});
|
|
4133
|
-
}
|
|
4134
|
-
if (summary.partialFailed > 0) {
|
|
4135
|
-
console.log('\n⚠️ Partial failed files (some tasks failed with continueOnError)');
|
|
4136
|
-
this.getPartialFailedFiles().forEach((file)=>{
|
|
4137
|
-
console.log(` ${file}`);
|
|
4138
|
-
});
|
|
4139
|
-
}
|
|
4140
|
-
if (summary.notExecuted > 0) {
|
|
4141
|
-
console.log('\n⏸️ Not executed files');
|
|
4142
|
-
this.getNotExecutedFiles().forEach((file)=>{
|
|
4143
|
-
console.log(` ${file}`);
|
|
4144
|
-
});
|
|
4145
|
-
}
|
|
4146
|
-
if (success) console.log('\n🎉 All files executed successfully!');
|
|
4147
|
-
else console.log('\n⚠️ Some files failed or were not executed.');
|
|
4148
|
-
return success;
|
|
4149
|
-
}
|
|
4150
|
-
constructor(config){
|
|
4151
|
-
batch_runner_define_property(this, "config", void 0);
|
|
4152
|
-
batch_runner_define_property(this, "results", []);
|
|
4153
|
-
this.config = config;
|
|
4154
|
-
}
|
|
3299
|
+
};
|
|
3300
|
+
const result = await runRstest({
|
|
3301
|
+
cwd: options.cwd || project.projectDir,
|
|
3302
|
+
inlineConfig
|
|
3303
|
+
});
|
|
3304
|
+
if (!result.ok && 'pipe' !== options.stdio && result.unhandledErrors.length) console.error(result.unhandledErrors.map((error)=>formatRunError(error)).join('\n'));
|
|
3305
|
+
return result.ok ? 0 : 1;
|
|
4155
3306
|
}
|
|
3307
|
+
const createCaseOptions = (config)=>{
|
|
3308
|
+
const caseOptions = {};
|
|
3309
|
+
for (const file of config.files)caseOptions[(0, external_node_path_.resolve)(file)] = {
|
|
3310
|
+
globalConfig: config.globalConfig
|
|
3311
|
+
};
|
|
3312
|
+
return caseOptions;
|
|
3313
|
+
};
|
|
3314
|
+
const createWebRuntimeOptions = (config, runtimeOptions)=>{
|
|
3315
|
+
const caseOptions = {};
|
|
3316
|
+
for (const file of config.files)caseOptions[(0, external_node_path_.resolve)(file)] = {
|
|
3317
|
+
headed: runtimeOptions.headed ?? config.headed,
|
|
3318
|
+
keepWindow: runtimeOptions.keepWindow ?? config.keepWindow
|
|
3319
|
+
};
|
|
3320
|
+
return caseOptions;
|
|
3321
|
+
};
|
|
3322
|
+
const readProjectResults = (project)=>project.cases.map((item)=>{
|
|
3323
|
+
if ((0, external_node_fs_.existsSync)(item.resultFile)) return JSON.parse((0, external_node_fs_.readFileSync)(item.resultFile, 'utf8'));
|
|
3324
|
+
return execution_summary_createNotExecutedYamlResult(item.yamlFile);
|
|
3325
|
+
});
|
|
3326
|
+
async function runFrameworkTestConfig(config, commandOptions = {}) {
|
|
3327
|
+
execution_summary_printExecutionPlan(config);
|
|
3328
|
+
const projectDir = (0, external_node_path_.resolve)(commandOptions.projectDir || process.cwd());
|
|
3329
|
+
const project = createRstestYamlProject({
|
|
3330
|
+
files: config.files,
|
|
3331
|
+
projectDir,
|
|
3332
|
+
outputDir: commandOptions.outputDir,
|
|
3333
|
+
frameworkImport: commandOptions.frameworkImport,
|
|
3334
|
+
caseOptions: createCaseOptions(config),
|
|
3335
|
+
webRuntimeOptions: createWebRuntimeOptions(config, commandOptions),
|
|
3336
|
+
maxConcurrency: commandOptions.concurrent ?? config.concurrent,
|
|
3337
|
+
bail: config.continueOnError ? 0 : 1,
|
|
3338
|
+
batchConfig: config.shareBrowserContext ? config : void 0
|
|
3339
|
+
});
|
|
3340
|
+
const runner = commandOptions.rstestRunner || runRstestYamlProject;
|
|
3341
|
+
const exitCode = await runner({
|
|
3342
|
+
project,
|
|
3343
|
+
cwd: projectDir,
|
|
3344
|
+
stdio: commandOptions.stdio
|
|
3345
|
+
});
|
|
3346
|
+
const results = readProjectResults(project);
|
|
3347
|
+
const summaryPath = execution_summary_writeExecutionSummaryFile(config.summary, results);
|
|
3348
|
+
execution_summary_printExecutionFinished();
|
|
3349
|
+
const success = printExecutionSummary(results, summaryPath);
|
|
3350
|
+
return success ? exitCode : 1;
|
|
3351
|
+
}
|
|
3352
|
+
require("@rstest/core");
|
|
3353
|
+
__webpack_require__("@midscene/core/yaml");
|
|
3354
|
+
require("@midscene/web/puppeteer-agent-launcher");
|
|
3355
|
+
__webpack_require__("lodash.merge");
|
|
3356
|
+
require("puppeteer");
|
|
3357
|
+
require("http-server");
|
|
3358
|
+
require("node:assert");
|
|
3359
|
+
require("@midscene/core/agent");
|
|
3360
|
+
require("@midscene/core/utils");
|
|
3361
|
+
var logger_ = __webpack_require__("@midscene/shared/logger");
|
|
3362
|
+
require("@midscene/web/bridge-mode");
|
|
3363
|
+
(0, logger_.getDebug)('create-yaml-player');
|
|
3364
|
+
__webpack_require__("../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/index.js");
|
|
3365
|
+
process.env.MIDSCENE_CLI_LOG_ON_NON_TTY || process.stdout.isTTY;
|
|
3366
|
+
require("node:util");
|
|
3367
|
+
},
|
|
3368
|
+
"./src/index.ts" (__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
|
|
3369
|
+
"use strict";
|
|
3370
|
+
var external_node_fs_ = __webpack_require__("node:fs");
|
|
3371
|
+
var external_node_fs_namespaceObject = /*#__PURE__*/ __webpack_require__.t(external_node_fs_, 2);
|
|
3372
|
+
var external_node_path_ = __webpack_require__("node:path");
|
|
3373
|
+
const core_namespaceObject = require("@midscene/core");
|
|
3374
|
+
const cli_namespaceObject = require("@midscene/shared/cli");
|
|
3375
|
+
var main = __webpack_require__("../../node_modules/.pnpm/dotenv@16.4.5/node_modules/dotenv/lib/main.js");
|
|
3376
|
+
var main_default = /*#__PURE__*/ __webpack_require__.n(main);
|
|
3377
|
+
var package_namespaceObject = JSON.parse('{"rE":"1.8.8-beta-20260601092817.0"}');
|
|
3378
|
+
var logger_ = __webpack_require__("@midscene/shared/logger");
|
|
4156
3379
|
var brace_expansion = __webpack_require__("../../node_modules/.pnpm/brace-expansion@2.0.1/node_modules/brace-expansion/index.js");
|
|
4157
3380
|
const MAX_PATTERN_LENGTH = 65536;
|
|
4158
3381
|
const assertValidPattern = (pattern)=>{
|
|
@@ -5287,7 +4510,7 @@ var __webpack_modules__ = {
|
|
|
5287
4510
|
minimatch.Minimatch = esm_Minimatch;
|
|
5288
4511
|
minimatch.escape = escape_escape;
|
|
5289
4512
|
minimatch.unescape = unescape_unescape;
|
|
5290
|
-
|
|
4513
|
+
var external_node_url_ = __webpack_require__("node:url");
|
|
5291
4514
|
const perf = 'object' == typeof performance && performance && 'function' == typeof performance.now ? performance : Date;
|
|
5292
4515
|
const warned = new Set();
|
|
5293
4516
|
const PROCESS = 'object' == typeof process && process ? process : {};
|
|
@@ -6798,7 +6021,7 @@ var __webpack_modules__ = {
|
|
|
6798
6021
|
realpath: promises_namespaceObject.realpath
|
|
6799
6022
|
}
|
|
6800
6023
|
};
|
|
6801
|
-
const fsFromOption = (fsOption)=>fsOption && fsOption !== defaultFS && fsOption !==
|
|
6024
|
+
const fsFromOption = (fsOption)=>fsOption && fsOption !== defaultFS && fsOption !== external_node_fs_namespaceObject ? {
|
|
6802
6025
|
...defaultFS,
|
|
6803
6026
|
...fsOption,
|
|
6804
6027
|
promises: {
|
|
@@ -7405,7 +6628,7 @@ var __webpack_modules__ = {
|
|
|
7405
6628
|
return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
|
|
7406
6629
|
}
|
|
7407
6630
|
getRootString(path) {
|
|
7408
|
-
return
|
|
6631
|
+
return external_node_path_.win32.parse(path).root;
|
|
7409
6632
|
}
|
|
7410
6633
|
getRoot(rootPath) {
|
|
7411
6634
|
rootPath = uncToDrive(rootPath.toUpperCase());
|
|
@@ -7446,7 +6669,7 @@ var __webpack_modules__ = {
|
|
|
7446
6669
|
#fs;
|
|
7447
6670
|
constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16384, fs = defaultFS } = {}){
|
|
7448
6671
|
this.#fs = fsFromOption(fs);
|
|
7449
|
-
if (cwd instanceof URL || cwd.startsWith('file://')) cwd = (0,
|
|
6672
|
+
if (cwd instanceof URL || cwd.startsWith('file://')) cwd = (0, external_node_url_.fileURLToPath)(cwd);
|
|
7450
6673
|
const cwdPath = pathImpl.resolve(cwd);
|
|
7451
6674
|
this.roots = Object.create(null);
|
|
7452
6675
|
this.rootPath = this.parseRootPath(cwdPath);
|
|
@@ -7814,7 +7037,7 @@ var __webpack_modules__ = {
|
|
|
7814
7037
|
sep = '\\';
|
|
7815
7038
|
constructor(cwd = process.cwd(), opts = {}){
|
|
7816
7039
|
const { nocase = true } = opts;
|
|
7817
|
-
super(cwd,
|
|
7040
|
+
super(cwd, external_node_path_.win32, '\\', {
|
|
7818
7041
|
...opts,
|
|
7819
7042
|
nocase
|
|
7820
7043
|
});
|
|
@@ -7822,7 +7045,7 @@ var __webpack_modules__ = {
|
|
|
7822
7045
|
for(let p = this.cwd; p; p = p.parent)p.nocase = this.nocase;
|
|
7823
7046
|
}
|
|
7824
7047
|
parseRootPath(dir) {
|
|
7825
|
-
return
|
|
7048
|
+
return external_node_path_.win32.parse(dir).root.toUpperCase();
|
|
7826
7049
|
}
|
|
7827
7050
|
newRoot(fs) {
|
|
7828
7051
|
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), {
|
|
@@ -7837,7 +7060,7 @@ var __webpack_modules__ = {
|
|
|
7837
7060
|
sep = '/';
|
|
7838
7061
|
constructor(cwd = process.cwd(), opts = {}){
|
|
7839
7062
|
const { nocase = false } = opts;
|
|
7840
|
-
super(cwd,
|
|
7063
|
+
super(cwd, external_node_path_.posix, '/', {
|
|
7841
7064
|
...opts,
|
|
7842
7065
|
nocase
|
|
7843
7066
|
});
|
|
@@ -8536,7 +7759,7 @@ var __webpack_modules__ = {
|
|
|
8536
7759
|
this.nodir = !!opts.nodir;
|
|
8537
7760
|
this.mark = !!opts.mark;
|
|
8538
7761
|
if (opts.cwd) {
|
|
8539
|
-
if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) opts.cwd = (0,
|
|
7762
|
+
if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) opts.cwd = (0, external_node_url_.fileURLToPath)(opts.cwd);
|
|
8540
7763
|
} else this.cwd = '';
|
|
8541
7764
|
this.cwd = opts.cwd || '';
|
|
8542
7765
|
this.root = opts.root;
|
|
@@ -8688,7 +7911,7 @@ var __webpack_modules__ = {
|
|
|
8688
7911
|
return new Glob(pattern, options).iterate();
|
|
8689
7912
|
}
|
|
8690
7913
|
const streamSync = globStreamSync;
|
|
8691
|
-
const
|
|
7914
|
+
const stream = Object.assign(globStream, {
|
|
8692
7915
|
sync: globStreamSync
|
|
8693
7916
|
});
|
|
8694
7917
|
const iterateSync = globIterateSync;
|
|
@@ -8704,7 +7927,7 @@ var __webpack_modules__ = {
|
|
|
8704
7927
|
globSync,
|
|
8705
7928
|
sync: esm_sync,
|
|
8706
7929
|
globStream,
|
|
8707
|
-
stream
|
|
7930
|
+
stream,
|
|
8708
7931
|
globStreamSync,
|
|
8709
7932
|
streamSync,
|
|
8710
7933
|
globIterate,
|
|
@@ -9564,7 +8787,7 @@ var __webpack_modules__ = {
|
|
|
9564
8787
|
var external_assert_ = __webpack_require__("assert");
|
|
9565
8788
|
new RegExp("\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)", 'g');
|
|
9566
8789
|
const external_url_namespaceObject = require("url");
|
|
9567
|
-
const
|
|
8790
|
+
const node = {
|
|
9568
8791
|
fs: {
|
|
9569
8792
|
readFileSync: external_fs_.readFileSync,
|
|
9570
8793
|
writeFile: external_fs_.writeFile
|
|
@@ -9714,7 +8937,7 @@ var __webpack_modules__ = {
|
|
|
9714
8937
|
locale: y18n.locale
|
|
9715
8938
|
};
|
|
9716
8939
|
}
|
|
9717
|
-
const y18n_y18n = (opts)=>lib_y18n(opts,
|
|
8940
|
+
const y18n_y18n = (opts)=>lib_y18n(opts, node);
|
|
9718
8941
|
const node_modules_y18n = y18n_y18n;
|
|
9719
8942
|
let esm_dirname;
|
|
9720
8943
|
try {
|
|
@@ -9733,6 +8956,8 @@ var __webpack_modules__ = {
|
|
|
9733
8956
|
Yargs.hideBin = processArgv.hideBin;
|
|
9734
8957
|
Yargs.Parser = yargs_Parser;
|
|
9735
8958
|
const yargs = Yargs;
|
|
8959
|
+
const external_node_process_namespaceObject = require("node:process");
|
|
8960
|
+
var yaml_ = __webpack_require__("@midscene/core/yaml");
|
|
9736
8961
|
/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */ function isNothing(subject) {
|
|
9737
8962
|
return null == subject;
|
|
9738
8963
|
}
|
|
@@ -11805,12 +11030,14 @@ var __webpack_modules__ = {
|
|
|
11805
11030
|
throw new Error('Function yaml.' + from + " is removed in js-yaml 4. Use yaml." + to + ' instead, which is now safe by default.');
|
|
11806
11031
|
};
|
|
11807
11032
|
}
|
|
11808
|
-
var
|
|
11033
|
+
var load = loader.load;
|
|
11809
11034
|
loader.loadAll;
|
|
11810
11035
|
dumper.dump;
|
|
11811
11036
|
renamed('safeLoad', 'load');
|
|
11812
11037
|
renamed('safeLoadAll', 'loadAll');
|
|
11813
11038
|
renamed('safeDump', 'dump');
|
|
11039
|
+
var external_lodash_merge_ = __webpack_require__("lodash.merge");
|
|
11040
|
+
var external_lodash_merge_default = /*#__PURE__*/ __webpack_require__.n(external_lodash_merge_);
|
|
11814
11041
|
const config_factory_defaultConfig = {
|
|
11815
11042
|
concurrent: 1,
|
|
11816
11043
|
continueOnError: false,
|
|
@@ -11833,19 +11060,19 @@ var __webpack_modules__ = {
|
|
|
11833
11060
|
return allFiles;
|
|
11834
11061
|
}
|
|
11835
11062
|
async function parseConfigYaml(configYamlPath) {
|
|
11836
|
-
const basePath = (0,
|
|
11837
|
-
const configContent = (0,
|
|
11838
|
-
const interpolatedContent = (0,
|
|
11063
|
+
const basePath = (0, external_node_path_.dirname)((0, external_node_path_.resolve)(configYamlPath));
|
|
11064
|
+
const configContent = (0, external_node_fs_.readFileSync)(configYamlPath, 'utf8');
|
|
11065
|
+
const interpolatedContent = (0, yaml_.interpolateEnvVars)(configContent);
|
|
11839
11066
|
let configYaml;
|
|
11840
11067
|
try {
|
|
11841
|
-
configYaml =
|
|
11068
|
+
configYaml = load(interpolatedContent);
|
|
11842
11069
|
} catch (error) {
|
|
11843
11070
|
throw new Error(`Failed to parse config YAML: ${error}`);
|
|
11844
11071
|
}
|
|
11845
11072
|
if (!configYaml?.files || !Array.isArray(configYaml?.files)) throw new Error('Config YAML must contain a "files" array');
|
|
11846
11073
|
const files = await expandFilePatterns(configYaml?.files, basePath);
|
|
11847
11074
|
if (0 === files.length) throw new Error('No YAML files found matching the patterns in "files"');
|
|
11848
|
-
const configFileName = (0,
|
|
11075
|
+
const configFileName = (0, external_node_path_.basename)(configYamlPath, (0, external_node_path_.extname)(configYamlPath));
|
|
11849
11076
|
const timestamp = Date.now();
|
|
11850
11077
|
const defaultSummary = `${configFileName}-${timestamp}.json`;
|
|
11851
11078
|
const config = {
|
|
@@ -11882,7 +11109,7 @@ var __webpack_modules__ = {
|
|
|
11882
11109
|
const finalHeaded = keepWindow || headed;
|
|
11883
11110
|
let files = parsedConfig.files;
|
|
11884
11111
|
if (options?.files && options.files.length > 0) {
|
|
11885
|
-
const basePath = (0,
|
|
11112
|
+
const basePath = (0, external_node_path_.dirname)((0, external_node_path_.resolve)(configYamlPath));
|
|
11886
11113
|
files = await expandFilePatterns(options.files, basePath);
|
|
11887
11114
|
}
|
|
11888
11115
|
return {
|
|
@@ -11922,7 +11149,7 @@ var __webpack_modules__ = {
|
|
|
11922
11149
|
}
|
|
11923
11150
|
};
|
|
11924
11151
|
}
|
|
11925
|
-
const
|
|
11152
|
+
const debug = (0, logger_.getDebug)('midscene:cli');
|
|
11926
11153
|
function kebabToCamel(str) {
|
|
11927
11154
|
return str.replace(/-([a-z])/g, (_, letter)=>letter.toUpperCase());
|
|
11928
11155
|
}
|
|
@@ -11981,7 +11208,7 @@ Usage:
|
|
|
11981
11208
|
type: 'boolean',
|
|
11982
11209
|
description: `Turn on logging to help debug why certain keys or values are not being set as you expect, default is ${config_factory_defaultConfig.dotenvDebug}`
|
|
11983
11210
|
}
|
|
11984
|
-
}).version('version', 'Show version number', "1.8.
|
|
11211
|
+
}).version('version', 'Show version number', "1.8.8-beta-20260601092817.0").help().epilogue(`For complete list of configuration options, please visit:
|
|
11985
11212
|
• Web options: https://midscenejs.com/automate-with-scripts-in-yaml#the-web-part
|
|
11986
11213
|
• Android options: https://midscenejs.com/automate-with-scripts-in-yaml#the-android-part
|
|
11987
11214
|
• iOS options: https://midscenejs.com/automate-with-scripts-in-yaml#the-ios-part
|
|
@@ -11991,7 +11218,7 @@ Examples:
|
|
|
11991
11218
|
$0 script.yaml --android.device-id emulator-5554 --android.ime-strategy yadb-for-non-ascii
|
|
11992
11219
|
$0 script.yaml --ios.wda-port 8100 --ios.auto-dismiss-keyboard`).wrap(yargs().terminalWidth());
|
|
11993
11220
|
const argv = await args.argv;
|
|
11994
|
-
|
|
11221
|
+
debug('argv', argv);
|
|
11995
11222
|
const transformedArgv = {
|
|
11996
11223
|
...argv
|
|
11997
11224
|
};
|
|
@@ -12015,7 +11242,7 @@ Examples:
|
|
|
12015
11242
|
};
|
|
12016
11243
|
};
|
|
12017
11244
|
async function matchYamlFiles(fileGlob, options) {
|
|
12018
|
-
if ((0,
|
|
11245
|
+
if ((0, external_node_fs_.existsSync)(fileGlob) && (0, external_node_fs_.statSync)(fileGlob).isDirectory()) fileGlob = (0, external_node_path_.join)(fileGlob, '**/*.{yml,yaml}');
|
|
12019
11246
|
const { cwd } = options || {};
|
|
12020
11247
|
const ignore = [
|
|
12021
11248
|
'**/node_modules/**'
|
|
@@ -12029,6 +11256,7 @@ Examples:
|
|
|
12029
11256
|
});
|
|
12030
11257
|
return files.filter((file)=>file.endsWith('.yml') || file.endsWith('.yaml')).sort();
|
|
12031
11258
|
}
|
|
11259
|
+
var framework = __webpack_require__("./src/framework/index.ts");
|
|
12032
11260
|
Promise.resolve((async ()=>{
|
|
12033
11261
|
const rawArgs = process.argv.slice(2);
|
|
12034
11262
|
const [firstArg] = rawArgs;
|
|
@@ -12087,8 +11315,8 @@ Examples:
|
|
|
12087
11315
|
console.error('Could not create a valid configuration.');
|
|
12088
11316
|
process.exit(1);
|
|
12089
11317
|
}
|
|
12090
|
-
const dotEnvConfigFile = (0,
|
|
12091
|
-
if ((0,
|
|
11318
|
+
const dotEnvConfigFile = (0, external_node_path_.join)(process.cwd(), '.env');
|
|
11319
|
+
if ((0, external_node_fs_.existsSync)(dotEnvConfigFile)) {
|
|
12092
11320
|
console.log(` Env file: ${dotEnvConfigFile}`);
|
|
12093
11321
|
main_default().config({
|
|
12094
11322
|
path: dotEnvConfigFile,
|
|
@@ -12096,21 +11324,24 @@ Examples:
|
|
|
12096
11324
|
override: config.dotenvOverride
|
|
12097
11325
|
});
|
|
12098
11326
|
}
|
|
12099
|
-
const
|
|
12100
|
-
await executor.run();
|
|
12101
|
-
const success = executor.printExecutionSummary();
|
|
11327
|
+
const exitCode = await (0, framework.runFrameworkTestConfig)(config);
|
|
12102
11328
|
if (config.keepWindow) setInterval(()=>{
|
|
12103
11329
|
console.log('browser is still running, use ctrl+c to stop it');
|
|
12104
11330
|
}, 5000);
|
|
12105
|
-
else
|
|
12106
|
-
if (!success) process.exit(1);
|
|
12107
|
-
process.exit(0);
|
|
12108
|
-
}
|
|
11331
|
+
else process.exit(exitCode);
|
|
12109
11332
|
})().catch((e1)=>{
|
|
12110
11333
|
console.error(e1);
|
|
12111
11334
|
process.exit(1);
|
|
12112
11335
|
}));
|
|
12113
11336
|
},
|
|
11337
|
+
"@midscene/core/yaml" (module) {
|
|
11338
|
+
"use strict";
|
|
11339
|
+
module.exports = require("@midscene/core/yaml");
|
|
11340
|
+
},
|
|
11341
|
+
"@midscene/shared/logger" (module) {
|
|
11342
|
+
"use strict";
|
|
11343
|
+
module.exports = require("@midscene/shared/logger");
|
|
11344
|
+
},
|
|
12114
11345
|
assert (module) {
|
|
12115
11346
|
"use strict";
|
|
12116
11347
|
module.exports = require("assert");
|
|
@@ -12123,6 +11354,22 @@ Examples:
|
|
|
12123
11354
|
"use strict";
|
|
12124
11355
|
module.exports = require("fs");
|
|
12125
11356
|
},
|
|
11357
|
+
"lodash.merge" (module) {
|
|
11358
|
+
"use strict";
|
|
11359
|
+
module.exports = require("lodash.merge");
|
|
11360
|
+
},
|
|
11361
|
+
"node:fs" (module) {
|
|
11362
|
+
"use strict";
|
|
11363
|
+
module.exports = require("node:fs");
|
|
11364
|
+
},
|
|
11365
|
+
"node:path" (module) {
|
|
11366
|
+
"use strict";
|
|
11367
|
+
module.exports = require("node:path");
|
|
11368
|
+
},
|
|
11369
|
+
"node:url" (module) {
|
|
11370
|
+
"use strict";
|
|
11371
|
+
module.exports = require("node:url");
|
|
11372
|
+
},
|
|
12126
11373
|
os (module) {
|
|
12127
11374
|
"use strict";
|
|
12128
11375
|
module.exports = require("os");
|