@midscene/cli 1.13.1-beta-20260922030100.0 → 1.13.1

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/index.mjs CHANGED
@@ -19,6 +19,7 @@ import puppeteer from "puppeteer";
19
19
  import { createYamlPlayer as yaml_runtime_createYamlPlayer } from "@midscene/test/internal/yaml-runtime";
20
20
  import { stripVTControlCharacters } from "node:util";
21
21
  import { createRequire } from "node:module";
22
+ import { serializeError } from "@midscene/shared/agent-tools/error-formatter";
22
23
  import { globalModelConfigManager } from "@midscene/shared/env";
23
24
  import { classifyWorkflowDocumentFormat } from "@midscene/core/internal/test-runner";
24
25
  import * as __rspack_external_assert from "assert";
@@ -3022,7 +3023,9 @@ var __webpack_modules__ = {
3022
3023
  module.exports = (string, columns, options)=>String(string).normalize().replace(/\r\n/g, '\n').split('\n').map((line)=>exec(line, columns, options)).join('\n');
3023
3024
  },
3024
3025
  "./src/index.ts" (__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
3025
- var package_namespaceObject = JSON.parse('{"rE":"1.13.1-beta-20260922030100.0"}');
3026
+ var package_namespaceObject = {
3027
+ rE: "1.13.1"
3028
+ };
3026
3029
  var brace_expansion = __webpack_require__("../../node_modules/.pnpm/brace-expansion@2.0.1/node_modules/brace-expansion/index.js");
3027
3030
  const MAX_PATTERN_LENGTH = 65536;
3028
3031
  const assertValidPattern = (pattern)=>{
@@ -8602,6 +8605,7 @@ var __webpack_modules__ = {
8602
8605
  continueOnError: false,
8603
8606
  retry: 0,
8604
8607
  shareBrowserContext: false,
8608
+ reusePage: false,
8605
8609
  headed: false,
8606
8610
  keepWindow: false,
8607
8611
  dotenvOverride: false,
@@ -8676,6 +8680,10 @@ Usage:
8676
8680
  type: 'boolean',
8677
8681
  description: `Share a Puppeteer Web browser context across multiple yaml files, default is ${config_options_defaultConfig.shareBrowserContext}`
8678
8682
  },
8683
+ 'reuse-page': {
8684
+ type: 'boolean',
8685
+ description: `Reuse one Puppeteer Web page across sequential yaml files; requires --share-browser-context and --concurrent 1, default is ${config_options_defaultConfig.reusePage}`
8686
+ },
8679
8687
  'dotenv-override': {
8680
8688
  type: 'boolean',
8681
8689
  description: `Whether the variables in the .env file override the global variables, the default is ${config_options_defaultConfig.dotenvOverride}`
@@ -8688,7 +8696,7 @@ Usage:
8688
8696
  type: 'boolean',
8689
8697
  description: 'Whether to dismiss the HarmonyOS keyboard after text input'
8690
8698
  }
8691
- }).version('version', 'Show version number', "1.13.1-beta-20260922030100.0").help().epilogue(`For complete list of configuration options, please visit:
8699
+ }).version('version', 'Show version number', "1.13.1").help().epilogue(`For complete list of configuration options, please visit:
8692
8700
  • Web options: https://midscenejs.com/automate-with-scripts-in-yaml#the-web-part
8693
8701
  • Android options: https://midscenejs.com/automate-with-scripts-in-yaml#the-android-part
8694
8702
  • HarmonyOS options: https://midscenejs.com/automate-with-scripts-in-yaml#the-harmony-part
@@ -10864,6 +10872,7 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
10864
10872
  retry: configYaml.retry ?? config_options_defaultConfig.retry,
10865
10873
  summary: configYaml.summary ?? defaultSummary,
10866
10874
  shareBrowserContext: configYaml.shareBrowserContext ?? config_options_defaultConfig.shareBrowserContext,
10875
+ reusePage: configYaml.reusePage ?? config_options_defaultConfig.reusePage,
10867
10876
  patterns: configYaml.files,
10868
10877
  files,
10869
10878
  setup,
@@ -10891,6 +10900,7 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
10891
10900
  setup = await resolveSetupFile(options.setup, basePath);
10892
10901
  }
