@midscene/cli 1.12.10-beta-20260920031616.0 → 1.13.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.
@@ -2463,7 +2463,6 @@ var __webpack_exports__ = {};
2463
2463
  });
2464
2464
  var external_node_fs_ = __webpack_require__("node:fs");
2465
2465
  var external_node_path_ = __webpack_require__("node:path");
2466
- var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_);
2467
2466
  const external_node_crypto_namespaceObject = require("node:crypto");
2468
2467
  var core_ = __webpack_require__("@midscene/core");
2469
2468
  const common_namespaceObject = require("@midscene/shared/common");
@@ -2928,282 +2927,7 @@ var __webpack_exports__ = {};
2928
2927
  }
2929
2928
  const external_puppeteer_namespaceObject = require("puppeteer");
2930
2929
  var external_puppeteer_default = /*#__PURE__*/ __webpack_require__.n(external_puppeteer_namespaceObject);
2931
- const external_http_server_namespaceObject = require("http-server");
2932
- const external_node_assert_namespaceObject = require("node:assert");
2933
- var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
2934
- const agent_namespaceObject = require("@midscene/core/agent");
2935
- const utils_namespaceObject = require("@midscene/core/utils");
2936
- const bridge_mode_namespaceObject = require("@midscene/web/bridge-mode");
2937
- const debug = (0, logger_.getDebug)('create-yaml-player');
2938
- const cleanupWarning = (0, logger_.getDebug)('create-yaml-player', {
2939
- console: true
2940
- });
2941
- async function cleanupFailedPlayerSetup(freeFn) {
2942
- for (const cleanup of [
2943
- ...freeFn
2944
- ].reverse())try {
2945
- await cleanup.fn();
2946
- } catch (error) {
2947
- cleanupWarning(`failed to run ${cleanup.name} after YAML player setup failed`, error);
2948
- }
2949
- }
2950
- const launchServer = async (dir)=>new Promise((resolve)=>{
2951
- const server = (0, external_http_server_namespaceObject.createServer)({
2952
- root: dir
2953
- });
2954
- server.listen(0, '127.0.0.1', ()=>{
2955
- resolve(server);
2956
- });
2957
- });
2958
- function resolveReportFileName(yamlReportFileName, cliTestId, yamlTestId, fileName) {
2959
- if (void 0 !== yamlReportFileName) return yamlReportFileName;
2960
- const baseName = cliTestId ?? yamlTestId ?? fileName;
2961
- return (0, agent_namespaceObject.getReportFileName)(baseName);
2962
- }
2963
- function buildAgentOptions(yamlAgent, reportFileName, fileName) {
2964
- return {
2965
- ...yamlAgent || {},
2966
- cache: (0, utils_namespaceObject.processCacheConfig)(yamlAgent?.cache, fileName),
2967
- reportFileName
2968
- };
2969
- }
2970
- async function createYamlPlayer(file, script, options) {
2971
- const yamlScript = script || (0, yaml_.parseYamlScript)((0, external_node_fs_.readFileSync)(file, 'utf-8'), file);
2972
- const clonedYamlScript = structuredClone(yamlScript);
2973
- const fileName = (0, external_node_path_.basename)(file, (0, external_node_path_.extname)(file));
2974
- const preference = {
2975
- headed: options?.headed,
2976
- keepWindow: options?.keepWindow,
2977
- reportFileName: resolveReportFileName(clonedYamlScript.agent?.reportFileName, options?.testId, clonedYamlScript.agent?.testId, fileName)
2978
- };
2979
- const player = new yaml_.ScriptPlayer(clonedYamlScript, async ()=>{
2980
- const freeFn = [];
2981
- try {
2982
- const resolvedWebTarget = (0, yaml_.resolveWebTarget)(clonedYamlScript);
2983
- const webTarget = resolvedWebTarget?.target;
2984
- const targetCount = [
2985
- void 0 !== resolvedWebTarget,
2986
- void 0 !== clonedYamlScript.android,
2987
- void 0 !== clonedYamlScript.ios,
2988
- void 0 !== clonedYamlScript.harmony,
2989
- void 0 !== clonedYamlScript.computer,
2990
- void 0 !== clonedYamlScript.interface
2991
- ].filter(Boolean).length;
2992
- if (targetCount > 1) {
2993
- const specifiedTargets = [
2994
- resolvedWebTarget?.source ?? null,
2995
- void 0 !== clonedYamlScript.android ? 'android' : null,
2996
- void 0 !== clonedYamlScript.ios ? 'ios' : null,
2997
- void 0 !== clonedYamlScript.harmony ? 'harmony' : null,
2998
- void 0 !== clonedYamlScript.computer ? 'computer' : null,
2999
- void 0 !== clonedYamlScript.interface ? 'interface' : null
3000
- ].filter(Boolean);
3001
- throw new Error(`Only one target type can be specified, but found multiple: ${specifiedTargets.join(', ')}. Please specify only one of: page, browser, web, android, ios, harmony, computer, or interface.`);
3002
- }
3003
- if (void 0 !== webTarget) {
3004
- if (resolvedWebTarget?.source === 'target') console.warn("target is deprecated, please use page or browser instead. See https://midscenejs.com/automate-with-scripts-in-yaml for more information. Sorry for the inconvenience.");
3005
- let localServer;
3006
- let urlToVisit;
3007
- if (webTarget.serve) {
3008
- external_node_assert_default()('string' == typeof webTarget.url, 'url is required in serve mode');
3009
- localServer = await launchServer(webTarget.serve);
3010
- const serverAddress = localServer.server.address();
3011
- freeFn.push({
3012
- name: 'local_server',
3013
- fn: async ()=>{
3014
- if (!localServer) return;
3015
- await new Promise((resolve, reject)=>{
3016
- localServer?.server.close((error)=>{
3017
- if (error) reject(error);
3018
- else resolve();
3019
- });
3020
- });
3021
- }
3022
- });
3023
- urlToVisit = webTarget.url.startsWith('/') ? `http://${serverAddress?.address}:${serverAddress?.port}${webTarget.url}` : `http://${serverAddress?.address}:${serverAddress?.port}/${webTarget.url}`;
3024
- webTarget.url = urlToVisit;
3025
- }
3026
- if (webTarget.cdpEndpoint && webTarget.bridgeMode) throw new Error('cdpEndpoint and bridgeMode are mutually exclusive. Please specify only one.');
3027
- if ('browser' === webTarget.mode && webTarget.bridgeMode) throw new Error('[midscene] browser mode does not support bridgeMode. Use page: or web.mode: page for bridge mode.');
3028
- if (webTarget.cdpEndpoint) {
3029
- const ownsCdpBrowser = !options?.browser;
3030
- const cdpBrowser = options?.browser ?? await external_puppeteer_default().connect({
3031
- browserWSEndpoint: webTarget.cdpEndpoint,
3032
- defaultViewport: null,
3033
- downloadBehavior: (0, puppeteer_agent_launcher_namespaceObject.buildDownloadBehavior)(webTarget.downloadPath)
3034
- });
3035
- if (webTarget.chromeArgs) console.warn('chromeArgs are not supported in CDP mode (browser is already running). They will be ignored.');
3036
- let launchedAgent;
3037
- try {
3038
- launchedAgent = await (0, puppeteer_agent_launcher_namespaceObject.puppeteerAgentForTarget)(webTarget, {
3039
- ...preference,
3040
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3041
- }, cdpBrowser, options?.page, options?.browserContext);
3042
- } catch (error) {
3043
- if (ownsCdpBrowser) try {
3044
- cdpBrowser.disconnect();
3045
- } catch (cleanupError) {
3046
- cleanupWarning('failed to disconnect the CDP browser after agent setup failed', cleanupError);
3047
- }
3048
- throw error;
3049
- }
3050
- const { agent, freeFn: newFreeFn } = launchedAgent;
3051
- const cleanFreeFn = newFreeFn.filter((f)=>'puppeteer_browser' !== f.name);
3052
- freeFn.push(...cleanFreeFn);
3053
- if (ownsCdpBrowser) freeFn.push({
3054
- name: 'cdp_browser_disconnect',
3055
- fn: ()=>cdpBrowser.disconnect()
3056
- });
3057
- return {
3058
- agent,
3059
- freeFn
3060
- };
3061
- }
3062
- if (!webTarget.bridgeMode) {
3063
- const { agent, freeFn: newFreeFn } = await (0, puppeteer_agent_launcher_namespaceObject.puppeteerAgentForTarget)(webTarget, {
3064
- ...preference,
3065
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3066
- }, options?.browser, options?.page, options?.browserContext);
3067
- freeFn.push(...newFreeFn);
3068
- return {
3069
- agent,
3070
- freeFn
3071
- };
3072
- }
3073
- external_node_assert_default()('newTabWithUrl' === webTarget.bridgeMode || 'currentTab' === webTarget.bridgeMode, `bridgeMode config value must be either "newTabWithUrl" or "currentTab", but got ${webTarget.bridgeMode}`);
3074
- const bridgeUnsupportedKeys = [
3075
- 'userAgent',
3076
- 'viewportWidth',
3077
- 'viewportHeight',
3078
- 'deviceScaleFactor',
3079
- 'waitForNetworkIdle',
3080
- 'cookie',
3081
- 'extraHTTPHeaders',
3082
- 'downloadPath',
3083
- 'chromeArgs'
3084
- ];
3085
- const ignoredKeys = bridgeUnsupportedKeys.filter((key)=>null != webTarget[key]);
3086
- if (ignoredKeys.length > 0) console.warn(`puppeteer options (${ignoredKeys.join(', ')}) are not supported in bridge mode. They will be ignored.`);
3087
- const agent = new bridge_mode_namespaceObject.AgentOverChromeBridge({
3088
- closeNewTabsAfterDisconnect: webTarget.closeNewTabsAfterDisconnect,
3089
- closeConflictServer: true,
3090
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3091
- });
3092
- if ('newTabWithUrl' === webTarget.bridgeMode) await agent.connectNewTabWithUrl(webTarget.url);
3093
- else {
3094
- if (webTarget.url) console.warn('url will be ignored in bridge mode with "currentTab"');
3095
- await agent.connectCurrentTab();
3096
- }
3097
- freeFn.push({
3098
- name: 'destroy_agent_over_chrome_bridge',
3099
- fn: ()=>agent.destroy()
3100
- });
3101
- return {
3102
- agent,
3103
- freeFn
3104
- };
3105
- }
3106
- if (void 0 !== clonedYamlScript.android) {
3107
- const androidTarget = clonedYamlScript.android;
3108
- const { agentFromAdbDevice } = await import("@midscene/android");
3109
- const agent = await agentFromAdbDevice(androidTarget?.deviceId, {
3110
- ...androidTarget,
3111
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3112
- });
3113
- if (androidTarget?.launch) await agent.launch(androidTarget.launch);
3114
- freeFn.push({
3115
- name: 'destroy_android_agent',
3116
- fn: ()=>agent.destroy()
3117
- });
3118
- return {
3119
- agent,
3120
- freeFn
3121
- };
3122
- }
3123
- if (void 0 !== clonedYamlScript.ios) {
3124
- const iosTarget = clonedYamlScript.ios;
3125
- const { agentFromWebDriverAgent } = await import("@midscene/ios");
3126
- const agent = await agentFromWebDriverAgent({
3127
- ...iosTarget,
3128
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3129
- });
3130
- if (iosTarget?.launch) await agent.launch(iosTarget.launch);
3131
- freeFn.push({
3132
- name: 'destroy_ios_agent',
3133
- fn: ()=>agent.destroy()
3134
- });
3135
- return {
3136
- agent,
3137
- freeFn
3138
- };
3139
- }
3140
- if (void 0 !== clonedYamlScript.harmony) {
3141
- const harmonyTarget = clonedYamlScript.harmony;
3142
- const { agentFromHdcDevice } = await import("@midscene/harmony");
3143
- const agent = await agentFromHdcDevice(harmonyTarget?.deviceId, {
3144
- ...harmonyTarget,
3145
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3146
- });
3147
- if (harmonyTarget?.launch) await agent.launch(harmonyTarget.launch);
3148
- freeFn.push({
3149
- name: 'destroy_harmony_agent',
3150
- fn: ()=>agent.destroy()
3151
- });
3152
- return {
3153
- agent,
3154
- freeFn
3155
- };
3156
- }
3157
- if (void 0 !== clonedYamlScript.computer) {
3158
- const computerTarget = clonedYamlScript.computer;
3159
- const { agentForComputer } = await import("@midscene/computer");
3160
- const agent = await agentForComputer({
3161
- ...computerTarget,
3162
- ...buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName)
3163
- });
3164
- freeFn.push({
3165
- name: 'destroy_computer_agent',
3166
- fn: ()=>agent.destroy()
3167
- });
3168
- return {
3169
- agent,
3170
- freeFn
3171
- };
3172
- }
3173
- if (void 0 !== clonedYamlScript.interface) {
3174
- const interfaceTarget = clonedYamlScript.interface;
3175
- const moduleSpecifier = interfaceTarget.module;
3176
- let finalModuleSpecifier;
3177
- if (moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../') || external_node_path_default().isAbsolute(moduleSpecifier)) {
3178
- const resolvedPath = (0, external_node_path_.join)(process.cwd(), moduleSpecifier);
3179
- finalModuleSpecifier = resolvedPath;
3180
- } else finalModuleSpecifier = moduleSpecifier;
3181
- debug('importing module config', interfaceTarget.module, 'with export config', interfaceTarget.export, 'final module specifier', finalModuleSpecifier);
3182
- const importedModule = await import(finalModuleSpecifier);
3183
- const DeviceClass = interfaceTarget.export ? importedModule[interfaceTarget.export] : importedModule.default || importedModule;
3184
- debug('DeviceClass', DeviceClass, 'with param', interfaceTarget.param);
3185
- const device = new DeviceClass(interfaceTarget.param || {});
3186
- debug('creating agent from device', device);
3187
- const agent = (0, agent_namespaceObject.createAgent)(device, buildAgentOptions(clonedYamlScript.agent, preference.reportFileName, fileName));
3188
- freeFn.push({
3189
- name: 'destroy_general_interface_agent',
3190
- fn: ()=>{
3191
- agent.destroy();
3192
- }
3193
- });
3194
- return {
3195
- agent,
3196
- freeFn
3197
- };
3198
- }
3199
- throw new Error('No valid interface configuration found in the yaml script, should be either "web", "android", "ios", "harmony", "computer", or "interface"');
3200
- } catch (error) {
3201
- await cleanupFailedPlayerSetup(freeFn);
3202
- throw error;
3203
- }
3204
- }, void 0, file);
3205
- return player;
3206
- }
2930
+ const yaml_runtime_namespaceObject = require("@midscene/test/internal/yaml-runtime");
3207
2931
  var chalk_source = __webpack_require__("../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/source/index.js");
