@midscene/test 1.13.2-beta-20260923035443.0 → 1.13.2

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.
@@ -16,7 +16,9 @@ var __webpack_modules__ = {
16
16
  module.exports = require("yargs/yargs");
17
17
  },
18
18
  "./package.json" (module) {
19
- module.exports = JSON.parse('{"rE":"1.13.2-beta-20260923035443.0"}');
19
+ module.exports = {
20
+ rE: "1.13.2"
21
+ };
20
22
  }
21
23
  };
22
24
  var __webpack_module_cache__ = {};
@@ -81,7 +83,7 @@ var __webpack_exports__ = {};
81
83
  var package_0 = __webpack_require__("./package.json");
82
84
  const v4_namespaceObject = require("zod/v4");
83
85
  const GENERATED_COMMENT = '<!-- Generated by `midscene-test nodes`. Do not edit directly. -->';
84
- const sortNodesForReference = (nodes)=>{
86
+ const sortNodesForSpec = (nodes)=>{
85
87
  const priority = (name)=>'aiAct' === name ? 0 : 'aiAssert' === name ? 1 : 2;
86
88
  return [
87
89
  ...nodes
@@ -101,7 +103,7 @@ var __webpack_exports__ = {};
101
103
  const renderWorkflowLocations = (location)=>{
102
104
  const sections = [
103
105
  '## Where to use these Nodes',
104
- 'Use these Nodes in Workflow Documents (`.yaml` or `.yml` files) selected by an Execution Project. Case file patterns and the config file path below are relative to this reference file. Case file patterns use glob syntax. A custom `--config` path does not change where case files are selected.',
106
+ 'Use these Nodes in Workflow Documents (`.yaml` or `.yml` files) selected by an Execution Project. Case file patterns and the config file path below are relative to this spec file. Case file patterns use glob syntax. A custom `--config` path does not change where case files are selected.',
105
107
  'Projects created by `midscene-test create` select `cases/**/*.{yaml,yml}` by default, so you can write test cases in `cases/example.yaml` or subdirectories of `cases/`. If an Execution Project has no `files` configuration, Midscene Test searches `**/*.{yaml,yml}` recursively instead. Check `projects[].files` in your configuration before choosing a file location.'
106
108
  ];
107
109
  if (location) {
@@ -191,13 +193,14 @@ Each Node's returned \`data\` is saved on that Step's result. Results are not na
191
193
  }
192
194
  return sections.join('\n\n');
193
195
  };
194
- const renderNodeReference = (nodes, location)=>{
196
+ const renderNodeSpec = (nodes, location)=>{
195
197
  const warnings = [];
196
- const sortedNodes = sortNodesForReference(nodes);
198
+ const sortedNodes = sortNodesForSpec(nodes);
197
199
  const sections = [
198
200
  GENERATED_COMMENT,
199
- '# Midscene Test Node Reference',
200
- 'This document describes the nodes registered by the current Test Project.',
201
+ '# Midscene Test Node Spec',
202
+ 'This document describes the Nodes available in YAML test files (`.yaml` or `.yml`) for the Midscene Test framework (`@midscene/test`). It lists the Nodes registered by the current Test Project, their inputs, and how to call them in test steps and lifecycle hooks.',
203
+ "Learn about the framework and YAML test authoring:\n\n- [Midscene Test overview](https://midscenejs.com/midscene-test/overview): framework concepts and the role of Nodes.\n- [Create and use test projects](https://midscenejs.com/midscene-test/use): write YAML cases, run tests, and inspect results.\n- [Configure test projects](https://midscenejs.com/midscene-test/configuration): register Nodes, select case files, and manage runtime resources.",
201
204
  renderNodeOverview(sortedNodes),
202
205
  renderWorkflowLocations(location),
203
206
  WORKFLOW_STEP_CONTRACT
@@ -1214,32 +1217,13 @@ Each Node's returned \`data\` is saved on that Step's result. Results are not na
1214
1217
  notRunReason: reason
1215
1218
  });
1216
1219
  const summarize = (projects)=>{
1217
- const healthCases = projects.flatMap((project)=>{
1218
- const documentAttemptByRunId = new Map(project.documents.map((document)=>[
1219
- document.documentRunId,
1220
- document.attemptIndex ?? 0
1221
- ]));
1222
- return latestById(project.cases, (item)=>item.caseId).map((item)=>({
1223
- status: item.status,
1224
- ...item.run ? {
1225
- run: item.run
1226
- } : {},
1227
- ...item.attempts ? {
1228
- attempts: item.attempts
1229
- } : {},
1230
- retryCount: item.documentRunId ? documentAttemptByRunId.get(item.documentRunId) ?? 0 : 0
1231
- }));
1232
- });
1220
+ const cases = projects.flatMap((project)=>latestById(project.cases, (item)=>item.caseId));
1233
1221
  const documents = projects.flatMap((project)=>latestById(project.documents, (item)=>item.documentId));
1234
- const health = (0, report_namespaceObject.calculateTestRunHealth)(healthCases);
1235
1222
  return {
1236
- total: health.total,
1237
- passed: health.passed,
1238
- failed: health.failed,
1239
- notRun: health.notRun,
1240
- passedAfterRetry: health.passedAfterRetry,
1241
- finalPassRate: health.finalPassRate,
1242
- firstPassRate: health.firstPassRate,
1223
+ total: cases.length,
1224
+ passed: cases.filter((item)=>'success' === item.status).length,
1225
+ failed: cases.filter((item)=>'failed' === item.status).length,
1226
+ notRun: cases.filter((item)=>'not-run' === item.status).length,
1243
1227
  filtered: projects.reduce((total, project)=>total + project.filteredCaseCount, 0),
1244
1228
  collectionErrors: projects.reduce((total, project)=>total + project.collectionErrors.length, 0),
1245
1229
  documentFailures: documents.filter((document)=>'failed' === document.status).length,
@@ -1599,24 +1583,44 @@ Legacy tasks/flow YAML and its CLI options belong to the midscene command.
1599
1583
  const projectName = options.projectNames?.[0];
1600
1584
  const selectedProjects = projectName ? project.projects.filter((candidate)=>candidate.name === projectName) : project.projects;
1601
1585
  if (0 === selectedProjects.length) throw new Error(`Unknown Midscene project: ${projectName}`);
1602
- const registry = selectedProjects[0].nodes;
1603
- if (selectedProjects.some((candidate)=>candidate.nodes.names().length !== registry.names().length || candidate.nodes.definitions().some((node)=>registry.get(node.name) !== node))) throw new Error('Projects have different Nodes. Use nodes --project <name> to select one.');
1604
- const nodes = sortNodesForReference(registry.definitions());
1605
- const document = renderNodeReference(nodes, {
1606
- configPath: configPath ? (0, external_node_path_.relative)(configSearchRoot, configPath).split(external_node_path_.sep).join('/') : void 0,
1607
- projects: selectedProjects.map((executionProject)=>({
1608
- name: executionProject.name,
1609
- files: executionProject.files ?? DEFAULT_TEST_FILE_SELECTION
1610
- }))
1586
+ const filenames = new Map();
1587
+ const owners = new Map();
1588
+ for (const executionProject of project.projects){
1589
+ const safeName = executionProject.name.normalize('NFC').replace(/[<>:"/\\|?*\u0000-\u001f]/g, '-').replace(/[. ]+$/g, '-');
1590
+ const filename = project.hasExplicitProjects ? `midscene-node-spec.${safeName}.md` : 'midscene-node-spec.md';
1591
+ const key = filename.toLowerCase();
1592
+ const owner = owners.get(key);
1593
+ if (void 0 !== owner) throw new Error(`Projects "${owner}" and "${executionProject.name}" generate the same Node Spec filename: ${filename}`);
1594
+ owners.set(key, executionProject.name);
1595
+ filenames.set(executionProject.name, filename);
1596
+ }
1597
+ const specs = selectedProjects.map((executionProject)=>{
1598
+ const nodes = sortNodesForSpec(executionProject.nodes.definitions());
1599
+ const document = renderNodeSpec(nodes, {
1600
+ configPath: configPath ? (0, external_node_path_.relative)(configSearchRoot, configPath).split(external_node_path_.sep).join('/') : void 0,
1601
+ projects: [
1602
+ {
1603
+ name: executionProject.name,
1604
+ files: executionProject.files ?? DEFAULT_TEST_FILE_SELECTION
1605
+ }
1606
+ ]
1607
+ });
1608
+ return {
1609
+ executionProject,
1610
+ nodes,
1611
+ document
1612
+ };
1611
1613
  });
1612
- for (const warning of document.warnings)io.error(`midscene-test nodes: ${warning}`);
1613
- const referencePath = (0, external_node_path_.resolve)(configSearchRoot, 'midscene-node-reference.md');
1614
- (0, external_node_fs_.writeFileSync)(referencePath, document.markdown);
1615
- if (projectName) io.log(`Execution Project: ${projectName}`);
1616
- io.log(`Registered Nodes (${nodes.length}):`);
1617
- if (0 === nodes.length) io.log('No nodes are registered by the current Test Project.');
1618
- for (const node of nodes)io.log(`- ${node.name}: ${node.description?.trim() || "Description not declared."}`);
1619
- io.log(`\nNode reference generated: ${referencePath}`);
1614
+ for (const { executionProject, nodes, document } of specs){
1615
+ for (const warning of document.warnings)io.error(`midscene-test nodes: ${warning}`);
1616
+ const specPath = (0, external_node_path_.resolve)(configSearchRoot, filenames.get(executionProject.name));
1617
+ (0, external_node_fs_.writeFileSync)(specPath, document.markdown);
1618
+ if (project.hasExplicitProjects || projectName) io.log(`Execution Project: ${executionProject.name}`);
1619
+ io.log(`Registered Nodes (${nodes.length}):`);
1620
+ if (0 === nodes.length) io.log('No nodes are registered by the current Test Project.');
1621
+ for (const node of nodes)io.log(`- ${node.name}: ${node.description?.trim() || "Description not declared."}`);
1622
+ io.log(`\nNode Spec generated: ${specPath}`);
1623
+ }
1620
1624
  };
1621
1625
  async function runTestCli(args, io = defaultCliIO) {
1622
1626
  try {