Skip to content

Commit 73f013b

Browse files
committed
feat(test): discover native ESM config
1 parent 4e79bf1 commit 73f013b

4 files changed

Lines changed: 50 additions & 12 deletions

File tree

apps/site/docs/en/midscene-test/configuration.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ Midscene Test supports the following configuration files:
1010

1111
| How the configuration is selected | Supported file | Loading behavior |
1212
| --- | --- | --- |
13-
| Automatic discovery, when no configuration path is provided | `midscene.config.ts` only | Transformed from TypeScript and loaded |
13+
| Automatic discovery, when no configuration path is provided | `midscene.config.ts` or `midscene.config.mjs` | `.ts` is transformed from TypeScript; `.mjs` is loaded by Node.js as native ESM |
1414
| An explicit path passed through the CLI's `--config <path>` option or `loadTestProject(path)` | `.ts` or `.mjs` | `.ts` is transformed from TypeScript; `.mjs` is loaded by Node.js as native ESM without TypeScript transformation |
1515

16-
For a typical project, create `midscene.config.ts` in the project root and run Midscene Test without `--config`. Use `.mjs` when another build step already emits the configuration as JavaScript, and pass that file explicitly. A file named `midscene.config.mjs` is not discovered automatically.
16+
For a typical project, create `midscene.config.ts` in the project root and run Midscene Test without `--config`. If another build step emits the configuration as JavaScript, name it `midscene.config.mjs` and it is discovered in the same way. If both files exist, Midscene Test reports a conflict instead of choosing one silently; use `--config <path>` to select the intended file explicitly.
1717

1818
Create browser or device resources in `setup` and register the corresponding Agent Nodes through `nodes`. These determine the capabilities available to each execution project.
1919

@@ -452,7 +452,7 @@ import {
452452
} from '@midscene/test';
453453
```
454454

455-
- **`loadTestProject(path)`**: asynchronously loads an explicitly provided TypeScript (`.ts`) or JavaScript ESM (`.mjs`) project configuration. Without an explicit path, the CLI discovers only `midscene.config.ts`. Midscene Test does not support synchronous loading.
455+
- **`loadTestProject(path)`**: asynchronously loads an explicitly provided TypeScript (`.ts`) or JavaScript ESM (`.mjs`) project configuration. Without `--config`, the CLI discovers `midscene.config.ts` or `midscene.config.mjs`; if both exist, it asks you to select one explicitly. Midscene Test does not support synchronous loading.
456456
- **`runTestProject()`**: asynchronously discovers, runs, and summarizes the entire project.
457457
- **`CaseRunner` / `createCaseRunner()`**: directly runs one test case represented as a plain object, without file parsing or lifecycle management.
458458
- **`runWorkflowDocument()`**: runs the complete lifecycle and every Case in one document.

apps/site/docs/zh/midscene-test/configuration.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ Midscene Test 支持以下配置文件:
1010

1111
| 配置文件的选择方式 | 支持的文件 | 加载方式 |
1212
| --- | --- | --- |
13-
| 未指定配置路径,由 Midscene Test 自动查找 | 仅支持 `midscene.config.ts` | 先转换 TypeScript,再加载配置 |
13+
| 未指定配置路径,由 Midscene Test 自动查找 | `midscene.config.ts` `midscene.config.mjs` | `.ts` 会先经过 TypeScript 转换;`.mjs` 由 Node.js 作为原生 ESM 直接加载 |
1414
| 通过 CLI 的 `--config <路径>``loadTestProject(路径)` 显式指定 | `.ts``.mjs` | `.ts` 会先经过 TypeScript 转换;`.mjs` 由 Node.js 作为原生 ESM 直接加载,不经过 TypeScript 转换 |
1515

16-
一般情况下,在项目根目录创建 `midscene.config.ts`,运行 Midscene Test 时无需传入 `--config`。如果配置已经由其他构建流程输出为 JavaScript,可以使用 `.mjs`但必须显式传入文件路径。Midscene Test 不会自动查找名为 `midscene.config.mjs` 的文件
16+
一般情况下,在项目根目录创建 `midscene.config.ts`,运行 Midscene Test 时无需传入 `--config`。如果配置已经由其他构建流程输出为 JavaScript,将它命名为 `midscene.config.mjs`Midscene Test 也会自动查找。如果两个文件同时存在,Midscene Test 会报告冲突,不会静默选择其中一个;此时请通过 `--config <路径>` 明确指定要使用的文件
1717

1818
`setup` 中创建浏览器或设备资源,并通过 `nodes` 注册对应 Agent 的 Node。这些资源和 Node 决定各执行项目可用的能力。
1919

@@ -446,7 +446,7 @@ import {
446446
} from '@midscene/test';
447447
```
448448