10893
10902
  const shareBrowserContext = options?.shareBrowserContext ?? parsedConfig.shareBrowserContext;
10903
+ const reusePage = options?.reusePage ?? parsedConfig.reusePage;
10894
10904
  return {
10895
10905
  files,
10896
10906
  setup,
@@ -10899,6 +10909,7 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
10899
10909
  retry: options?.retry ?? parsedConfig.retry,
10900
10910
  summary: options?.summary ?? parsedConfig.summary,
10901
10911
  shareBrowserContext,
10912
+ reusePage,
10902
10913
  headed: finalHeaded,
10903
10914
  keepWindow: keepWindow,
10904
10915
  dotenvOverride: options?.dotenvOverride ?? parsedConfig.dotenvOverride,
@@ -10915,6 +10926,7 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
10915
10926
  const headed = options.headed ?? config_options_defaultConfig.headed;
10916
10927
  const finalHeaded = keepWindow || headed;
10917
10928
  const shareBrowserContext = options.shareBrowserContext ?? config_options_defaultConfig.shareBrowserContext;
10929
+ const reusePage = options.reusePage ?? config_options_defaultConfig.reusePage;
10918
10930
  return {
10919
10931
  files,
10920
10932
  setup,
@@ -10923,6 +10935,7 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
10923
10935
  retry: options.retry ?? config_options_defaultConfig.retry,
10924
10936
  summary: options.summary ?? defaultSummary,
10925
10937
  shareBrowserContext,
10938
+ reusePage,
10926
10939
  headed: finalHeaded,
10927
10940
  keepWindow: keepWindow,
10928
10941
  dotenvOverride: options.dotenvOverride ?? config_options_defaultConfig.dotenvOverride,
@@ -11194,6 +11207,7 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
11194
11207
  console.log(` Continue on error: ${config.continueOnError}`);
11195
11208
  console.log(` Retry: ${config.retry ?? 0}`);
11196
11209
  console.log(` Share browser context: ${config.shareBrowserContext ?? false}`);
11210
+ console.log(` Reuse browser page: ${config.reusePage ?? false}`);
11197
11211
  console.log(` Summary output: ${config.summary}`);
11198
11212
  }
11199
11213
  function printExecutionFinished() {
@@ -11888,11 +11902,22 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
11888
11902
  }
11889
11903
  if (setupContext && !shareBrowserContext && 'puppeteer-web' === resolveBatchRuntimeTarget(setupContext.executionConfig)) throw new Error(`Puppeteer Web setup "${setupContext.file}" requires shareBrowserContext: true so its browser state can be shared with the main files.`);
11890
11904
  };
