@midscene/test 1.12.4-beta-20260903111111.0 → 1.12.4
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/android/index.mjs +50 -106
- package/dist/es/android/index.mjs.map +1 -1
- package/dist/es/cli/index.mjs +99 -149
- package/dist/es/cli/index.mjs.map +1 -1
- package/dist/es/harmony/index.mjs +119 -0
- package/dist/es/harmony/index.mjs.map +1 -0
- package/dist/es/index.mjs +36 -87
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/ios/index.mjs +51 -101
- package/dist/es/ios/index.mjs.map +1 -1
- package/dist/es/midscene/index.mjs +37 -235
- package/dist/es/midscene/index.mjs.map +1 -1
- package/dist/es/playwright/index.mjs +14 -10
- package/dist/es/playwright/index.mjs.map +1 -1
- package/dist/es/test-cli.mjs +102 -150
- package/dist/es/test-cli.mjs.map +1 -1
- package/dist/lib/android/index.js +151 -178
- package/dist/lib/android/index.js.map +1 -1
- package/dist/lib/cli/index.js +99 -149
- package/dist/lib/cli/index.js.map +1 -1
- package/dist/lib/harmony/index.js +188 -0
- package/dist/lib/harmony/index.js.map +1 -0
- package/dist/lib/index.js +37 -100
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/ios/index.js +152 -173
- package/dist/lib/ios/index.js.map +1 -1
- package/dist/lib/midscene/index.js +264 -412
- package/dist/lib/midscene/index.js.map +1 -1
- package/dist/lib/playwright/index.js +14 -10
- package/dist/lib/playwright/index.js.map +1 -1
- package/dist/lib/test-cli.js +102 -150
- package/dist/lib/test-cli.js.map +1 -1
- package/dist/types/android/index.d.ts +27 -101
- package/dist/types/cli/index.d.ts +9 -32
- package/dist/types/harmony/index.d.ts +124 -0
- package/dist/types/index.d.ts +18 -45
- package/dist/types/ios/index.d.ts +28 -107
- package/dist/types/midscene/index.d.ts +54 -153
- package/dist/types/playwright/index.d.ts +9 -63
- package/package.json +25 -6
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_modules__ = {
|
|
3
|
+
"./src/errors.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
5
|
+
ww: ()=>NodeDefinitionError
|
|
6
|
+
});
|
|
7
|
+
function _define_property(obj, key, value) {
|
|
8
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
9
|
+
value: value,
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true
|
|
13
|
+
});
|
|
14
|
+
else obj[key] = value;
|
|
15
|
+
return obj;
|
|
16
|
+
}
|
|
17
|
+
class WorkflowError extends Error {
|
|
18
|
+
toJSON() {
|
|
19
|
+
return {
|
|
20
|
+
name: this.name,
|
|
21
|
+
message: this.message,
|
|
22
|
+
code: this.code,
|
|
23
|
+
...void 0 === this.details ? {} : {
|
|
24
|
+
details: this.details
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
constructor(message, options = {}){
|
|
29
|
+
super(message, {
|
|
30
|
+
cause: options.cause
|
|
31
|
+
}), _define_property(this, "code", void 0), _define_property(this, "details", void 0);
|
|
32
|
+
this.name = new.target.name;
|
|
33
|
+
this.code = options.code ?? 'WORKFLOW_ERROR';
|
|
34
|
+
this.details = options.details;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class NodeDefinitionError extends WorkflowError {
|
|
38
|
+
constructor(message, details){
|
|
39
|
+
super(message, {
|
|
40
|
+
code: 'NODE_DEFINITION_ERROR',
|
|
41
|
+
details
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"./src/midscene/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
47
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
48
|
+
createAgentTestRunnerNodes: ()=>createAgentTestRunnerNodes
|
|
49
|
+
});
|
|
50
|
+
require("@midscene/core/agent/test-runner");
|
|
51
|
+
const v4_namespaceObject = require("zod/v4");
|
|
52
|
+
var errors = __webpack_require__("./src/errors.ts");
|
|
53
|
+
const validateOptionalText = (value, field, node)=>{
|
|
54
|
+
if (void 0 !== value && ('string' != typeof value || 0 === value.trim().length)) throw new errors.ww(`Node "${node}" ${field} must be a non-empty string.`, {
|
|
55
|
+
node,
|
|
56
|
+
field
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const validateInputSchema = (schema, node)=>{
|
|
60
|
+
if (void 0 === schema) return;
|
|
61
|
+
if (!(schema instanceof v4_namespaceObject.z.ZodObject)) throw new errors.ww(`Node "${node}" inputSchema must be a Zod object schema.`, {
|
|
62
|
+
node,
|
|
63
|
+
field: 'inputSchema'
|
|
64
|
+
});
|
|
65
|
+
if ('$' in schema.shape) throw new errors.ww(`Node "${node}" inputSchema must not declare "$" as an input property.`, {
|
|
66
|
+
node,
|
|
67
|
+
field: 'inputSchema.$'
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
const validateDefinition = (options)=>{
|
|
71
|
+
if (!options || 'object' != typeof options) throw new errors.ww('Node definition must be an object.');
|
|
72
|
+
if ('string' != typeof options.name || 0 === options.name.trim().length) throw new errors.ww('Node name must be a non-empty string.');
|
|
73
|
+
validateOptionalText(options.title, 'title', options.name);
|
|
74
|
+
validateOptionalText(options.description, "description", options.name);
|
|
75
|
+
if (void 0 !== options.stringInputKey && false !== options.stringInputKey && ('string' != typeof options.stringInputKey || 0 === options.stringInputKey.trim().length)) throw new errors.ww(`Node "${options.name}" stringInputKey must be a non-empty string or false.`, {
|
|
76
|
+
node: options.name,
|
|
77
|
+
field: 'stringInputKey'
|
|
78
|
+
});
|
|
79
|
+
validateInputSchema(options.inputSchema, options.name);
|
|
80
|
+
if ('string' == typeof options.stringInputKey && options.inputSchema instanceof v4_namespaceObject.z.ZodObject && !(options.stringInputKey in options.inputSchema.shape)) throw new errors.ww(`Node "${options.name}" stringInputKey must reference a field in inputSchema.`, {
|
|
81
|
+
node: options.name,
|
|
82
|
+
field: 'stringInputKey'
|
|
83
|
+
});
|
|
84
|
+
if ('function' != typeof options.execute) throw new errors.ww(`Node "${options.name}" must provide an execute function.`, {
|
|
85
|
+
node: options.name
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
function define_node_defineNode(options) {
|
|
89
|
+
validateDefinition(options);
|
|
90
|
+
return options;
|
|
91
|
+
}
|
|
92
|
+
const nonBlankPrompt = (description)=>v4_namespaceObject.z.string().regex(/\S/, 'prompt must contain a non-whitespace character').describe(description);
|
|
93
|
+
v4_namespaceObject.z.strictObject({
|
|
94
|
+
duration: v4_namespaceObject.z.number().positive().describe('How long to wait.'),
|
|
95
|
+
unit: v4_namespaceObject.z["enum"]([
|
|
96
|
+
'ms',
|
|
97
|
+
's',
|
|
98
|
+
'min'
|
|
99
|
+
]).default('ms').describe('Duration unit: milliseconds, seconds, or minutes.')
|
|
100
|
+
});
|
|
101
|
+
v4_namespaceObject.z.strictObject({
|
|
102
|
+
prompt: nonBlankPrompt('A self-contained task, including allowed tools and success conditions.')
|
|
103
|
+
});
|
|
104
|
+
const createAgentTestRunnerNodes = (definitions, getAgent)=>definitions.map((definition)=>define_node_defineNode({
|
|
105
|
+
name: definition.name,
|
|
106
|
+
...void 0 === definition.title ? {} : {
|
|
107
|
+
title: definition.title
|
|
108
|
+
},
|
|
109
|
+
...void 0 === definition.description ? {} : {
|
|
110
|
+
description: definition.description
|
|
111
|
+
},
|
|
112
|
+
...void 0 === definition.stringInputKey ? {} : {
|
|
113
|
+
stringInputKey: definition.stringInputKey
|
|
114
|
+
},
|
|
115
|
+
inputSchema: definition.inputSchema,
|
|
116
|
+
async execute (ctx) {
|
|
117
|
+
const agent = await getAgent(ctx);
|
|
118
|
+
return definition.execute(agent, ctx.input, {
|
|
119
|
+
signal: ctx.signal
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var __webpack_module_cache__ = {};
|
|
126
|
+
function __webpack_require__(moduleId) {
|
|
127
|
+
var cachedModule = __webpack_module_cache__[moduleId];
|
|
128
|
+
if (void 0 !== cachedModule) return cachedModule.exports;
|
|
129
|
+
var module = __webpack_module_cache__[moduleId] = {
|
|
130
|
+
exports: {}
|
|
131
|
+
};
|
|
132
|
+
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
133
|
+
return module.exports;
|
|
134
|
+
}
|
|
135
|
+
(()=>{
|
|
136
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
137
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
138
|
+
enumerable: true,
|
|
139
|
+
get: definition[key]
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
})();
|
|
143
|
+
(()=>{
|
|
144
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
145
|
+
})();
|
|
146
|
+
(()=>{
|
|
147
|
+
__webpack_require__.r = (exports1)=>{
|
|
148
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
149
|
+
value: 'Module'
|
|
150
|
+
});
|
|
151
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
152
|
+
value: true
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
})();
|
|
156
|
+
var __webpack_exports__ = {};
|
|
157
|
+
(()=>{
|
|
158
|
+
__webpack_require__.r(__webpack_exports__);
|
|
159
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
160
|
+
runHdcShellInputSchema: ()=>test_runner_namespaceObject.runHdcShellInputSchema,
|
|
161
|
+
createHarmonyNodes: ()=>createHarmonyNodes,
|
|
162
|
+
terminateInputSchema: ()=>test_runner_namespaceObject.terminateInputSchema,
|
|
163
|
+
launchInputSchema: ()=>test_runner_namespaceObject.launchInputSchema
|
|
164
|
+
});
|
|
165
|
+
const test_runner_namespaceObject = require("@midscene/harmony/test-runner");
|
|
166
|
+
var errors = __webpack_require__("./src/errors.ts");
|
|
167
|
+
var midscene = __webpack_require__("./src/midscene/index.ts");
|
|
168
|
+
function createHarmonyNodes(options) {
|
|
169
|
+
if (!options || 'object' != typeof options) throw new errors.ww('createHarmonyNodes() options must be an object.');
|
|
170
|
+
if ('function' != typeof options.getAgent) throw new errors.ww('createHarmonyNodes() requires getAgent().');
|
|
171
|
+
return (0, midscene.createAgentTestRunnerNodes)(test_runner_namespaceObject.harmonyAgentTestRunnerNodeDefinitions, options.getAgent);
|
|
172
|
+
}
|
|
173
|
+
})();
|
|
174
|
+
exports.createHarmonyNodes = __webpack_exports__.createHarmonyNodes;
|
|
175
|
+
exports.launchInputSchema = __webpack_exports__.launchInputSchema;
|
|
176
|
+
exports.runHdcShellInputSchema = __webpack_exports__.runHdcShellInputSchema;
|
|
177
|
+
exports.terminateInputSchema = __webpack_exports__.terminateInputSchema;
|
|
178
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
179
|
+
"createHarmonyNodes",
|
|
180
|
+
"launchInputSchema",
|
|
181
|
+
"runHdcShellInputSchema",
|
|
182
|
+
"terminateInputSchema"
|
|
183
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
184
|
+
Object.defineProperty(exports, '__esModule', {
|
|
185
|
+
value: true
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harmony/index.js","sources":["../../../src/errors.ts","../../../src/node/define-node.ts","../../../src/midscene/index.ts","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/harmony/index.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\nexport interface WorkflowErrorOptions {\n code?: string;\n details?: unknown;\n cause?: unknown;\n}\n\nexport class WorkflowError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, options: WorkflowErrorOptions = {}) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code ?? 'WORKFLOW_ERROR';\n this.details = options.details;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n ...(this.details === undefined ? {} : { details: this.details }),\n };\n }\n}\n\nexport class WorkflowParseError extends WorkflowError {\n constructor(message: string, details?: unknown, cause?: unknown) {\n super(message, { code: 'WORKFLOW_PARSE_ERROR', details, cause });\n }\n}\n\nexport class NodeDefinitionError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_DEFINITION_ERROR', details });\n }\n}\n\nexport class DuplicateNodeError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is already registered.`, {\n code: 'DUPLICATE_NODE',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeNotFoundError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is not registered.`, {\n code: 'NODE_NOT_FOUND',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeInputValidationError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_INPUT_VALIDATION_ERROR', details });\n }\n\n static fromZod(node: string, error: z.ZodError): NodeInputValidationError {\n const issues = error.issues.map((issue) => ({\n code: issue.code,\n path: issue.path.map(String).join('.'),\n message: issue.message,\n }));\n const firstIssue = issues[0];\n const path = firstIssue?.path || '<root>';\n const message = firstIssue?.message ?? 'invalid input';\n return new NodeInputValidationError(\n `Node \"${node}\" input validation failed at \"${path}\": ${message}`,\n { node, issues },\n );\n }\n}\n\nexport class StepTimeoutError extends WorkflowError {\n readonly timeoutMs: number;\n readonly node?: string;\n\n constructor(timeoutMs: number, node?: string) {\n super(\n node\n ? `Node \"${node}\" timed out after ${timeoutMs}ms.`\n : `Step timed out after ${timeoutMs}ms.`,\n {\n code: 'STEP_TIMEOUT',\n details: { timeoutMs, ...(node === undefined ? {} : { node }) },\n },\n );\n this.timeoutMs = timeoutMs;\n this.node = node;\n }\n}\n\nexport class NodeExecutionError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string, cause: unknown) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Node \"${node}\" failed: ${causeMessage}`, {\n code: 'NODE_EXECUTION_ERROR',\n details: { node },\n cause,\n });\n this.node = node;\n }\n}\n\nexport class WorkflowLifecycleError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'WORKFLOW_LIFECYCLE_ERROR', details });\n }\n}\n\nexport class ProjectSetupError extends WorkflowError {\n constructor(cause: unknown, details: { projectName: string }) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" setup failed: ${causeMessage}`, {\n code: 'PROJECT_SETUP_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class ProjectTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: { projectName: string; registrationIndex: number },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" teardown failed: ${causeMessage}`, {\n code: 'PROJECT_TEARDOWN_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class NodeScopeTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: {\n scope: 'case' | 'document';\n scopeId: string;\n node: string;\n registrationIndex: number;\n },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(\n `${details.scope === 'case' ? 'Case attempt' : 'Workflow document'} node teardown failed for \"${details.node}\": ${causeMessage}`,\n { code: 'NODE_SCOPE_TEARDOWN_ERROR', details, cause },\n );\n }\n}\n\nexport class FatalDeviceError extends WorkflowError {\n constructor(message: string, cause?: unknown) {\n super(message, { code: 'FATAL_DEVICE_ERROR', cause });\n }\n}\n\nexport const isFatalDeviceError = (error: unknown): boolean => {\n if (error instanceof FatalDeviceError) return true;\n if (error instanceof WorkflowError && error.code === 'FATAL_DEVICE_ERROR') {\n return true;\n }\n if (\n error instanceof Error &&\n /device offline|device not found|(?:adb|bdc|device) connection (?:was )?closed/i.test(\n error.message,\n )\n ) {\n return true;\n }\n return error instanceof Error && error.cause !== undefined\n ? isFatalDeviceError(error.cause)\n : false;\n};\n\nexport class CaseExecutionError extends WorkflowError {\n readonly result: import('./engine/types').CaseRunResult;\n\n constructor(result: import('./engine/types').CaseRunResult) {\n super(`Case \"${result.name}\" failed.`, {\n code: 'CASE_EXECUTION_FAILED',\n details: { caseId: result.caseId, runId: result.runId },\n });\n this.result = result;\n }\n}\n\nexport class WorkflowDocumentExecutionError extends WorkflowError {\n readonly result: import('./engine/types').WorkflowDocumentRunResult;\n\n constructor(result: import('./engine/types').WorkflowDocumentRunResult) {\n super(`Workflow document \"${result.sourcePath}\" failed.`, {\n code: 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n details: {\n documentId: result.documentId,\n documentRunId: result.documentRunId,\n },\n });\n this.result = result;\n }\n}\n\nexport function normalizeNodeExecutionError(\n error: unknown,\n node: string,\n): WorkflowError {\n return error instanceof WorkflowError\n ? error\n : new NodeExecutionError(node, error);\n}\n","import { z } from 'zod/v4';\nimport { NodeDefinitionError } from '../errors';\nimport type {\n DefineNodeOptions,\n DefineNodeWithSchemaOptions,\n NodeDefinition,\n NodeDefinitionWithSchema,\n NodeInputSchema,\n} from './types';\n\nconst validateOptionalText = (\n value: unknown,\n field: 'title' | 'description',\n node: string,\n): void => {\n if (\n value !== undefined &&\n (typeof value !== 'string' || value.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${node}\" ${field} must be a non-empty string.`,\n { node, field },\n );\n }\n};\n\nconst validateInputSchema = (schema: unknown, node: string): void => {\n if (schema === undefined) return;\n if (!(schema instanceof z.ZodObject)) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must be a Zod object schema.`,\n { node, field: 'inputSchema' },\n );\n }\n if ('$' in schema.shape) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must not declare \"$\" as an input property.`,\n { node, field: 'inputSchema.$' },\n );\n }\n};\n\nconst validateDefinition = (options: {\n name: string;\n title?: unknown;\n description?: unknown;\n stringInputKey?: unknown;\n inputSchema?: unknown;\n execute: unknown;\n}): void => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError('Node definition must be an object.');\n }\n\n if (typeof options.name !== 'string' || options.name.trim().length === 0) {\n throw new NodeDefinitionError('Node name must be a non-empty string.');\n }\n\n validateOptionalText(options.title, 'title', options.name);\n validateOptionalText(options.description, 'description', options.name);\n if (\n options.stringInputKey !== undefined &&\n options.stringInputKey !== false &&\n (typeof options.stringInputKey !== 'string' ||\n options.stringInputKey.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must be a non-empty string or false.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n validateInputSchema(options.inputSchema, options.name);\n\n if (\n typeof options.stringInputKey === 'string' &&\n options.inputSchema instanceof z.ZodObject &&\n !(options.stringInputKey in options.inputSchema.shape)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must reference a field in inputSchema.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n\n if (typeof options.execute !== 'function') {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" must provide an execute function.`,\n { node: options.name },\n );\n }\n};\n\nexport function defineNode<\n TSchema extends NodeInputSchema,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeWithSchemaOptions<TSchema, TData, TContext>,\n): NodeDefinitionWithSchema<TSchema, TData, TContext>;\n\nexport function defineNode<\n TInput = unknown,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeOptions<TInput, TData, TContext>,\n): NodeDefinition<TInput, TData, TContext>;\n\nexport function defineNode(\n options: DefineNodeOptions<any, any, any>,\n): NodeDefinition<any, any, any> {\n validateDefinition(options);\n return options;\n}\n","import {\n type AgentTestRunnerNodeDefinition,\n type AgentTestRunnerNodeProvider,\n type CommonAgentTestRunnerApi,\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n} from '@midscene/core/agent/test-runner';\nimport { z } from 'zod/v4';\nimport type { Awaitable } from '../engine/types';\nimport { NodeDefinitionError, NodeExecutionError } from '../errors';\nimport { defineNode } from '../node/define-node';\nimport type {\n NodeDefinition,\n NodeExecutionContext,\n NodeResult,\n} from '../node/types';\n\nexport type MidsceneUIAgent = CommonAgentTestRunnerApi;\n\nexport {\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n};\n\nexport interface AgentProvider<TContext> {\n getAgent(\n runId: string,\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n // biome-ignore lint/suspicious/noConfusingVoidType: providers without a report intentionally return void.\n releaseAgent?(runId: string): Awaitable<AgentReleaseResult | void>;\n dispose?(): Awaitable<void>;\n}\n\nexport interface AgentReleaseResult {\n /** Absolute path to the finalized report for this Agent scope. */\n reportPath?: string;\n}\n\nexport interface AgentExecutorInput<TContext> {\n prompt: string;\n context: TContext;\n signal: AbortSignal;\n execution:\n | { scope: 'case'; runId: string }\n | { scope: 'document'; runId: string };\n}\n\nexport interface AgentExecutor<TContext> {\n // biome-ignore lint/suspicious/noConfusingVoidType: executors may perform side effects without returning a summary.\n execute(input: AgentExecutorInput<TContext>): Awaitable<NodeResult | void>;\n}\n\nconst nonBlankPrompt = (description: string) =>\n z\n .string()\n .regex(/\\S/, 'prompt must contain a non-whitespace character')\n .describe(description);\n\nexport const waitInputSchema = z.strictObject({\n duration: z.number().positive().describe('How long to wait.'),\n unit: z\n .enum(['ms', 's', 'min'])\n .default('ms')\n .describe('Duration unit: milliseconds, seconds, or minutes.'),\n});\n\nexport const agentInputSchema = z.strictObject({\n prompt: nonBlankPrompt(\n 'A self-contained task, including allowed tools and success conditions.',\n ),\n});\n\nexport type AiActNodeInput = z.infer<typeof aiActInputSchema>;\nexport type AiAssertNodeInput = z.infer<typeof aiAssertInputSchema>;\nexport type AiTapNodeInput = z.infer<typeof aiTapInputSchema>;\nexport type InsightNodeInput = z.infer<typeof insightInputSchema>;\nexport type RecordToReportNodeInput = z.infer<typeof recordToReportInputSchema>;\nexport type WaitNodeInput = z.infer<typeof waitInputSchema>;\nexport type AgentNodeInput = z.infer<typeof agentInputSchema>;\n\nexport interface CreateMidsceneNodesOptions<TContext> {\n getAgent?(\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n agentProvider?: AgentProvider<TContext>;\n /** Agent class that declares the Agent-backed Nodes to register. */\n agentClass: AgentTestRunnerNodeProvider;\n agentExecutor?: AgentExecutor<TContext>;\n}\n\nconst waitFor = async (durationMs: number, signal: AbortSignal) => {\n if (signal.aborted) {\n throw signal.reason ?? new Error('Wait aborted.');\n }\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n signal.removeEventListener('abort', abort);\n resolve();\n }, durationMs);\n const abort = () => {\n clearTimeout(timeout);\n reject(signal.reason ?? new Error('Wait aborted.'));\n };\n signal.addEventListener('abort', abort, { once: true });\n });\n};\n\n/** Adapt Agent-owned descriptions to executable Test Runner Nodes. */\nexport const createAgentTestRunnerNodes = <TContext>(\n definitions: readonly AgentTestRunnerNodeDefinition[],\n getAgent: (\n ctx: NodeExecutionContext<unknown, TContext>,\n ) => Awaitable<unknown>,\n): readonly NodeDefinition<any, any, TContext>[] =>\n definitions.map((definition) =>\n defineNode({\n name: definition.name,\n ...(definition.title === undefined ? {} : { title: definition.title }),\n ...(definition.description === undefined\n ? {}\n : { description: definition.description }),\n ...(definition.stringInputKey === undefined\n ? {}\n : { stringInputKey: definition.stringInputKey }),\n inputSchema: definition.inputSchema,\n async execute(ctx) {\n const agent = await getAgent(ctx);\n return definition.execute(agent, ctx.input, {\n signal: ctx.signal,\n });\n },\n }),\n );\n\nexport function createMidsceneNodes<TContext>(\n options: CreateMidsceneNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() options must be an object.',\n );\n }\n if (\n typeof options.agentProvider?.getAgent !== 'function' &&\n typeof options.getAgent !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires getAgent or agentProvider.getAgent.',\n );\n }\n if (\n !options.agentClass ||\n typeof options.agentClass.getTestRunnerNodeDefinitions !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires agentClass.getTestRunnerNodeDefinitions().',\n );\n }\n\n const registeredAgentScopes = new Set<string>();\n const getExecutionId = (ctx: NodeExecutionContext<unknown, TContext>) =>\n ctx.scope === 'case' ? ctx.case.runId : ctx.document.documentRunId;\n const getAgent = async (\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Promise<MidsceneUIAgent> => {\n if (!options.agentProvider) return options.getAgent!(ctx);\n const runId = getExecutionId(ctx);\n if (\n options.agentProvider.releaseAgent &&\n !registeredAgentScopes.has(runId)\n ) {\n registeredAgentScopes.add(runId);\n ctx.onTeardown(async () => {\n try {\n const released = await options.agentProvider!.releaseAgent!(runId);\n return released?.reportPath\n ? { reportPaths: [released.reportPath] }\n : undefined;\n } finally {\n registeredAgentScopes.delete(runId);\n }\n });\n }\n return options.agentProvider.getAgent(runId, ctx);\n };\n\n const agentDefinitions = options.agentClass.getTestRunnerNodeDefinitions();\n\n return [\n ...createAgentTestRunnerNodes(agentDefinitions, getAgent),\n defineNode<typeof waitInputSchema, unknown, TContext>({\n name: 'wait',\n description: 'Wait for a fixed duration while honoring cancellation.',\n stringInputKey: false,\n inputSchema: waitInputSchema,\n async execute(ctx) {\n const multiplier =\n ctx.input.unit === 'min'\n ? 60_000\n : ctx.input.unit === 's'\n ? 1_000\n : 1;\n const durationMs = ctx.input.duration * multiplier;\n await waitFor(durationMs, ctx.signal);\n return { summary: `Waited ${durationMs}ms` };\n },\n }),\n defineNode<typeof agentInputSchema, unknown, TContext>({\n name: 'agent',\n description:\n 'Execute one self-contained natural-language task with an injected Agent executor.',\n stringInputKey: 'prompt',\n inputSchema: agentInputSchema,\n async execute(ctx) {\n if (!options.agentExecutor) {\n throw new NodeExecutionError(\n 'agent',\n new TypeError('createMidsceneNodes() requires an agentExecutor.'),\n );\n }\n const execution =\n ctx.scope === 'case'\n ? { scope: 'case' as const, runId: ctx.case.runId }\n : {\n scope: 'document' as const,\n runId: ctx.document.documentRunId,\n };\n const result = await options.agentExecutor.execute({\n prompt: ctx.input.prompt,\n context: ctx.context,\n signal: ctx.signal,\n execution,\n });\n return result ?? { summary: 'Agent task completed.' };\n },\n }),\n ];\n}\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { HarmonyAgent } from '@midscene/harmony';\nimport {\n harmonyAgentTestRunnerNodeDefinitions,\n launchInputSchema,\n runHdcShellInputSchema,\n terminateInputSchema,\n} from '@midscene/harmony/test-runner';\nexport type {\n LaunchNodeInput,\n RunHdcShellNodeInput,\n TerminateNodeInput,\n} from '@midscene/harmony/test-runner';\nimport type { Awaitable } from '../engine/types';\nimport { NodeDefinitionError } from '../errors';\nimport { createAgentTestRunnerNodes } from '../midscene';\nimport type { NodeDefinition, NodeExecutionContext } from '../node/types';\n\nexport { launchInputSchema, runHdcShellInputSchema, terminateInputSchema };\n\nexport type HarmonyRunnerAgent = Pick<\n HarmonyAgent,\n 'launch' | 'terminate' | 'runHdcShell' | 'back' | 'home' | 'recentApps'\n>;\n\nexport interface CreateHarmonyNodesOptions<TContext> {\n getAgent(\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<HarmonyRunnerAgent>;\n}\n\nexport function createHarmonyNodes<TContext>(\n options: CreateHarmonyNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createHarmonyNodes() options must be an object.',\n );\n }\n if (typeof options.getAgent !== 'function') {\n throw new NodeDefinitionError('createHarmonyNodes() requires getAgent().');\n }\n\n return createAgentTestRunnerNodes(\n harmonyAgentTestRunnerNodeDefinitions,\n options.getAgent,\n );\n}\n"],"names":["WorkflowError","Error","undefined","message","options","NodeDefinitionError","details","validateOptionalText","value","field","node","validateInputSchema","schema","z","validateDefinition","defineNode","nonBlankPrompt","description","createAgentTestRunnerNodes","definitions","getAgent","definition","ctx","agent","__webpack_require__","key","Object","obj","prop","Symbol","createHarmonyNodes","harmonyAgentTestRunnerNodeDefinitions"],"mappings":"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"}
|
package/dist/lib/index.js
CHANGED
|
@@ -27,14 +27,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
27
27
|
NodeInputValidationError: ()=>NodeInputValidationError,
|
|
28
28
|
createCaseRunner: ()=>createCaseRunner,
|
|
29
29
|
isFatalDeviceError: ()=>isFatalDeviceError,
|
|
30
|
-
|
|
31
|
-
toHistoryEntry: ()=>toHistoryEntry,
|
|
30
|
+
collectWorkflowDocument: ()=>collectWorkflowDocument,
|
|
32
31
|
FatalDeviceError: ()=>FatalDeviceError,
|
|
33
32
|
runWorkflowDocument: ()=>runWorkflowDocument,
|
|
34
33
|
defineNode: ()=>defineNode,
|
|
35
34
|
z: ()=>v4_namespaceObject.z,
|
|
36
35
|
createProjectRuntime: ()=>createProjectRuntime,
|
|
37
|
-
createHistory: ()=>createHistory,
|
|
38
36
|
createWorkflowDocumentId: ()=>createWorkflowDocumentId,
|
|
39
37
|
NodeDefinitionError: ()=>NodeDefinitionError,
|
|
40
38
|
normalizeNodeExecutionError: ()=>normalizeNodeExecutionError,
|
|
@@ -48,8 +46,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
48
46
|
NodeRegistry: ()=>NodeRegistry,
|
|
49
47
|
CaseRunner: ()=>CaseRunner,
|
|
50
48
|
StepTimeoutError: ()=>StepTimeoutError,
|
|
51
|
-
assertJsonSerializable: ()=>assertJsonSerializable,
|
|
52
|
-
validateCommonNodeInput: ()=>validateCommonNodeInput,
|
|
53
49
|
WorkflowParseError: ()=>WorkflowParseError,
|
|
54
50
|
NodeScopeTeardownError: ()=>NodeScopeTeardownError,
|
|
55
51
|
WorkflowDocumentExecutionError: ()=>WorkflowDocumentExecutionError,
|
|
@@ -58,7 +54,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
58
54
|
resolveWorkflowVariables: ()=>resolveWorkflowVariables,
|
|
59
55
|
createCaseId: ()=>createCaseId,
|
|
60
56
|
createDocumentRuntime: ()=>createDocumentRuntime,
|
|
61
|
-
|
|
57
|
+
normalizeSteps: ()=>normalizeSteps
|
|
62
58
|
});
|
|
63
59
|
function _define_property(obj, key, value) {
|
|
64
60
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
@@ -296,13 +292,7 @@ function normalizeMeta(value, index) {
|
|
|
296
292
|
continueOnError: continueOnError ?? false
|
|
297
293
|
};
|
|
298
294
|
}
|
|
299
|
-
function
|
|
300
|
-
if (void 0 !== input.prompt && 'string' != typeof input.prompt) throw new WorkflowParseError(`${formatStep(index)} "prompt" must be a string.`, {
|
|
301
|
-
index,
|
|
302
|
-
prompt: input.prompt
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
function normalizeStep(value, index = 0) {
|
|
295
|
+
function normalizeStep(value, index = 0, resolveNode) {
|
|
306
296
|
if (!isMapping(value)) throw new WorkflowParseError(`${formatStep(index)} must be a mapping.`, {
|
|
307
297
|
index
|
|
308
298
|
});
|
|
@@ -315,30 +305,37 @@ function normalizeStep(value, index = 0) {
|
|
|
315
305
|
if (0 === node.trim().length) throw new WorkflowParseError(`${formatStep(index)} node name must not be empty.`, {
|
|
316
306
|
index
|
|
317
307
|
});
|
|
318
|
-
if ('string' == typeof rawValue)
|
|
319
|
-
node
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
308
|
+
if ('string' == typeof rawValue) {
|
|
309
|
+
const resolvedNode = resolveNode?.(node);
|
|
310
|
+
const stringInputKey = resolvedNode ? resolvedNode.stringInputKey : 'prompt';
|
|
311
|
+
if (false === stringInputKey || void 0 === stringInputKey) throw new WorkflowParseError(`${formatStep(index)} node "${node}" does not accept string shorthand.`, {
|
|
312
|
+
index,
|
|
313
|
+
node
|
|
314
|
+
});
|
|
315
|
+
return {
|
|
316
|
+
node,
|
|
317
|
+
input: {
|
|
318
|
+
[stringInputKey]: rawValue
|
|
319
|
+
},
|
|
320
|
+
meta: {
|
|
321
|
+
continueOnError: false
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
327
325
|
if (!isMapping(rawValue)) throw new WorkflowParseError(`${formatStep(index)} value must be a string shorthand or a mapping.`, {
|
|
328
326
|
index,
|
|
329
327
|
node
|
|
330
328
|
});
|
|
331
329
|
const { $: rawMeta, ...input } = rawValue;
|
|
332
|
-
validateCommonNodeInput(input, index);
|
|
333
330
|
return {
|
|
334
331
|
node,
|
|
335
332
|
input,
|
|
336
333
|
meta: normalizeMeta(rawMeta, index)
|
|
337
334
|
};
|
|
338
335
|
}
|
|
339
|
-
function normalizeSteps(steps) {
|
|
336
|
+
function normalizeSteps(steps, resolveNode) {
|
|
340
337
|
if (!Array.isArray(steps)) throw new WorkflowParseError('Steps must be an array.');
|
|
341
|
-
return steps.map((step, index)=>normalizeStep(step, index));
|
|
338
|
+
return steps.map((step, index)=>normalizeStep(step, index, resolveNode));
|
|
342
339
|
}
|
|
343
340
|
const v4_namespaceObject = require("zod/v4");
|
|
344
341
|
const validateOptionalText = (value, field, node)=>{
|
|
@@ -363,7 +360,15 @@ const validateDefinition = (options)=>{
|
|
|
363
360
|
if ('string' != typeof options.name || 0 === options.name.trim().length) throw new NodeDefinitionError('Node name must be a non-empty string.');
|
|
364
361
|
validateOptionalText(options.title, 'title', options.name);
|
|
365
362
|
validateOptionalText(options.description, "description", options.name);
|
|
363
|
+
if (void 0 !== options.stringInputKey && false !== options.stringInputKey && ('string' != typeof options.stringInputKey || 0 === options.stringInputKey.trim().length)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must be a non-empty string or false.`, {
|
|
364
|
+
node: options.name,
|
|
365
|
+
field: 'stringInputKey'
|
|
366
|
+
});
|
|
366
367
|
validateInputSchema(options.inputSchema, options.name);
|
|
368
|
+
if ('string' == typeof options.stringInputKey && options.inputSchema instanceof v4_namespaceObject.z.ZodObject && !(options.stringInputKey in options.inputSchema.shape)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must reference a field in inputSchema.`, {
|
|
369
|
+
node: options.name,
|
|
370
|
+
field: 'stringInputKey'
|
|
371
|
+
});
|
|
367
372
|
if ('function' != typeof options.execute) throw new NodeDefinitionError(`Node "${options.name}" must provide an execute function.`, {
|
|
368
373
|
node: options.name
|
|
369
374
|
});
|
|
@@ -451,45 +456,6 @@ const assertJsonSerializable = (value, label, node)=>{
|
|
|
451
456
|
throw new NodeExecutionError(node, error);
|
|
452
457
|
}
|
|
453
458
|
};
|
|
454
|
-
const cloneAndFreezeJson = (value)=>{
|
|
455
|
-
if (Array.isArray(value)) return Object.freeze(value.map(cloneAndFreezeJson));
|
|
456
|
-
if ('object' == typeof value && null !== value) return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, child])=>[
|
|
457
|
-
key,
|
|
458
|
-
cloneAndFreezeJson(child)
|
|
459
|
-
])));
|
|
460
|
-
return value;
|
|
461
|
-
};
|
|
462
|
-
const toHistoryEntry = (result, scope)=>{
|
|
463
|
-
assertJsonSerializable(result.input, 'input', result.node);
|
|
464
|
-
if (result.output?.data !== void 0) assertJsonSerializable(result.output.data, 'output.data', result.node);
|
|
465
|
-
return Object.freeze({
|
|
466
|
-
scope,
|
|
467
|
-
phase: result.phase,
|
|
468
|
-
stepIndex: result.stepIndex,
|
|
469
|
-
node: result.node,
|
|
470
|
-
input: cloneAndFreezeJson(result.input),
|
|
471
|
-
...'string' == typeof result.input?.prompt ? {
|
|
472
|
-
intent: result.input.prompt
|
|
473
|
-
} : {},
|
|
474
|
-
status: 'success' === result.status ? 'passed' : 'failed',
|
|
475
|
-
...result.output?.summary === void 0 ? {} : {
|
|
476
|
-
summary: result.output.summary
|
|
477
|
-
},
|
|
478
|
-
...result.output?.data === void 0 ? {} : {
|
|
479
|
-
data: cloneAndFreezeJson(result.output.data)
|
|
480
|
-
},
|
|
481
|
-
...result.error ? {
|
|
482
|
-
error: Object.freeze({
|
|
483
|
-
name: result.error.name,
|
|
484
|
-
message: result.error.message
|
|
485
|
-
})
|
|
486
|
-
} : {}
|
|
487
|
-
});
|
|
488
|
-
};
|
|
489
|
-
const createHistory = (prefix, results, scope)=>Object.freeze([
|
|
490
|
-
...prefix,
|
|
491
|
-
...results.map((result)=>toHistoryEntry(result, scope))
|
|
492
|
-
]);
|
|
493
459
|
function validateNodeOutput(output, node) {
|
|
494
460
|
if (void 0 === output) return;
|
|
495
461
|
if ('object' != typeof output || null === output || Array.isArray(output)) throw new NodeExecutionError(node, new TypeError('Node output must be an object or undefined.'));
|
|
@@ -511,7 +477,6 @@ function createStepResultBase(step, startedAt, phase, stepIndex) {
|
|
|
511
477
|
};
|
|
512
478
|
}
|
|
513
479
|
async function executeNode(step, execute, phase, stepIndex, options) {
|
|
514
|
-
validateCommonNodeInput(step.input, stepIndex);
|
|
515
480
|
const startedAt = new Date();
|
|
516
481
|
const abortController = new AbortController();
|
|
517
482
|
const parentSignal = options.parentSignal;
|
|
@@ -595,7 +560,6 @@ async function executeStep(step, node, target, context, execution = {}) {
|
|
|
595
560
|
$: step.meta,
|
|
596
561
|
signal,
|
|
597
562
|
context,
|
|
598
|
-
history: execution.history ?? Object.freeze([]),
|
|
599
563
|
onTeardown: (teardown)=>{
|
|
600
564
|
if (!execution.onTeardown) throw new NodeExecutionError(step.node, new Error('The current execution scope cannot register teardown.'));
|
|
601
565
|
execution.onTeardown(step.node, teardown);
|
|
@@ -644,7 +608,6 @@ async function runCollectedCase(collectedCase, options) {
|
|
|
644
608
|
const beforeEach = [];
|
|
645
609
|
const steps = [];
|
|
646
610
|
const afterEach = [];
|
|
647
|
-
const completedNodes = [];
|
|
648
611
|
const teardownStack = [];
|
|
649
612
|
let acceptingTeardowns = true;
|
|
650
613
|
const onTeardown = (node, teardown)=>{
|
|
@@ -673,13 +636,7 @@ async function runCollectedCase(collectedCase, options) {
|
|
|
673
636
|
sourcePath: collectedCase.sourcePath,
|
|
674
637
|
caseIndex: collectedCase.caseIndex,
|
|
675
638
|
phase,
|
|
676
|
-
stepIndex
|
|
677
|
-
completedSteps: Object.freeze([
|
|
678
|
-
...steps
|
|
679
|
-
]),
|
|
680
|
-
completedNodes: Object.freeze([
|
|
681
|
-
...completedNodes
|
|
682
|
-
])
|
|
639
|
+
stepIndex
|
|
683
640
|
};
|
|
684
641
|
const stepInfo = {
|
|
685
642
|
scope: 'case',
|
|
@@ -692,14 +649,12 @@ async function runCollectedCase(collectedCase, options) {
|
|
|
692
649
|
scope: 'case',
|
|
693
650
|
case: caseContext
|
|
694
651
|
}, options.context, {
|
|
695
|
-
history: createHistory(options.documentHistory ?? [], completedNodes, 'case'),
|
|
696
652
|
signal,
|
|
697
653
|
defaultTimeoutMs: options.defaultTimeoutMs,
|
|
698
654
|
onTeardown
|
|
699
655
|
});
|
|
700
656
|
await options.onStepResult?.(stepInfo, result);
|
|
701
657
|
results.push(result);
|
|
702
|
-
completedNodes.push(result);
|
|
703
658
|
if ('failed' === result.status && !result.continuedAfterError) break;
|
|
704
659
|
}
|
|
705
660
|
};
|
|
@@ -739,7 +694,7 @@ async function runCollectedCase(collectedCase, options) {
|
|
|
739
694
|
name: collectedCase.definition.name,
|
|
740
695
|
sourcePath: collectedCase.sourcePath,
|
|
741
696
|
caseIndex: collectedCase.caseIndex,
|
|
742
|
-
status:
|
|
697
|
+
status: beforeEach.some((step)=>'failed' === step.status) || steps.some((step)=>'failed' === step.status) || afterEach.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
|
|
743
698
|
beforeEach,
|
|
744
699
|
steps,
|
|
745
700
|
afterEach,
|
|
@@ -782,7 +737,7 @@ class CaseRunner {
|
|
|
782
737
|
definition: {
|
|
783
738
|
name: input.name ?? 'case',
|
|
784
739
|
tags: input.tags ?? [],
|
|
785
|
-
steps: normalizeSteps(input.steps)
|
|
740
|
+
steps: normalizeSteps(input.steps, (name)=>this.registry.get(name))
|
|
786
741
|
}
|
|
787
742
|
};
|
|
788
743
|
const result = await runCollectedCase(collectedCase, {
|
|
@@ -809,7 +764,6 @@ function createDocumentRuntime(document, options) {
|
|
|
809
764
|
const startedAt = new Date();
|
|
810
765
|
const beforeAll = [];
|
|
811
766
|
const afterAll = [];
|
|
812
|
-
const completedNodes = [];
|
|
813
767
|
const nodes = {
|
|
814
768
|
beforeAll: document.lifecycle.beforeAll.map((step)=>options.resolveNode(step.node)),
|
|
815
769
|
afterAll: document.lifecycle.afterAll.map((step)=>options.resolveNode(step.node))
|
|
@@ -840,7 +794,7 @@ function createDocumentRuntime(document, options) {
|
|
|
840
794
|
projectId: document.projectId,
|
|
841
795
|
projectName: project.name,
|
|
842
796
|
sourcePath: document.sourcePath,
|
|
843
|
-
status:
|
|
797
|
+
status: beforeAll.some((step)=>'failed' === step.status) || afterAll.some((step)=>'failed' === step.status) || teardownErrors.length > 0 ? 'failed' : 'success',
|
|
844
798
|
startedAt: startedAt.toISOString(),
|
|
845
799
|
endedAt: endedAt.toISOString(),
|
|
846
800
|
durationMs: Math.max(0, endedAt.getTime() - startedAt.getTime()),
|
|
@@ -869,10 +823,7 @@ function createDocumentRuntime(document, options) {
|
|
|
869
823
|
projectName: project.name,
|
|
870
824
|
sourcePath: document.sourcePath,
|
|
871
825
|
phase,
|
|
872
|
-
stepIndex
|
|
873
|
-
completedNodes: Object.freeze([
|
|
874
|
-
...completedNodes
|
|
875
|
-
])
|
|
826
|
+
stepIndex
|
|
876
827
|
};
|
|
877
828
|
const stepInfo = {
|
|
878
829
|
scope: 'document',
|
|
@@ -885,7 +836,6 @@ function createDocumentRuntime(document, options) {
|
|
|
885
836
|
scope: 'document',
|
|
886
837
|
document: documentContext
|
|
887
838
|
}, context, {
|
|
888
|
-
history: createHistory([], completedNodes, 'document'),
|
|
889
839
|
signal: executionSignal,
|
|
890
840
|
defaultTimeoutMs: options.defaultTimeoutMs,
|
|
891
841
|
onTeardown (node, teardown) {
|
|
@@ -908,7 +858,6 @@ function createDocumentRuntime(document, options) {
|
|
|
908
858
|
});
|
|
909
859
|
await options.onStepResult?.(stepInfo, result);
|
|
910
860
|
results.push(result);
|
|
911
|
-
completedNodes.push(result);
|
|
912
861
|
if ('failed' === result.status && !result.continuedAfterError) break;
|
|
913
862
|
}
|
|
914
863
|
};
|
|
@@ -916,9 +865,6 @@ function createDocumentRuntime(document, options) {
|
|
|
916
865
|
get context () {
|
|
917
866
|
return context;
|
|
918
867
|
},
|
|
919
|
-
get history () {
|
|
920
|
-
return createHistory([], completedNodes, 'document');
|
|
921
|
-
},
|
|
922
868
|
get canRunCases () {
|
|
923
869
|
return started && !signal.aborted && !beforeAll.some((step)=>'failed' === step.status);
|
|
924
870
|
},
|
|
@@ -1013,7 +959,6 @@ async function runWorkflowDocument(document, options) {
|
|
|
1013
959
|
context: runtime.context,
|
|
1014
960
|
projectName,
|
|
1015
961
|
attemptIndex,
|
|
1016
|
-
documentHistory: runtime.history,
|
|
1017
962
|
signal: options.signal,
|
|
1018
963
|
defaultTimeoutMs: options.defaultTimeoutMs,
|
|
1019
964
|
onStepStart: options.onStepStart,
|
|
@@ -1276,7 +1221,7 @@ function collectWorkflowDocument(source, options) {
|
|
|
1276
1221
|
if (!Array.isArray(value)) throw new WorkflowParseError(`Workflow document ${phase} must be an array.`, {
|
|
1277
1222
|
phase
|
|
1278
1223
|
});
|
|
1279
|
-
return normalizeSteps(value).map((normalized, stepIndex)=>{
|
|
1224
|
+
return normalizeSteps(value, options.resolveNode).map((normalized, stepIndex)=>{
|
|
1280
1225
|
const resolved = options.resolveNode(normalized.node);
|
|
1281
1226
|
if (!resolved) throw new WorkflowParseError(`Workflow document ${phase} step ${stepIndex + 1} references unknown node "${normalized.node}".`, {
|
|
1282
1227
|
phase,
|
|
@@ -1312,7 +1257,7 @@ function collectWorkflowDocument(source, options) {
|
|
|
1312
1257
|
if (!Array.isArray(tags) || tags.some((tag)=>'string' != typeof tag || 0 === tag.trim().length)) throw new WorkflowParseError(`Case ${caseIndex + 1} tags must be an array of non-empty strings.`, {
|
|
1313
1258
|
caseIndex
|
|
1314
1259
|
});
|
|
1315
|
-
const steps = normalizeSteps(definition.steps).map((normalized, stepIndex)=>{
|
|
1260
|
+
const steps = normalizeSteps(definition.steps, options.resolveNode).map((normalized, stepIndex)=>{
|
|
1316
1261
|
if (!options.resolveNode(normalized.node)) throw new WorkflowParseError(`Case ${caseIndex + 1} step ${stepIndex + 1} references unknown node "${normalized.node}".`, {
|
|
1317
1262
|
caseIndex,
|
|
1318
1263
|
stepIndex,
|
|
@@ -1362,12 +1307,10 @@ exports.WorkflowDocumentExecutionError = __webpack_exports__.WorkflowDocumentExe
|
|
|
1362
1307
|
exports.WorkflowError = __webpack_exports__.WorkflowError;
|
|
1363
1308
|
exports.WorkflowLifecycleError = __webpack_exports__.WorkflowLifecycleError;
|
|
1364
1309
|
exports.WorkflowParseError = __webpack_exports__.WorkflowParseError;
|
|
1365
|
-
exports.assertJsonSerializable = __webpack_exports__.assertJsonSerializable;
|
|
1366
1310
|
exports.collectWorkflowDocument = __webpack_exports__.collectWorkflowDocument;
|
|
1367
1311
|
exports.createCaseId = __webpack_exports__.createCaseId;
|
|
1368
1312
|
exports.createCaseRunner = __webpack_exports__.createCaseRunner;
|
|
1369
1313
|
exports.createDocumentRuntime = __webpack_exports__.createDocumentRuntime;
|
|
1370
|
-
exports.createHistory = __webpack_exports__.createHistory;
|
|
1371
1314
|
exports.createProjectRuntime = __webpack_exports__.createProjectRuntime;
|
|
1372
1315
|
exports.createWorkflowDocumentId = __webpack_exports__.createWorkflowDocumentId;
|
|
1373
1316
|
exports.defineNode = __webpack_exports__.defineNode;
|
|
@@ -1377,8 +1320,6 @@ exports.normalizeStep = __webpack_exports__.normalizeStep;
|
|
|
1377
1320
|
exports.normalizeSteps = __webpack_exports__.normalizeSteps;
|
|
1378
1321
|
exports.resolveWorkflowVariables = __webpack_exports__.resolveWorkflowVariables;
|
|
1379
1322
|
exports.runWorkflowDocument = __webpack_exports__.runWorkflowDocument;
|
|
1380
|
-
exports.toHistoryEntry = __webpack_exports__.toHistoryEntry;
|
|
1381
|
-
exports.validateCommonNodeInput = __webpack_exports__.validateCommonNodeInput;
|
|
1382
1323
|
exports.z = __webpack_exports__.z;
|
|
1383
1324
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
1384
1325
|
"CaseExecutionError",
|
|
@@ -1398,12 +1339,10 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
1398
1339
|
"WorkflowError",
|
|
1399
1340
|
"WorkflowLifecycleError",
|
|
1400
1341
|
"WorkflowParseError",
|
|
1401
|
-
"assertJsonSerializable",
|
|
1402
1342
|
"collectWorkflowDocument",
|
|
1403
1343
|
"createCaseId",
|
|
1404
1344
|
"createCaseRunner",
|
|
1405
1345
|
"createDocumentRuntime",
|
|
1406
|
-
"createHistory",
|
|
1407
1346
|
"createProjectRuntime",
|
|
1408
1347
|
"createWorkflowDocumentId",
|
|
1409
1348
|
"defineNode",
|
|
@@ -1413,8 +1352,6 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
1413
1352
|
"normalizeSteps",
|
|
1414
1353
|
"resolveWorkflowVariables",
|
|
1415
1354
|
"runWorkflowDocument",
|
|
1416
|
-
"toHistoryEntry",
|
|
1417
|
-
"validateCommonNodeInput",
|
|
1418
1355
|
"z"
|
|
1419
1356
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
1420
1357
|
Object.defineProperty(exports, '__esModule', {
|