449-
* **`loadTestProject(path)`**:异步加载显式指定的 TypeScript(`.ts`)或 JavaScript ESM(`.mjs`)项目配置。CLI 未收到显式路径时,只会自动查找 `midscene.config.ts`。Midscene Test 不支持同步加载。
449+
* **`loadTestProject(path)`**:异步加载显式指定的 TypeScript(`.ts`)或 JavaScript ESM(`.mjs`)项目配置。CLI 未收到 `--config` 时,会自动查找 `midscene.config.ts` 或 `midscene.config.mjs`;如果两者同时存在,则要求明确指定一个。Midscene Test 不支持同步加载。
450450
* **`runTestProject()`**:异步发现、运行并汇总整个项目。
451451
* **`CaseRunner` / `createCaseRunner()`**:直接执行纯对象形式的单个用例(不含文件解析和生命周期控制)。
452452
* **`runWorkflowDocument()`**:执行单个文档的完整生命周期及内部全部 Case。

packages/test/src/cli/test-project-runner.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import type {
4848
TestProjectRunSummary,
4949
} from './types';
5050

51-
const CONFIG_NAME = 'midscene.config.ts';
51+
const CONFIG_NAMES = ['midscene.config.ts', 'midscene.config.mjs'] as const;
5252
const CONFIG_PREFIX = 'midscene.config.';
5353
const ALWAYS_IGNORED_PATTERNS = [
5454
'.git/**',
@@ -117,17 +117,31 @@ export const discoverTestConfig = (projectRoot: string): string | undefined => {
117117
const candidates = readdirSync(root)
118118
.filter((name) => name.startsWith(CONFIG_PREFIX))
119119
.sort();
120-
const unsupported = candidates.filter((name) => name !== CONFIG_NAME);
120+
const supported = candidates.filter((name) =>
121+
CONFIG_NAMES.includes(name as (typeof CONFIG_NAMES)[number]),
122+
);
123+
const unsupported = candidates.filter(
124+
(name) => !CONFIG_NAMES.includes(name as (typeof CONFIG_NAMES)[number]),
125+
);
121126
if (unsupported.length > 0) {
122127
throw new Error(
123128
[
124129
`Unsupported or conflicting Midscene configs found in ${root}:`,
125130
...candidates.map((name) => `- ${name}`),
126-
`Only ${CONFIG_NAME} is supported.`,
131+
`Only ${CONFIG_NAMES.join(' and ')} are supported.`,
132+
].join('\n'),
133+
);
134+
}
135+
if (supported.length > 1) {
136+
throw new Error(
137+
[
138+
`Multiple Midscene configs found in ${root}:`,
139+
...supported.map((name) => `- ${name}`),
140+
'Pass --config <path> to select one explicitly.',
127141
].join('\n'),
128142
);
129143
}
130-
return candidates.includes(CONFIG_NAME) ? join(root, CONFIG_NAME) : undefined;
144+
return supported[0] ? join(root, supported[0]) : undefined;
131145
};
132146

133147
const defaultResultDir = (projectRoot: string): string =>

packages/test/tests/test-project-runner.test.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,38 @@ describe('test project main-process runner', () => {
8181
).toBe('20260807090504-12345678');
8282
});
8383

84-
it('discovers only midscene.config.ts', () => {
84+
it('discovers midscene.config.ts', () => {
8585
const root = createProject();
8686
const configPath = join(root, 'midscene.config.ts');
8787
writeFileSync(configPath, 'export default { nodes: [] };');
8888

8989
expect(discoverTestConfig(root)).toBe(configPath);
9090
});
9191

92+
it('discovers midscene.config.mjs', () => {
93+
const root = createProject();
94+
const configPath = join(root, 'midscene.config.mjs');
95+
writeFileSync(configPath, 'export default { nodes: [] };');
96+
97+
expect(discoverTestConfig(root)).toBe(configPath);
98+
});
99+
100+
it('requires an explicit config when both supported names exist', () => {
101+
const root = createProject();
102+
writeFileSync(
103+
join(root, 'midscene.config.ts'),
104+
'export default { nodes: [] };',
105+
);
106+
writeFileSync(
107+
join(root, 'midscene.config.mjs'),
108+
'export default { nodes: [] };',
109+
);
110+
111+
expect(() => discoverTestConfig(root)).toThrow(
112+
'Pass --config <path> to select one explicitly.',
113+
);
114+
});
115+
92116
it.each(['js', 'cjs', 'mts', 'cts', 'tsx'])(
93117
'rejects a midscene.config.%s discovery candidate',
94118
(extension) => {
@@ -100,7 +124,7 @@ describe('test project main-process runner', () => {
100124
writeFileSync(join(root, `midscene.config.${extension}`), 'unsupported');
101125

102126
expect(() => discoverTestConfig(root)).toThrow(
103-
'Only midscene.config.ts is supported.',
127+
'Only midscene.config.ts and midscene.config.mjs are supported.',
104128
);
105129
},
106130
);

0 commit comments

Comments
 (0)