@midscene/test 1.16.1 → 1.16.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.
- package/dist/es/{1~77.mjs → 1~731.mjs} +9 -9
- package/dist/es/1~731.mjs.map +1 -0
- package/dist/es/cli/index.mjs +342 -83
- package/dist/es/cli/index.mjs.map +1 -1
- package/dist/es/index.mjs +45 -1
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/test-cli.mjs +1532 -134
- package/dist/es/test-cli.mjs.map +1 -1
- package/dist/lib/cli/index.js +340 -81
- package/dist/lib/cli/index.js.map +1 -1
- package/dist/lib/index.js +45 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/test-cli.js +1523 -131
- package/dist/lib/test-cli.js.map +1 -1
- package/dist/templates/test/android/.env.example +1 -1
- package/dist/templates/test/android/README.md +1 -1
- package/dist/templates/test/android/README.zh.md +1 -1
- package/dist/templates/test/computer/.env.example +1 -1
- package/dist/templates/test/computer/README.md +1 -1
- package/dist/templates/test/computer/README.zh.md +1 -1
- package/dist/templates/test/harmony/.env.example +1 -1
- package/dist/templates/test/harmony/README.md +1 -1
- package/dist/templates/test/harmony/README.zh.md +1 -1
- package/dist/templates/test/ios/.env.example +1 -1
- package/dist/templates/test/ios/README.md +1 -1
- package/dist/templates/test/ios/README.zh.md +1 -1
- package/dist/templates/test/web/.env.example +1 -1
- package/dist/templates/test/web/README.md +1 -1
- package/dist/templates/test/web/README.zh.md +1 -1
- package/dist/types/cli/index.d.ts +75 -0
- package/dist/types/index.d.ts +3 -0
- package/package.json +14 -13
- package/dist/es/1~77.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copy this file to .env before running tests.
|
|
2
2
|
# Do not commit .env to your repository. In CI, inject these values as environment variables instead.
|
|
3
3
|
# Choose a supported model and copy its four configuration values from:
|
|
4
|
-
# https://midscenejs.com/model-
|
|
4
|
+
# https://midscenejs.com/model-api-setup.html
|
|
5
5
|
# For the complete environment variable reference, see:
|
|
6
6
|
# https://midscenejs.com/model-config.html
|
|
7
7
|
# After configuring .env, verify model connectivity and Midscene compatibility from the project directory:
|
|
@@ -4,7 +4,7 @@ A Midscene Test project for Android, based on the TodoMVC case in `midscene-exam
|
|
|
4
4
|
|
|
5
5
|
If you skipped installation during creation, run `{{INSTALL_COMMAND}}`. The `postinstall` script automatically generates `midscene-node-spec.android.md` after each dependency installation. If lifecycle scripts are disabled, run `{{RUN_NODES_COMMAND}}` manually.
|
|
6
6
|
|
|
7
|
-
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-
|
|
7
|
+
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-api-setup.html). Do not commit `.env` to your repository; inject the model configuration as environment variables in CI.
|
|
8
8
|
|
|
9
9
|
After configuring `.env`, run `{{VERIFY_MODEL_COMMAND}}` from the project directory to check model connectivity and Midscene compatibility. This check does not require a browser or device. If it fails, see [Model debugging and observability](https://midscenejs.com/model-debugging-observability.html) before running tests.
|
|
10
10
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
这是参考 `midscene-example/android/vitest-demo` TodoMVC 用例的 Android 版 Midscene Test 项目。
|
|
4
4
|
|
|
5
|
-
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.android.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-
|
|
5
|
+
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.android.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-api-setup.html)配置模型。
|
|
6
6
|
|
|
7
7
|
配置后,在项目目录执行 `{{VERIFY_MODEL_COMMAND}}`,检查模型连接和 Midscene 兼容性。这一步不需要浏览器或设备;若检查失败,请先参考[模型调试与可观测性](https://midscenejs.com/model-debugging-observability.html)排查,再运行测试。
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copy this file to .env before running tests.
|
|
2
2
|
# Do not commit .env to your repository. In CI, inject these values as environment variables instead.
|
|
3
3
|
# Choose a supported model and copy its four configuration values from:
|
|
4
|
-
# https://midscenejs.com/model-
|
|
4
|
+
# https://midscenejs.com/model-api-setup.html
|
|
5
5
|
# For the complete environment variable reference, see:
|
|
6
6
|
# https://midscenejs.com/model-config.html
|
|
7
7
|
# After configuring .env, verify model connectivity and Midscene compatibility from the project directory:
|
|
@@ -4,7 +4,7 @@ A Midscene Test project for Computer, based on the TodoMVC case in `midscene-exa
|
|
|
4
4
|
|
|
5
5
|
If you skipped installation during creation, run `{{INSTALL_COMMAND}}`. The `postinstall` script automatically generates `midscene-node-spec.computer.md` after each dependency installation. If lifecycle scripts are disabled, run `{{RUN_NODES_COMMAND}}` manually.
|
|
6
6
|
|
|
7
|
-
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-
|
|
7
|
+
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-api-setup.html). Do not commit `.env` to your repository; inject the model configuration as environment variables in CI.
|
|
8
8
|
|
|
9
9
|
After configuring `.env`, run `{{VERIFY_MODEL_COMMAND}}` from the project directory to check model connectivity and Midscene compatibility. This check does not require a browser or device. If it fails, see [Model debugging and observability](https://midscenejs.com/model-debugging-observability.html) before running tests.
|
|
10
10
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
这是参考 `midscene-example/computer/vitest-demo` TodoMVC 用例的 Computer 版 Midscene Test 项目。
|
|
4
4
|
|
|
5
|
-
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.computer.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-
|
|
5
|
+
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.computer.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-api-setup.html)配置模型。
|
|
6
6
|
|
|
7
7
|
配置后,在项目目录执行 `{{VERIFY_MODEL_COMMAND}}`,检查模型连接和 Midscene 兼容性。这一步不需要浏览器或设备;若检查失败,请先参考[模型调试与可观测性](https://midscenejs.com/model-debugging-observability.html)排查,再运行测试。
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copy this file to .env before running tests.
|
|
2
2
|
# Do not commit .env to your repository. In CI, inject these values as environment variables instead.
|
|
3
3
|
# Choose a supported model and copy its four configuration values from:
|
|
4
|
-
# https://midscenejs.com/model-
|
|
4
|
+
# https://midscenejs.com/model-api-setup.html
|
|
5
5
|
# For the complete environment variable reference, see:
|
|
6
6
|
# https://midscenejs.com/model-config.html
|
|
7
7
|
# After configuring .env, verify model connectivity and Midscene compatibility from the project directory:
|
|
@@ -4,7 +4,7 @@ A Midscene Test project for HarmonyOS, based on the TodoMVC case in `midscene-ex
|
|
|
4
4
|
|
|
5
5
|
If you skipped installation during creation, run `{{INSTALL_COMMAND}}`. The `postinstall` script automatically generates `midscene-node-spec.harmony.md` after each dependency installation. If lifecycle scripts are disabled, run `{{RUN_NODES_COMMAND}}` manually.
|
|
6
6
|
|
|
7
|
-
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-
|
|
7
|
+
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-api-setup.html). Do not commit `.env` to your repository; inject the model configuration as environment variables in CI.
|
|
8
8
|
|
|
9
9
|
After configuring `.env`, run `{{VERIFY_MODEL_COMMAND}}` from the project directory to check model connectivity and Midscene compatibility. This check does not require a browser or device. If it fails, see [Model debugging and observability](https://midscenejs.com/model-debugging-observability.html) before running tests.
|
|
10
10
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
这是参考 `midscene-example/harmony/vitest-demo` TodoMVC 用例的 HarmonyOS 版 Midscene Test 项目。
|
|
4
4
|
|
|
5
|
-
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.harmony.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-
|
|
5
|
+
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.harmony.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-api-setup.html)配置模型。
|
|
6
6
|
|
|
7
7
|
配置后,在项目目录执行 `{{VERIFY_MODEL_COMMAND}}`,检查模型连接和 Midscene 兼容性。这一步不需要浏览器或设备;若检查失败,请先参考[模型调试与可观测性](https://midscenejs.com/model-debugging-observability.html)排查,再运行测试。
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copy this file to .env before running tests.
|
|
2
2
|
# Do not commit .env to your repository. In CI, inject these values as environment variables instead.
|
|
3
3
|
# Choose a supported model and copy its four configuration values from:
|
|
4
|
-
# https://midscenejs.com/model-
|
|
4
|
+
# https://midscenejs.com/model-api-setup.html
|
|
5
5
|
# For the complete environment variable reference, see:
|
|
6
6
|
# https://midscenejs.com/model-config.html
|
|
7
7
|
# After configuring .env, verify model connectivity and Midscene compatibility from the project directory:
|
|
@@ -4,7 +4,7 @@ A Midscene Test project for iOS, based on the TodoMVC case in `midscene-example/
|
|
|
4
4
|
|
|
5
5
|
If you skipped installation during creation, run `{{INSTALL_COMMAND}}`. The `postinstall` script automatically generates `midscene-node-spec.ios.md` after each dependency installation. If lifecycle scripts are disabled, run `{{RUN_NODES_COMMAND}}` manually.
|
|
6
6
|
|
|
7
|
-
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-
|
|
7
|
+
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-api-setup.html). Do not commit `.env` to your repository; inject the model configuration as environment variables in CI.
|
|
8
8
|
|
|
9
9
|
After configuring `.env`, run `{{VERIFY_MODEL_COMMAND}}` from the project directory to check model connectivity and Midscene compatibility. This check does not require a browser or device. If it fails, see [Model debugging and observability](https://midscenejs.com/model-debugging-observability.html) before running tests.
|
|
10
10
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
这是参考 `midscene-example/ios/vitest-demo` TodoMVC 用例的 iOS 版 Midscene Test 项目。
|
|
4
4
|
|
|
5
|
-
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.ios.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-
|
|
5
|
+
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.ios.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-api-setup.html)配置模型。
|
|
6
6
|
|
|
7
7
|
配置后,在项目目录执行 `{{VERIFY_MODEL_COMMAND}}`,检查模型连接和 Midscene 兼容性。这一步不需要浏览器或设备;若检查失败,请先参考[模型调试与可观测性](https://midscenejs.com/model-debugging-observability.html)排查,再运行测试。
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Copy this file to .env before running tests.
|
|
2
2
|
# Do not commit .env to your repository. In CI, inject these values as environment variables instead.
|
|
3
3
|
# Choose a supported model and copy its four configuration values from:
|
|
4
|
-
# https://midscenejs.com/model-
|
|
4
|
+
# https://midscenejs.com/model-api-setup.html
|
|
5
5
|
# For the complete environment variable reference, see:
|
|
6
6
|
# https://midscenejs.com/model-config.html
|
|
7
7
|
# After configuring .env, verify model connectivity and Midscene compatibility from the project directory:
|
|
@@ -4,7 +4,7 @@ A Midscene Test project for Web, based on the TodoMVC Test Runner example. For d
|
|
|
4
4
|
|
|
5
5
|
If you skipped installation during creation, run `{{INSTALL_COMMAND}}`. The `postinstall` script automatically generates `midscene-node-spec.web.md` after each dependency installation. If lifecycle scripts are disabled, run `{{RUN_NODES_COMMAND}}` manually.
|
|
6
6
|
|
|
7
|
-
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-
|
|
7
|
+
Copy `.env.example` to `.env`, then choose and configure a model using the [supported models and setup guide](https://midscenejs.com/model-api-setup.html). Do not commit `.env` to your repository; inject the model configuration as environment variables in CI.
|
|
8
8
|
|
|
9
9
|
After configuring `.env`, run `{{VERIFY_MODEL_COMMAND}}` from the project directory to check model connectivity and Midscene compatibility. This check does not require a browser or device. If it fails, see [Model debugging and observability](https://midscenejs.com/model-debugging-observability.html) before running tests.
|
|
10
10
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
这是参考 `midscene-example` TodoMVC Test Runner 用例的 Web 版 Midscene Test 项目。直接使用 Playwright 的示例请看 [playwright-demo](https://github.com/web-infra-dev/midscene-example/tree/main/playwright-demo)。
|
|
4
4
|
|
|
5
|
-
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.web.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-
|
|
5
|
+
如果创建时跳过安装,执行 `{{INSTALL_COMMAND}}`。安装后会自动生成 `midscene-node-spec.web.md`;若禁用了安装脚本,手动执行 `{{RUN_NODES_COMMAND}}`。复制 `.env.example` 为 `.env`,按[模型配置指南](https://midscenejs.com/model-api-setup.html)配置模型。
|
|
6
6
|
|
|
7
7
|
配置后,在项目目录执行 `{{VERIFY_MODEL_COMMAND}}`,检查模型连接和 Midscene 兼容性。这一步不需要浏览器或设备;若检查失败,请先参考[模型调试与可观测性](https://midscenejs.com/model-debugging-observability.html)排查,再运行测试。
|
|
8
8
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Awaitable } from '@midscene/core/internal/test-runner';
|
|
2
|
+
import type { CaseRunOutcome as CaseRunOutcome_2 } from '@midscene/core/internal/test-runner';
|
|
3
|
+
import type { CaseRunResult as CaseRunResult_2 } from '@midscene/core/internal/test-runner';
|
|
2
4
|
import { CommonAgentTestRunnerApi } from '@midscene/core/agent/test';
|
|
3
5
|
import type * as Core from '@midscene/core/internal/test-runner';
|
|
4
6
|
import type { ExecutionProjectDefinition as ExecutionProjectDefinition_2 } from '@midscene/core/internal/test-runner';
|
|
@@ -14,9 +16,13 @@ import { ProjectSetupDefinition } from '@midscene/core/internal/test-runner';
|
|
|
14
16
|
import { ProjectTeardown } from '@midscene/core/internal/test-runner';
|
|
15
17
|
import { ProjectTeardownContext } from '@midscene/core/internal/test-runner';
|
|
16
18
|
import { ResolvedExecutionProject } from '@midscene/core/internal/test-runner';
|
|
19
|
+
import type { StepExecutionInfo } from '@midscene/core/internal/test-runner';
|
|
20
|
+
import type { StepRunResult as StepRunResult_2 } from '@midscene/core/internal/test-runner';
|
|
17
21
|
import { TestFileSelection } from '@midscene/core/internal/test-runner';
|
|
18
22
|
import { TestRunReportDocumentPlan } from '@midscene/core';
|
|
23
|
+
import type { TestRunReportMetrics } from '@midscene/core';
|
|
19
24
|
import { TestTagSelection } from '@midscene/core/internal/test-runner';
|
|
25
|
+
import type { WorkflowDocumentRunResult as WorkflowDocumentRunResult_2 } from '@midscene/core/internal/test-runner';
|
|
20
26
|
import { WorkflowError } from '@midscene/core/internal/test-runner';
|
|
21
27
|
import { WorkflowReportSource } from '@midscene/core/internal/test-runner';
|
|
22
28
|
|
|
@@ -218,9 +224,12 @@ export declare interface TestProjectRunOptions {
|
|
|
218
224
|
resultDir?: string;
|
|
219
225
|
projectNames?: readonly string[];
|
|
220
226
|
onProgress?(message: string): void;
|
|
227
|
+
onEvent?(event: TestReporterEvent): void;
|
|
221
228
|
}
|
|
222
229
|
|
|
223
230
|
export declare interface TestProjectRunResult {
|
|
231
|
+
/** Shared report usage, including every attempt and lifecycle phase. */
|
|
232
|
+
metrics?: TestRunReportMetrics;
|
|
224
233
|
operationLog?: {
|
|
225
234
|
path: string;
|
|
226
235
|
snapshotAt: string;
|
|
@@ -262,6 +271,72 @@ export declare interface TestProjectRunSummary {
|
|
|
262
271
|
projectFailures: number;
|
|
263
272
|
}
|
|
264
273
|
|
|
274
|
+
/** Structured presentation facts; execution and persistence do not depend on a reporter. */
|
|
275
|
+
declare type TestReporterEvent = {
|
|
276
|
+
type: 'project-end';
|
|
277
|
+
project: TestExecutionProjectRunResult;
|
|
278
|
+
} | {
|
|
279
|
+
type: 'project-phase';
|
|
280
|
+
projectName: string;
|
|
281
|
+
phase: 'setup' | 'running' | 'teardown';
|
|
282
|
+
} | {
|
|
283
|
+
type: 'run-start';
|
|
284
|
+
projects: number;
|
|
285
|
+
documents: number;
|
|
286
|
+
cases: number;
|
|
287
|
+
projectRoot?: string;
|
|
288
|
+
configPath?: string;
|
|
289
|
+
startedAt?: string;
|
|
290
|
+
maxConcurrentProjects?: number | null;
|
|
291
|
+
maxConcurrentFiles?: number | null;
|
|
292
|
+
configuredModels?: readonly {
|
|
293
|
+
name: string;
|
|
294
|
+
intents: readonly string[];
|
|
295
|
+
}[];
|
|
296
|
+
files?: readonly {
|
|
297
|
+
documentId: string;
|
|
298
|
+
projectName: string;
|
|
299
|
+
sourcePath: string;
|
|
300
|
+
cases: number;
|
|
301
|
+
}[];
|
|
302
|
+
} | {
|
|
303
|
+
type: 'document-start';
|
|
304
|
+
documentId: string;
|
|
305
|
+
projectName: string;
|
|
306
|
+
sourcePath: string;
|
|
307
|
+
cases: number;
|
|
308
|
+
} | {
|
|
309
|
+
type: 'document-end';
|
|
310
|
+
document: WorkflowDocumentRunResult_2;
|
|
311
|
+
cases: readonly CaseRunOutcome_2[];
|
|
312
|
+
durationMs: number;
|
|
313
|
+
} | {
|
|
314
|
+
type: 'step-start';
|
|
315
|
+
projectName: string;
|
|
316
|
+
info: StepExecutionInfo;
|
|
317
|
+
} | {
|
|
318
|
+
type: 'step-end';
|
|
319
|
+
projectName: string;
|
|
320
|
+
info: StepExecutionInfo;
|
|
321
|
+
result?: StepRunResult_2;
|
|
322
|
+
} | {
|
|
323
|
+
type: 'case-attempt-end';
|
|
324
|
+
attempt: CaseRunResult_2;
|
|
325
|
+
maxAttempts: number;
|
|
326
|
+
} | {
|
|
327
|
+
type: 'case-progress';
|
|
328
|
+
outcome: CaseRunOutcome_2;
|
|
329
|
+
documentAttemptIndex: number;
|
|
330
|
+
} | {
|
|
331
|
+
type: 'case-end';
|
|
332
|
+
outcome: CaseRunOutcome_2;
|
|
333
|
+
documentRetries?: number;
|
|
334
|
+
} | {
|
|
335
|
+
type: 'document-retry';
|
|
336
|
+
document: WorkflowDocumentRunResult_2;
|
|
337
|
+
maxAttempts: number;
|
|
338
|
+
};
|
|
339
|
+
|
|
265
340
|
export { TestTagSelection }
|
|
266
341
|
|
|
267
342
|
export declare const validateTestFileSelection: (value: unknown, label?: string) => TestFileSelection | undefined;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ import { StepValue } from '@midscene/core/internal/test-runner';
|
|
|
49
49
|
import { TestFileSelection } from '@midscene/core/internal/test-runner';
|
|
50
50
|
import { TestRunReportDocumentPlan } from '@midscene/core';
|
|
51
51
|
import type { TestRunReportDump } from '@midscene/core';
|
|
52
|
+
import type { TestRunReportMetrics } from '@midscene/core';
|
|
52
53
|
import type { TestRunReportSourceIndex } from '@midscene/core';
|
|
53
54
|
import { TestTagSelection } from '@midscene/core/internal/test-runner';
|
|
54
55
|
import { WorkflowDocumentDefinition } from '@midscene/core/internal/test-runner';
|
|
@@ -337,6 +338,8 @@ declare interface TestProjectCollectionError {
|
|
|
337
338
|
}
|
|
338
339
|
|
|
339
340
|
declare interface TestProjectRunResult {
|
|
341
|
+
/** Shared report usage, including every attempt and lifecycle phase. */
|
|
342
|
+
metrics?: TestRunReportMetrics;
|
|
340
343
|
operationLog?: {
|
|
341
344
|
path: string;
|
|
342
345
|
snapshotAt: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/test",
|
|
3
3
|
"description": "Midscene Test: an extensible YAML testing framework and Node SDK.",
|
|
4
|
-
"version": "1.16.
|
|
4
|
+
"version": "1.16.2",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/web-infra-dev/midscene.git",
|
|
@@ -54,12 +54,13 @@
|
|
|
54
54
|
"http-server": "14.1.1",
|
|
55
55
|
"js-yaml": "4.1.0",
|
|
56
56
|
"lodash.merge": "4.6.2",
|
|
57
|
+
"string-width": "4.2.3",
|
|
57
58
|
"tinyglobby": "0.2.15",
|
|
58
59
|
"tsx": "^4.19.2",
|
|
59
60
|
"yargs": "17.7.3",
|
|
60
61
|
"zod": "^3.25.1",
|
|
61
|
-
"@midscene/core": "1.16.
|
|
62
|
-
"@midscene/shared": "1.16.
|
|
62
|
+
"@midscene/core": "1.16.2",
|
|
63
|
+
"@midscene/shared": "1.16.2"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@rslib/core": "^0.18.3",
|
|
@@ -71,20 +72,20 @@
|
|
|
71
72
|
"puppeteer": "24.6.0",
|
|
72
73
|
"typescript": "^5.8.3",
|
|
73
74
|
"vitest": "3.0.5",
|
|
74
|
-
"@midscene/
|
|
75
|
-
"@midscene/
|
|
76
|
-
"@midscene/
|
|
77
|
-
"@midscene/
|
|
78
|
-
"@midscene/
|
|
75
|
+
"@midscene/computer": "1.16.2",
|
|
76
|
+
"@midscene/ios": "1.16.2",
|
|
77
|
+
"@midscene/web": "1.16.2",
|
|
78
|
+
"@midscene/harmony": "1.16.2",
|
|
79
|
+
"@midscene/android": "1.16.2"
|
|
79
80
|
},
|
|
80
81
|
"peerDependencies": {
|
|
81
82
|
"playwright": "^1.45.0",
|
|
82
83
|
"puppeteer": "24.6.0",
|
|
83
|
-
"@midscene/
|
|
84
|
-
"@midscene/
|
|
85
|
-
"@midscene/
|
|
86
|
-
"@midscene/
|
|
87
|
-
"@midscene/web": "1.16.
|
|
84
|
+
"@midscene/android": "1.16.2",
|
|
85
|
+
"@midscene/harmony": "1.16.2",
|
|
86
|
+
"@midscene/ios": "1.16.2",
|
|
87
|
+
"@midscene/computer": "1.16.2",
|
|
88
|
+
"@midscene/web": "1.16.2"
|
|
88
89
|
},
|
|
89
90
|
"peerDependenciesMeta": {
|
|
90
91
|
"@midscene/android": {
|
package/dist/es/1~77.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"1~77.mjs","sources":["../../src/cli/dotenv-loader.ts","../../src/cli/model-command.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport dotenv from 'dotenv';\n\nexport interface DotenvLoadOptions {\n dotenvOverride?: boolean;\n dotenvDebug?: boolean;\n cwd?: string;\n log?: (message: string) => void;\n}\n\nexport function loadDotenvConfig(options: DotenvLoadOptions = {}) {\n const dotEnvConfigFile = join(options.cwd ?? process.cwd(), '.env');\n if (!existsSync(dotEnvConfigFile)) {\n return;\n }\n\n options.log?.(` Env file: ${dotEnvConfigFile}`);\n dotenv.config({\n path: dotEnvConfigFile,\n debug: options.dotenvDebug,\n override: options.dotenvOverride,\n });\n}\n","import { runConnectivityTest } from '@midscene/core';\nimport {\n type IModelConfig,\n type TIntent,\n globalModelConfigManager,\n} from '@midscene/shared/env';\nimport chalk from 'chalk';\nimport { loadDotenvConfig } from './dotenv-loader';\n\nconst DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1';\nconst MODEL_VERIFY_SEPARATOR = '────────────────────────────────────────';\nconst modelCommandUsage = (commandName: string) => `Usage:\n ${commandName} model verify\n\nVerify model connectivity and Midscene compatibility for default, locate, planning, and insight models.\nReads .env from the current working directory, overriding shell environment variables.\nShows endpoints, model names, request counts, and per-check results with duration.\nReturns exit code 0 on success and 1 on failure.\n\nOptions:\n --help, -h Show this help\n`;\n\ninterface ModelCommandIO {\n stdout: (message: string) => void;\n stderr: (message: string) => void;\n}\n\ninterface ModelCommandDeps {\n loadDotenv: () => void;\n getModelConfig: (intent: TIntent) => IModelConfig;\n verifyModel: typeof runConnectivityTest;\n}\n\nexport interface CurlCommandItem {\n intents: TIntent[];\n curl: string;\n usesDefaultBaseURL: boolean;\n}\n\nfunction assertNoModelVerifyOptions(args: string[], commandName: string) {\n for (const arg of args) {\n throw new Error(`Unknown option for ${commandName} model verify: ${arg}`);\n }\n}\n\nfunction formatTable(headers: string[], rows: string[][]): string {\n const widths = headers.map((header, index) =>\n Math.max(header.length, ...rows.map((row) => row[index].length)),\n );\n const formatRow = (row: string[]) =>\n row\n .map((cell, index) => cell.padEnd(widths[index]))\n .join(' ')\n .trimEnd();\n return [formatRow(headers), ...rows.map(formatRow)].join('\\n');\n}\n\nfunction displayEndpoint(endpoint: string): string {\n try {\n const url = new URL(endpoint);\n url.username = '';\n url.password = '';\n url.search = '';\n url.hash = '';\n return url.toString();\n } catch {\n return '(invalid endpoint URL)';\n }\n}\n\nfunction shellSingleQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction buildChatCompletionsUrl(baseURL?: string): string {\n const normalizedBaseURL = (baseURL || DEFAULT_OPENAI_BASE_URL).replace(\n /\\/+$/,\n '',\n );\n if (normalizedBaseURL.endsWith('/chat/completions')) {\n return normalizedBaseURL;\n }\n return `${normalizedBaseURL}/chat/completions`;\n}\n\nfunction buildCurlCommand(modelConfig: IModelConfig): string {\n const payload = {\n model: modelConfig.modelName,\n messages: [{ role: 'user', content: 'What is 1+1?' }],\n };\n\n return [\n `curl -X POST ${shellSingleQuote(buildChatCompletionsUrl(modelConfig.openaiBaseURL))} \\\\`,\n ` -H ${shellSingleQuote(`Authorization: Bearer ${modelConfig.openaiApiKey || ''}`)} \\\\`,\n ` -H ${shellSingleQuote('Content-Type: application/json')} \\\\`,\n ` -d ${shellSingleQuote(JSON.stringify(payload, null, 2))}`,\n ].join('\\n');\n}\n\nfunction buildCurlDedupKey(modelConfig: IModelConfig): string {\n return JSON.stringify({\n baseURL: modelConfig.openaiBaseURL || DEFAULT_OPENAI_BASE_URL,\n apiKey: modelConfig.openaiApiKey || '',\n modelName: modelConfig.modelName,\n });\n}\n\nexport function buildModelVerifyCurlCommands(\n configs: Array<{ intent: TIntent; modelConfig: IModelConfig }>,\n): CurlCommandItem[] {\n const commandMap = new Map<string, CurlCommandItem>();\n\n for (const item of configs) {\n const key = buildCurlDedupKey(item.modelConfig);\n const existing = commandMap.get(key);\n if (existing) {\n existing.intents.push(item.intent);\n continue;\n }\n commandMap.set(key, {\n intents: [item.intent],\n curl: buildCurlCommand(item.modelConfig),\n usesDefaultBaseURL: !item.modelConfig.openaiBaseURL,\n });\n }\n\n return [...commandMap.values()];\n}\n\nfunction formatModelVerifyFailureOutput(\n message: string | undefined,\n curlCommands: CurlCommandItem[],\n): string {\n const details = message?.trim() || 'No failure details were generated.';\n const curlSection = curlCommands\n .map((item) => {\n const baseUrlNote = item.usesDefaultBaseURL\n ? ' (base URL not configured; using OpenAI SDK default)'\n : '';\n return chalk.gray(\n `# ${item.intents.join(', ')}${baseUrlNote}\\n${item.curl}`,\n );\n })\n .join('\\n\\n');\n\n return [\n chalk.red.bold('❌ Model verify failed with messages:'),\n MODEL_VERIFY_SEPARATOR,\n '',\n details,\n '',\n MODEL_VERIFY_SEPARATOR,\n 'Generated curl requests for basic API connectivity:',\n 'If the error is a basic connectivity issue, use these requests to test the base URL, API key, and model name directly.',\n 'These commands contain your API key. Do not share them publicly.',\n '',\n curlSection,\n ].join('\\n');\n}\n\nfunction getDefaultDeps(io: ModelCommandIO): ModelCommandDeps {\n return {\n loadDotenv: () => {\n loadDotenvConfig({\n dotenvDebug: true,\n dotenvOverride: true,\n log: io.stdout,\n });\n },\n getModelConfig: (intent) => globalModelConfigManager.getModelConfig(intent),\n verifyModel: runConnectivityTest,\n };\n}\n\nasync function runModelVerifyCommand(\n args: string[],\n deps: ModelCommandDeps,\n io: ModelCommandIO,\n commandName: string,\n): Promise<number> {\n try {\n if (args.includes('--help') || args.includes('-h')) {\n io.stdout(modelCommandUsage(commandName));\n return 0;\n }\n\n assertNoModelVerifyOptions(args, commandName);\n io.stdout(\n 'Model verify started. This usually completes within 30 seconds.',\n );\n deps.loadDotenv();\n io.stdout('');\n\n const defaultModelConfig = deps.getModelConfig('default');\n const locateModelConfig = deps.getModelConfig('locate');\n const planningModelConfig = deps.getModelConfig('planning');\n const insightModelConfig = deps.getModelConfig('insight');\n const curlCommands = buildModelVerifyCurlCommands([\n { intent: 'default', modelConfig: defaultModelConfig },\n { intent: 'locate', modelConfig: locateModelConfig },\n { intent: 'planning', modelConfig: planningModelConfig },\n { intent: 'insight', modelConfig: insightModelConfig },\n ]);\n\n const baseURLs = new Map<string, number>();\n const modelRows = (\n [\n ['planning', planningModelConfig, 'Text response'],\n ['insight', insightModelConfig, 'Image understanding'],\n ['locate', locateModelConfig, 'AI locate'],\n ['default', defaultModelConfig, 'Text response'],\n ] as const\n ).map(([intent, config, check]) => {\n const baseURL = config.openaiExtraConfig?.baseURL ?? config.openaiBaseURL;\n const endpoint = baseURL\n ? displayEndpoint(String(baseURL))\n : 'provider default';\n if (!baseURLs.has(endpoint)) baseURLs.set(endpoint, baseURLs.size + 1);\n return [intent, config.modelName, check, `[${baseURLs.get(endpoint)}]`];\n });\n io.stdout(\n formatTable(['Model role', 'Model', 'Check', 'Endpoint'], modelRows),\n );\n io.stdout('');\n for (const [endpoint, index] of baseURLs) {\n io.stdout(`[${index}] Base URL: ${endpoint}`);\n }\n io.stdout('\\nRunning 4 checks...\\n');\n\n const result = await deps.verifyModel({\n defaultModelConfig,\n locateModelConfig,\n planningModelConfig,\n insightModelConfig,\n });\n\n const checkLabels = {\n text: 'Text response',\n vision: 'Image understanding',\n aiLocate: 'AI locate',\n };\n io.stdout(\n formatTable(\n ['Model role', 'Check', 'Result', 'Requests', 'Time'],\n result.checks.map((check) => [\n check.intent,\n checkLabels[check.name],\n check.passed ? 'PASS' : 'FAIL',\n String(check.requestCount),\n `${check.durationMs} ms`,\n ]),\n ),\n );\n const requestEndpoints = new Map<string, Set<string>>();\n for (const check of result.checks) {\n for (const endpoint of check.endpoints) {\n const display = displayEndpoint(endpoint);\n if (!requestEndpoints.has(display))\n requestEndpoints.set(display, new Set());\n requestEndpoints.get(display)!.add(check.intent);\n }\n if (!check.passed && check.message)\n io.stdout(`\\n${check.intent}: ${check.message}`);\n }\n if (requestEndpoints.size > 0) {\n io.stdout('\\nRequest endpoints:');\n for (const [endpoint, intents] of requestEndpoints) {\n io.stdout(` ${[...intents].join(', ')}: ${endpoint}`);\n }\n }\n io.stdout('');\n const passedChecks = result.checks.filter((check) => check.passed).length;\n io.stdout(\n `Requests sent: ${result.requestCount}. Checks: ${passedChecks} passed, ${result.checks.length - passedChecks} failed.`,\n );\n\n if (result.passed) {\n io.stdout('✅ Model verify passed.');\n return 0;\n }\n\n io.stderr(formatModelVerifyFailureOutput(result.message, curlCommands));\n return 1;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n io.stderr(\n [\n MODEL_VERIFY_SEPARATOR,\n '❌ Model verify failed with messages:',\n '',\n message,\n MODEL_VERIFY_SEPARATOR,\n ].join('\\n'),\n );\n return 1;\n }\n}\n\nexport async function runModelCommand(\n rawArgs: string[],\n deps?: Partial<ModelCommandDeps>,\n io: ModelCommandIO = {\n stdout: console.log,\n stderr: console.error,\n },\n commandName = 'midscene-test',\n): Promise<number> {\n const [, action, ...restArgs] = rawArgs;\n const mergedDeps = {\n ...getDefaultDeps(io),\n ...deps,\n };\n\n if (!action || action === '--help' || action === '-h') {\n io.stdout(modelCommandUsage(commandName));\n return 0;\n }\n\n if (action === 'verify') {\n return runModelVerifyCommand(restArgs, mergedDeps, io, commandName);\n }\n\n if (action === 'eval') {\n io.stderr(\n `${commandName} model eval is not implemented yet. It is reserved for future model evaluation suites.`,\n );\n return 1;\n }\n\n io.stderr(\n `Unknown ${commandName} model command: ${action}\\n\\n${modelCommandUsage(commandName)}`,\n );\n return 1;\n}\n\nexport { loadDotenvConfig, type DotenvLoadOptions } from './dotenv-loader';\n"],"names":["loadDotenvConfig","options","dotEnvConfigFile","join","process","existsSync","dotenv","DEFAULT_OPENAI_BASE_URL","MODEL_VERIFY_SEPARATOR","modelCommandUsage","commandName","assertNoModelVerifyOptions","args","arg","Error","formatTable","headers","rows","widths","header","index","Math","row","formatRow","cell","displayEndpoint","endpoint","url","URL","shellSingleQuote","value","buildChatCompletionsUrl","baseURL","normalizedBaseURL","buildCurlCommand","modelConfig","payload","JSON","buildCurlDedupKey","buildModelVerifyCurlCommands","configs","commandMap","Map","item","key","existing","formatModelVerifyFailureOutput","message","curlCommands","details","curlSection","baseUrlNote","chalk","getDefaultDeps","io","intent","globalModelConfigManager","runConnectivityTest","runModelVerifyCommand","deps","defaultModelConfig","locateModelConfig","planningModelConfig","insightModelConfig","baseURLs","modelRows","config","check","String","result","checkLabels","requestEndpoints","display","Set","intents","passedChecks","error","runModelCommand","rawArgs","console","action","restArgs","mergedDeps"],"mappings":"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"}
|