@midscene/test 1.17.6 → 1.17.7

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.
@@ -13,6 +13,7 @@ import { globSync } from "tinyglobby";
13
13
  import { createHash, randomUUID } from "node:crypto";
14
14
  import { JSON_SCHEMA, load } from "js-yaml";
15
15
  import { mkdir, writeFile } from "node:fs/promises";
16
+ import { resolveMidsceneRunDir, runWithMidsceneRunDir } from "@midscene/shared/common";
16
17
  import { setMaxListeners } from "node:events";
17
18
  import { ReportSession, TestRunReportAssembler, calculateTestRunHealth } from "@midscene/core/report";
18
19
  var __webpack_modules__ = {
@@ -30,7 +31,7 @@ var __webpack_modules__ = {
30
31
  },
31
32
  "./package.json" (module) {
32
33
  module.exports = {
33
- rE: "1.17.6"
34
+ rE: "1.17.7"
34
35
  };
35
36
  }
36
37
  };
@@ -1519,8 +1520,7 @@ const validateTestOptions = (value, hasExplicitProjects)=>{
1519
1520
  testTimeout: validatePositiveInteger(candidate.testTimeout, 120000, 'test.testTimeout')
1520
1521
  });
1521
1522
  };
1522
- const validateOutputPath = (value, fallback, label)=>{
1523
- if (void 0 === value) return fallback;
1523
+ const validateOutputPath = (value, label)=>{
1524
1524
  if ('string' != typeof value || 0 === value.trim().length) throw new TypeError(`Midscene config ${label} must be non-empty.`);
1525
1525
  return value;
1526
1526
  };
@@ -1534,7 +1534,9 @@ const validateOutput = (value)=>{
1534
1534
  if (void 0 !== candidate.reportFormat && 'single-html' !== candidate.reportFormat && 'html-and-external-assets' !== candidate.reportFormat) throw new TypeError('Midscene config output.reportFormat must be single-html or html-and-external-assets.');
1535
1535
  return Object.freeze({
1536
1536
  reportFormat: candidate.reportFormat ?? 'single-html',
1537
- reportDir: validateOutputPath(candidate.reportDir, './midscene_run/report', 'output.reportDir')
1537
+ ...void 0 === candidate.reportDir ? {} : {
1538
+ reportDir: validateOutputPath(candidate.reportDir, 'output.reportDir')
1539
+ }
1538
1540
  });
1539
1541
  };
1540
1542
  const validateTestProjectDefinition = (definition)=>{
@@ -2122,8 +2124,16 @@ const DEFAULT_TEST_FILE_SELECTION = {
2122
2124
  ]
2123
2125
  };
2124
2126
  const project_preparation_toPosix = (value)=>value.split(external_node_path_.sep).join('/');
2125
- const discoverResolvedTestFiles = (projectRoot, selection)=>{
2127
+ const discoverResolvedTestFiles = (projectRoot, selection, excludedDirectories = [])=>{
2126
2128
  const root = (0, external_node_path_.resolve)(projectRoot);
2129
+ const outputPatterns = excludedDirectories.flatMap((directory)=>{
2130
+ const withinRoot = (0, external_node_path_.relative)(root, directory);
2131
+ if (!withinRoot || (0, external_node_path_.isAbsolute)(withinRoot) || '..' === withinRoot || withinRoot.startsWith(`..${external_node_path_.sep}`)) return [];
2132
+ const literal = project_preparation_toPosix(withinRoot).replace(/([*?{}[\]()!])/g, '\\$1');
2133
+ return [
2134
+ `${literal}/**`
2135
+ ];
2136
+ });
2127
2137
  const match = (patterns)=>globSync(patterns, {
2128
2138
  absolute: true,
2129
2139
  caseSensitiveMatch: false,
@@ -2133,6 +2143,7 @@ const discoverResolvedTestFiles = (projectRoot, selection)=>{
2133
2143
  followSymbolicLinks: false,
2134
2144
  ignore: [
2135
2145
  ...ALWAYS_IGNORED_PATTERNS,
2146
+ ...outputPatterns,
2136
2147
  ...selection.exclude ?? []
2137
2148
  ],
2138
2149
  onlyFiles: true
@@ -2202,7 +2213,7 @@ async function prepareProject(project, projectRoot, runDir, defaultTimeoutMs, op
2202
2213
  const platform = options.platform?.trim();
2203
2214
  const fileSelection = project.files ?? DEFAULT_TEST_FILE_SELECTION;
2204
2215
  const prerequisiteFile = options.prerequisiteFile ? (0, external_node_path_.resolve)(options.prerequisiteFile) : void 0;
2205
- const mainFiles = options.files ?? discoverResolvedTestFiles(projectRoot, fileSelection);
2216
+ const mainFiles = options.files ?? discoverResolvedTestFiles(projectRoot, fileSelection, options.excludedDirectories);
2206
2217
  const files = [
2207
2218
  ...prerequisiteFile ? [
2208
2219
  prerequisiteFile
@@ -2367,40 +2378,58 @@ async function prepareTestRun(options) {
2367
2378
  if (options.configPath && /\.ya?ml$/i.test(configPath)) throw new Error(`midscene-test --config only accepts a native TypeScript or JavaScript project config: ${configPath}. Run legacy batch YAML with \`midscene --config ${options.configPath}\`.`);
2368
2379
  if (options.configPath && !(0, external_node_fs_.existsSync)(configPath)) throw new Error(`Midscene config does not exist: ${configPath}`);
2369
2380
  const definition = await loadTestProject(configPath);
2370
- const resultDir = options.resultDir ? (0, external_node_path_.resolve)(input.cwd, options.resultDir) : (0, external_node_path_.join)(input.projectRoot, '.midscene', 'test-results');
2371
- const runDir = (0, external_node_path_.join)(resultDir, runId);
2372
- const summaryPath = (0, external_node_path_.join)(runDir, 'summary.json');
2373
- const reportDir = (0, external_node_path_.resolve)(input.projectRoot, definition.output.reportDir);
2374
- (0, external_node_fs_.mkdirSync)(resultDir, {
2375
- recursive: true
2381
+ const artifactDir = resolveMidsceneRunDir(input.projectRoot);
2382
+ return runWithMidsceneRunDir(artifactDir, async ()=>{
2383
+ const resultDir = options.resultDir ? (0, external_node_path_.resolve)(input.cwd, options.resultDir) : (0, external_node_path_.join)(artifactDir, 'test-results');
2384
+ const runDir = (0, external_node_path_.join)(resultDir, runId);
2385
+ const summaryPath = (0, external_node_path_.join)(runDir, 'summary.json');
2386
+ const reportDir = definition.output.reportDir ? (0, external_node_path_.resolve)(input.projectRoot, definition.output.reportDir) : (0, external_node_path_.join)(artifactDir, 'report');
2387
+ (0, external_node_fs_.mkdirSync)(resultDir, {
2388
+ recursive: true
2389
+ });
2390
+ (0, external_node_fs_.mkdirSync)(runDir);
2391
+ const projects = [];
2392
+ for (const project of selectProjects(definition.projects, options.projectNames))projects.push(await prepareProject(project, input.projectRoot, runDir, definition.test.testTimeout, {
2393
+ ...input.singleFile ? {
2394
+ files: [
2395
+ input.singleFile
2396
+ ]
2397
+ } : {},
2398
+ excludedDirectories: [
2399
+ artifactDir,
2400
+ resultDir,
2401
+ reportDir,
2402
+ ...[
2403
+ 'cache',
2404
+ 'log',
2405
+ 'output',
2406
+ 'tmp',
2407
+ 'dump'
2408
+ ].map((name)=>(0, external_node_path_.join)(artifactDir, name))
2409
+ ]
2410
+ }));
2411
+ const hasFormatMismatch = projects.some((project)=>project.collectionErrors.some(({ error })=>error instanceof NativeWorkflowFormatError));
2412
+ return {
2413
+ startedAt,
2414
+ runId,
2415
+ projectRoot: input.projectRoot,
2416
+ artifactDir,
2417
+ ...configPath ? {
2418
+ configPath
2419
+ } : {},
2420
+ resultDir,
2421
+ runDir,
2422
+ summaryPath,
2423
+ reportDir,
2424
+ definition,
2425
+ projects,
2426
+ preflightScope: hasFormatMismatch ? 'run' : 'project',
2427
+ reportEnabled: true,
2428
+ publications: [],
2429
+ onProgress: options.onProgress ?? (()=>{}),
2430
+ onEvent: options.onEvent
2431
+ };
2376
2432
  });
2377
- (0, external_node_fs_.mkdirSync)(runDir);
2378
- const projects = [];
2379
- for (const project of selectProjects(definition.projects, options.projectNames))projects.push(await prepareProject(project, input.projectRoot, runDir, definition.test.testTimeout, input.singleFile ? {
2380
- files: [
2381
- input.singleFile
2382
- ]
2383
- } : void 0));
2384
- const hasFormatMismatch = projects.some((project)=>project.collectionErrors.some(({ error })=>error instanceof NativeWorkflowFormatError));
2385
- return {
2386
- startedAt,
2387
- runId,
2388
- projectRoot: input.projectRoot,
2389
- ...configPath ? {
2390
- configPath
2391
- } : {},
2392
- resultDir,
2393
- runDir,
2394
- summaryPath,
2395
- reportDir,
2396
- definition,
2397
- projects,
2398
- preflightScope: hasFormatMismatch ? 'run' : 'project',
2399
- reportEnabled: true,
2400
- publications: [],
2401
- onProgress: options.onProgress ?? (()=>{}),
2402
- onEvent: options.onEvent
2403
- };
2404
2433
  }
2405
2434
  const result_markdown_text = (value)=>value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll('|', '&#124;').replaceAll('[', '&#91;').replaceAll(']', '&#93;').replaceAll('*', '&#42;').replaceAll('_', '&#95;').replaceAll('`', '&#96;').replaceAll('\\', '&#92;').replace(/[\r\n]+/g, ' ');
2406
2435
  const result_markdown_duration = (ms)=>{
@@ -3118,7 +3147,7 @@ const latestById = (items, id)=>[
3118
3147
  const notRunSuite = (prepared, reason)=>prepared.documents.flatMap((document)=>document.cases.map((item)=>asNotRun(document.documentId, item, prepared.project.name, reason)));
3119
3148
  async function runPreparedTestProject(plan) {
3120
3149
  const reports = new ReportSession((0, external_node_path_.join)(plan.runDir, 'records'));
3121
- return reports.run(()=>runWithReportSession(plan, reports));
3150
+ return runWithMidsceneRunDir(plan.artifactDir, ()=>reports.run(()=>runWithReportSession(plan, reports)));
3122
3151
  }
3123
3152
  async function runWithReportSession(plan, reports) {
3124
3153
  const { startedAt, runId, projectRoot, configPath, resultDir, runDir, summaryPath, reportDir, definition, projects: preparedProjects } = plan;