11891
- const createSharedBrowserRuntime = async (browser, browserContextOptions)=>{
11905
+ const createSharedBrowserRuntime = async (browser, browserContextOptions, reusePage = false)=>{
11892
11906
  const browserContext = await browser.createBrowserContext(browserContextOptions);
11893
- return {
11894
- browserContext
11895
- };
11907
+ try {
11908
+ const page = reusePage ? await browserContext.newPage() : void 0;
11909
+ return {
11910
+ browserContext,
11911
+ page
11912
+ };
11913
+ } catch (error) {
11914
+ try {
11915
+ await browserContext.close();
11916
+ } catch (cleanupError) {
11917
+ batchWarning('failed to close the shared browser context after page creation failed; preserving the original error', cleanupError);
11918
+ }
11919
+ throw error;
11920
+ }
11896
11921
  };
11897
11922
  class YamlBatchExecutor {
11898
11923
  async run(options = {}) {
@@ -11977,10 +12002,11 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
11977
12002
  sharedRuntime.current = null;
11978
12003
  await staleRuntime.browserContext.close();
11979
12004
  }
11980
- sharedRuntime.current = await createSharedBrowserRuntime(browser, browserContextOptions);
12005
+ sharedRuntime.current = await createSharedBrowserRuntime(browser, browserContextOptions, this.config.reusePage);
11981
12006
  for (const context of allContexts){
11982
12007
  context.options.browser = browser;
11983
12008
  context.options.browserContext = sharedRuntime.current.browserContext;
12009
+ if (sharedRuntime.current.page) context.options.page = sharedRuntime.current.page;
11984
12010
  }
11985
12011
  };
11986
12012
  await resetSetupRuntime();
@@ -12260,6 +12286,8 @@ Native cases/steps Test projects use the midscene-test command.`).wrap(yargs().t
12260
12286
  }, (_, index)=>`batch-occurrence-${index + 1}`);
12261
12287
  if (this.caseIds.length !== occurrenceCount) throw new Error(`Batch occurrence identity mismatch: expected ${occurrenceCount} case ID(s), received ${this.caseIds.length}`);
12262
12288
  if (new Set(this.caseIds).size !== this.caseIds.length) throw new Error('Batch occurrence case IDs must be unique');
12289
+ if (config.reusePage && !config.shareBrowserContext) throw new Error('reusePage requires shareBrowserContext: true');
12290
+ if (config.reusePage && 1 !== config.concurrent) throw new Error('reusePage requires concurrent: 1');
12263
12291
  }
12264
12292
  }
12265
12293
  async function runYamlBatch(config, options = {}) {
@@ -12503,27 +12531,23 @@ defineYamlBatchTest(test, testOptions);
12503
12531
  }
12504
12532
  });
12505
12533
  const rstest_contract_RSTEST_YAML_CASE_IDS_META_KEY = 'midsceneYamlCaseIds';
12506
- const formatRunError = (error)=>error.stack || `${error.name}: ${error.message}`;
12534
+ const formatRunError = (error)=>error.stack || `${error.name || 'Error'}: ${error.message}`;
12507
12535
  const collectRunErrors = (result)=>{
12508
12536
  const messages = [];
12509
12537
  const push = (error, label)=>{
12510
12538
  const formatted = formatRunError(error);
12511
12539
  messages.push(label ? `${label}: ${formatted}` : formatted);
12512
12540
  };
12513
- for (const file of result.files ?? []){
12541
+ for (const file of result.results){
12514
12542
  for (const error of file.errors ?? [])push(error, file.name || file.testPath);
12515
12543
  for (const testResult of file.results ?? [])for (const error of testResult.errors ?? [])push(error, testResult.name);
12516
12544
  }
12517
- for (const error of result.unhandledErrors ?? [])push(error);
12545
+ for (const error of result.unhandledErrors)push(error);
12518
12546
  return Array.from(new Set(messages));
12519
12547
  };
12520
12548
  const rstest_runner_errorMessage = (error)=>error.message || error.name || 'YAML case failed';
12521
12549
  const mapRunErrorsToCases = (project, result)=>{
12522
- const casesById = new Map(project.cases.map((item)=>[
12523
- item.caseId,
12524
- item
12525
- ]));
12526
- const knownCaseIds = new Set(casesById.keys());
12550
+ const knownCaseIds = new Set(project.cases.map((item)=>item.caseId));
12527
12551
  const errors = new Map();
12528
12552
  const add = (caseId, message)=>{
12529
12553
  if (knownCaseIds.has(caseId) && message && !errors.has(caseId)) errors.set(caseId, message);
@@ -12546,7 +12570,7 @@ defineYamlBatchTest(test, testOptions);
12546
12570
  const value = testResult.meta?.[rstest_contract_RSTEST_YAML_CASE_IDS_META_KEY];
12547
12571
  return Array.isArray(value) ? value.filter((item)=>'string' == typeof item) : [];
12548
12572
  };
12549
- for (const file of result.files ?? []){
12573
+ for (const file of result.results){
12550
12574
  const moduleCaseIds = findModuleCaseIds(file);
12551
12575
  for (const error of file.errors ?? [])addCases(moduleCaseIds, rstest_runner_errorMessage(error));
12552
12576
  for (const testResult of file.results ?? []){
@@ -12554,18 +12578,13 @@ defineYamlBatchTest(test, testOptions);
12554
12578
  for (const error of testResult.errors ?? [])addCases(caseIds.length ? caseIds : moduleCaseIds, rstest_runner_errorMessage(error));
12555
12579
  }
12556
12580
  }
12557
- if (1 === project.modules.length && result.unhandledErrors?.length) {
12581
+ if (result.unhandledErrors.length) {
12558
12582
  const message = rstest_runner_errorMessage(result.unhandledErrors[0]);
12559
- for (const caseId of project.modules[0].caseIds){
12560
- const item = casesById.get(caseId);
12561
- if (!errors.has(caseId) || item && !(0, __rspack_external_node_fs_5ea92f0c.existsSync)(item.resultFile)) errors.set(caseId, message);
12562
- }
12583
+ for (const item of project.cases)if (!errors.has(item.caseId) && !(0, __rspack_external_node_fs_5ea92f0c.existsSync)(item.resultFile)) errors.set(item.caseId, message);
12563
12584
  }
12564
12585
  return errors;
12565
12586
  };
12566
- const recordUnreportedCaseFailures = (project, result)=>{
12567
- if (!project.cases.length) return;
12568
- const caseErrors = mapRunErrorsToCases(project, result);
12587
+ const writePendingCaseFailures = (project, caseErrors)=>{
12569
12588
  for (const item of project.cases){
12570
12589
  if ((0, __rspack_external_node_fs_5ea92f0c.existsSync)(item.resultFile)) continue;
12571
12590
  const error = caseErrors.get(item.caseId);
@@ -12587,13 +12606,13 @@ defineYamlBatchTest(test, testOptions);
12587
12606
  }
12588
12607
  };
12589
12608
  async function runRstestYamlProject(options) {
12590
- const [{ runRstest }, { rspack }] = await Promise.all([
12609
+ const [{ createRstest }, { rspack }] = await Promise.all([
12591
12610
  import("@rstest/core/api"),
12592
12611
  import(pathToFileURL(resolvePackageFromRstestCore('@rsbuild/core')).href)
12593
12612
  ]);
12594
12613
  const { project } = options;
12595
12614
  const maxConcurrency = void 0 !== project.maxConcurrency ? Math.max(1, project.maxConcurrency) : void 0;
12596
- const inlineConfig = {
12615
+ const config = {
12597
12616
  root: project.projectDir,
12598
12617
  include: project.modules.map((item)=>item.id),
12599
12618
  testEnvironment: 'node',
@@ -12624,18 +12643,31 @@ defineYamlBatchTest(test, testOptions);
12624
12643
  }
12625
12644
  }
12626
12645
  };
12627
- const result = await runRstest({
12628
- cwd: options.cwd || project.projectDir,
12629
- inlineConfig
12630
- });
12631
- if (!result.ok) {
12632
- recordUnreportedCaseFailures(project, result);
12646
+ let result;
12647
+ try {
12648
+ const rstest = await createRstest({
12649
+ cwd: options.cwd || project.projectDir,
12650
+ config
12651
+ });
12652
+ result = await rstest.run();
12653
+ } catch (error) {
12654
+ const serialized = serializeError(error);
12655
+ writePendingCaseFailures(project, new Map(project.cases.map((item)=>[
12656
+ item.caseId,
12657
+ serialized.message
12658
+ ])));
12659
+ if ('pipe' !== options.stdio) console.error(`\nYAML execution failed:\n${formatRunError(serialized)}`);
12660
+ return 1;
12661
+ }
12662
+ const ok = 'pass' === result.status;
12663
+ if (!ok) {
12664
+ writePendingCaseFailures(project, mapRunErrorsToCases(project, result));
12633
12665
  if ('pipe' !== options.stdio) {
12634
12666
  const runErrors = collectRunErrors(result);
12635
12667
  if (runErrors.length) console.error(`\nYAML execution failed:\n${runErrors.join('\n\n')}`);
12636
12668
  }
12637
12669
  }
12638
- return result.ok ? 0 : 1;
12670
+ return ok ? 0 : 1;
12639
12671
  }
12640
12672
  const defaultInProcessRunner = (config)=>new BatchRunner(config).run();
12641
12673
  async function runConfigInMainProcess(config, commandOptions) {
@@ -12928,6 +12960,7 @@ defineYamlBatchTest(test, testOptions);
12928
12960
  retry: options.retry,
12929
12961
  summary: options.summary,
12930
12962
  shareBrowserContext: options['share-browser-context'],
12963
+ reusePage: options['reuse-page'],
12931
12964
  headed: options.headed,
12932
12965
  keepWindow: options['keep-window'],
12933
12966
  dotenvOverride: options['dotenv-override'],