3208
2932
  var source_default = /*#__PURE__*/ __webpack_require__.n(chalk_source);
3209
2933
  function resolveIsTTY(env = process.env, stdoutIsTTY = process.stdout.isTTY) {
@@ -3850,7 +3574,7 @@ var __webpack_exports__ = {};
3850
3574
  const createFilePlayerContext = async (context)=>{
3851
3575
  const fileContext = {
3852
3576
  file: context.file,
3853
- player: await createYamlPlayer(context.file, context.executionConfig, context.options)
3577
+ player: await (0, yaml_runtime_namespaceObject.createYamlPlayer)(context.file, context.executionConfig, context.options)
3854
3578
  };
3855
3579
  fileContextsByCaseId.set(context.caseId, fileContext);
3856
3580
  return fileContext;
@@ -3895,7 +3619,7 @@ var __webpack_exports__ = {};
3895
3619
  if (attempt > 1) {
3896
3620
  if (context.executionConfig.agent?.reportFileName) attempts[attempts.length - 1] = preserveYamlAttemptReport(attempts[attempts.length - 1]);
3897
3621
  await beforeRetry?.();
3898
- allFileContext.player = await createYamlPlayer(context.file, context.executionConfig, context.options);
3622
+ allFileContext.player = await (0, yaml_runtime_namespaceObject.createYamlPlayer)(context.file, context.executionConfig, context.options);
3899
3623
  }
3900
3624
  if (onProgress) reportProgressSnapshot(allFileContext, attempt, totalAttempts);
3901
3625
  else if (!isTTY) {
@@ -4546,6 +4270,7 @@ defineYamlBatchTest(test, testOptions);
4546
4270
  if ('error' === task.status) return `Task "${task.name}" failed`;
4547
4271
  };
4548
4272
  const cloneJson = (value)=>JSON.parse(JSON.stringify(value));
4273
+ const yaml_case_errorMessageOf = (error)=>error instanceof Error ? error.message : String(error);
4549
4274
  const normalizeTargetConfig = (config)=>{
4550
4275
  if (config.target) {
4551
4276
  config.web = {
@@ -4605,7 +4330,7 @@ defineYamlBatchTest(test, testOptions);
4605
4330
  const file = (0, external_node_path_.resolve)(options.file);
4606
4331
  const startTime = Date.now();
4607
4332
  const executionConfig = options.executionConfig || (options.globalConfig ? createExecutionConfig(file, options.globalConfig) : void 0);
4608
- const player = await createYamlPlayer(file, executionConfig, {
4333
+ const player = await (0, yaml_runtime_namespaceObject.createYamlPlayer)(file, executionConfig, {
4609
4334
  headed: options.headed,
4610
4335
  keepWindow: options.keepWindow
4611
4336
  });
@@ -4616,12 +4341,22 @@ defineYamlBatchTest(test, testOptions);
4616
4341
  });
4617
4342
  };
4618
4343
  reportSnapshot();
4344
+ let runError;
4619
4345
  try {
4620
4346
  await player.run();
4347
+ } catch (error) {
4348
+ runError = error;
4621
4349
  } finally{
4622
4350
  reportSnapshot();
4623
4351
  }
4624
- return createYamlCaseResult(file, player, Date.now() - startTime);
4352
+ const result = createYamlCaseResult(file, player, Date.now() - startTime);
4353
+ if (void 0 === runError) return result;
4354
+ return {
4355
+ ...result,
4356
+ success: false,
4357
+ resultType: 'failed',
4358
+ error: result.error ?? yaml_case_errorMessageOf(runError)
4359
+ };
4625
4360
  };
4626
4361
  function runYamlCaseResultWithSnapshots(options, onPlayerSnapshot) {
4627
4362
  return executeYamlCaseResult(options, onPlayerSnapshot);