Skip to content

Commit fd58ead

Browse files
quanruclaude
andauthored
feat(yaml): Support all device options in YAML configuration (#1367)
* feat(yaml): support all device options in YAML configuration This PR enables YAML scripts to use all Android and iOS device options by centralizing device option types and ensuring runtime configuration propagation. Changes: - Created packages/core/src/device/device-options.ts to centralize all device option type definitions (AndroidDeviceOpt, IOSDeviceOpt) - Updated MidsceneYamlScriptAndroidEnv and MidsceneYamlScriptIOSEnv to extend device options using Omit<> to exclude programmatic fields - Fixed runtime configuration passing in create-yaml-player.ts to forward all YAML config options to device constructors - Simplified agent creation functions to pass entire options object instead of manually listing each parameter YAML scripts can now configure: Android: - androidAdbPath, remoteAdbHost, remoteAdbPort - imeStrategy, displayId, usePhysicalDisplayIdForScreenshot - screenshotResizeScale, alwaysFetchScreenInfo - autoDismissKeyboard, keyboardDismissStrategy iOS: - deviceId, useWDA, wdaPort, wdaHost - autoDismissKeyboard 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * test(yaml): add unit tests for device options propagation Add comprehensive unit tests to verify that all device options are correctly passed from YAML configuration to device constructors. Tests include: - Android device options propagation from YAML to agentFromAdbDevice - iOS device options propagation from YAML to agentFromWebDriverAgent - Type definitions for AndroidDeviceOpt and IOSDeviceOpt - YAML environment types (MidsceneYamlScriptAndroidEnv, MidsceneYamlScriptIOSEnv) - Validation that customActions is excluded from YAML types - IME strategy and keyboard dismiss strategy type validations - Minimal and full configuration scenarios All 31 tests passing (17 in CLI, 14 in Core). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix(android): ensure empty object is passed when opts is undefined Fix failing unit tests by ensuring an empty object is passed to AndroidDevice and IOSDevice constructors when opts is undefined, maintaining backward compatibility with existing tests. Changes: - Updated agentFromAdbDevice to pass opts || {} to AndroidDevice - Updated agentFromWebDriverAgent to pass opts || {} to IOSDevice This ensures the constructors always receive an object instead of undefined, which is what the existing tests expect. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix(device-options): rename alwaysFetchScreenInfo to alwaysRefreshScreenInfo for clarity * docs(site): update Android and iOS sections to include all configuration options from their respective constructors --------- Co-authored-by: Claude <[email protected]>
1 parent b10ad89 commit fd58ead

File tree

13 files changed

+567
-104
lines changed

13 files changed

+567
-104
lines changed

apps/chrome-extension/src/extension/bridge/index.less

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,61 +11,42 @@
1111
}
1212

1313
.server-config-section {
14-
margin-top: 16px;
15-
margin-bottom: 24px;
16-
padding: 12px 16px;
17-
background: #f8f9fa;
18-
border-radius: 8px;
19-
border: 1px solid #e9ecef;
14+
margin-top: 12px;
15+
margin-bottom: 20px;
2016

2117
.server-config-header {
2218
display: flex;
2319
align-items: center;
24-
gap: 8px;
20+
gap: 6px;
2521
cursor: pointer;
2622
user-select: none;
27-
padding: 4px 0;
23+
padding: 6px 0;
24+
transition: opacity 0.2s ease;
2825

2926
&:hover {
30-
.server-config-title {
31-
color: #1890ff;
32-
}
33-
34-
.server-config-arrow {
35-
color: #1890ff;
36-
}
27+
opacity: 0.7;
3728
}
3829
}
3930

4031
.server-config-arrow {
41-
font-size: 12px;
42-
color: #666;
32+
font-size: 10px;
33+
color: rgba(0, 0, 0, 0.45);
4334
transition: transform 0.2s ease;
35+
transform: rotate(-90deg);
4436

4537
&.expanded {
46-
transform: rotate(180deg);
38+
transform: rotate(0deg);
4739
}
4840
}
4941

5042
.server-config-title {
51-
font-weight: 500;
52-
font-size: 14px;
53-
color: #333;
54-
transition: color 0.2s ease;
43+
font-size: 13px;
44+
color: rgba(0, 0, 0, 0.65);
5545
}
5646

5747
.server-config-content {
5848
margin-top: 12px;
59-
padding-top: 12px;
60-
border-top: 1px solid #e9ecef;
61-
}
62-
63-
.server-config-label {
64-
display: block;
65-
margin-bottom: 8px;
66-
font-weight: 500;
67-
font-size: 14px;
68-
color: #333;
49+
padding-left: 16px;
6950
}
7051

7152
.server-config-input {
@@ -74,9 +55,9 @@
7455

7556
.server-config-hint {
7657
display: block;
77-
margin-top: 8px;
58+
margin-top: 6px;
7859
font-size: 12px;
79-
color: #666;
60+
color: rgba(0, 0, 0, 0.45);
8061
line-height: 1.5;
8162
}
8263
}
@@ -201,12 +182,6 @@
201182
font-style: italic;
202183
}
203184

204-
.bridge-log-container {
205-
}
206-
207-
.bridge-log-item {
208-
}
209-
210185
.bottom-button-container {
211186
position: absolute;
212187
bottom: 16px;

apps/site/docs/en/automate-with-scripts-in-yaml.mdx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,20 @@ android:
230230
231231
# The path to the JSON file for outputting aiQuery/aiAssert results, optional.
232232
output: <path-to-output-file>
233+
234+
# All other options supported by the AndroidDevice constructor
235+
# For example: androidAdbPath, remoteAdbHost, remoteAdbPort,
236+
# imeStrategy, displayId, autoDismissKeyboard, keyboardDismissStrategy,
237+
# screenshotResizeScale, alwaysRefreshScreenInfo, etc.
238+
# See the AndroidDevice constructor documentation for the complete list
233239
```
234240

241+
:::tip View Complete Android Configuration Options
242+
243+
YAML scripts now support all configuration options from the `AndroidDevice` constructor. For the complete list of options, please refer to [AndroidDevice Constructor in Android Integration Documentation](./integrate-with-android#androiddevice-constructor).
244+
245+
:::
246+
235247
### The `ios` part
236248

237249
```yaml
@@ -253,8 +265,15 @@ ios:
253265
254266
# Whether to save log content to a JSON file, optional, defaults to `false`. If true, saves to `unstableLogContent.json`. If a string, saves to the specified path. The log content structure may change in the future.
255267
unstableLogContent: <boolean | path-to-unstable-log-file>
268+
269+
# All other options supported by the IOSDevice constructor
270+
# See the IOSDevice constructor documentation for the complete list
256271
```
257272

273+
:::tip View Complete iOS Configuration Options
274+
YAML scripts now support all configuration options from the `IOSDevice` constructor. For the complete list of options, please refer to [IOSDevice Constructor in iOS Integration Documentation](./integrate-with-ios#iosdevice-constructor).
275+
:::
276+
258277
### The `tasks` part
259278

260279
The `tasks` part is an array that defines the steps of the script. Remember to add a `-` before each step to indicate it's an array item.

apps/site/docs/zh/automate-with-scripts-in-yaml.mdx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,20 @@ android:
230230
231231
# 输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选
232232
output: <path-to-output-file>
233+
234+
# 其他 AndroidDevice 构造函数支持的所有选项
235+
# 例如:androidAdbPath, remoteAdbHost, remoteAdbPort,
236+
# imeStrategy, displayId, autoDismissKeyboard, keyboardDismissStrategy,
237+
# screenshotResizeScale, alwaysRefreshScreenInfo 等
238+
# 完整配置项请参考 AndroidDevice 的构造函数文档
233239
```
234240

241+
:::tip 查看完整的 Android 配置项
242+
243+
YAML 脚本现在支持 `AndroidDevice` 构造函数的所有配置选项。完整的配置项列表请参考 [Android 集成文档中的 AndroidDevice 构造函数](./integrate-with-android#androiddevice-的构造函数)。
244+
245+
:::
246+
235247
### `ios` 部分
236248

237249
```yaml
@@ -253,8 +265,15 @@ ios:
253265
254266
# 是否保存日志内容到 JSON 文件,可选,默认 `false`。如果为 true,保存到 `unstableLogContent.json` 文件中。如果为字符串,则保存到该字符串指定的路径中。日志内容的结构可能会在未来发生变化。
255267
unstableLogContent: <boolean | path-to-unstable-log-file>
268+
269+
# 其他 IOSDevice 构造函数支持的所有选项
270+
# 完整配置项请参考 IOSDevice 的构造函数文档
256271
```
257272

273+
:::tip 查看完整的 iOS 配置项
274+
YAML 脚本现在支持 `IOSDevice` 构造函数的所有配置选项。完整的配置项列表请参考 [iOS 集成文档中的 IOSDevice 构造函数](./integrate-with-ios#iosdevice-的构造函数)
275+
:::
276+
258277
### `tasks` 部分
259278

260279
`tasks` 部分是一个数组,定义了脚本执行的步骤。记得在每个步骤前添加 `-` 符号,表明这些步骤是个数组。

packages/android/src/agent.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,8 @@ export async function agentFromAdbDevice(
3434
);
3535
}
3636

37-
const device = new AndroidDevice(deviceId, {
38-
autoDismissKeyboard: opts?.autoDismissKeyboard,
39-
androidAdbPath: opts?.androidAdbPath,
40-
remoteAdbHost: opts?.remoteAdbHost,
41-
remoteAdbPort: opts?.remoteAdbPort,
42-
imeStrategy: opts?.imeStrategy,
43-
displayId: opts?.displayId,
44-
usePhysicalDisplayIdForScreenshot: opts?.usePhysicalDisplayIdForScreenshot,
45-
usePhysicalDisplayIdForDisplayLookup:
46-
opts?.usePhysicalDisplayIdForDisplayLookup,
47-
screenshotResizeScale: opts?.screenshotResizeScale,
48-
alwaysRefreshScreenInfo: opts?.alwaysRefreshScreenInfo,
49-
});
37+
// Pass all device options to AndroidDevice constructor, ensuring we pass an empty object if opts is undefined
38+
const device = new AndroidDevice(deviceId, opts || {});
5039

5140
await device.connect();
5241

packages/android/src/device.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
import {
1515
type AbstractInterface,
1616
type ActionTapParam,
17+
type AndroidDeviceInputOpt,
18+
type AndroidDeviceOpt,
1719
defineAction,
1820
defineActionClearInput,
1921
defineActionDoubleClick,
@@ -41,37 +43,22 @@ import { repeat } from '@midscene/shared/utils';
4143

4244
import { ADB } from 'appium-adb';
4345

46+
// Re-export AndroidDeviceOpt and AndroidDeviceInputOpt for backward compatibility
47+
export type {
48+
AndroidDeviceOpt,
49+
AndroidDeviceInputOpt,
50+
} from '@midscene/core/device';
51+
4452
// only for Android, because it's impossible to scroll to the bottom, so we need to set a default scroll times
4553
const defaultScrollUntilTimes = 10;
4654
const defaultFastScrollDuration = 100;
4755
const defaultNormalScrollDuration = 1000;
4856

4957
const IME_STRATEGY_ALWAYS_YADB = 'always-yadb' as const;
5058
const IME_STRATEGY_YADB_FOR_NON_ASCII = 'yadb-for-non-ascii' as const;
51-
type ImeStrategy =
52-
| typeof IME_STRATEGY_ALWAYS_YADB
53-
| typeof IME_STRATEGY_YADB_FOR_NON_ASCII;
5459

5560
const debugDevice = getDebug('android:device');
5661

57-
export type AndroidDeviceInputOpt = {
58-
autoDismissKeyboard?: boolean;
59-
keyboardDismissStrategy?: 'esc-first' | 'back-first';
60-
};
61-
62-
export type AndroidDeviceOpt = {
63-
androidAdbPath?: string;
64-
remoteAdbHost?: string;
65-
remoteAdbPort?: number;
66-
imeStrategy?: ImeStrategy;
67-
displayId?: number;
68-
usePhysicalDisplayIdForScreenshot?: boolean;
69-
usePhysicalDisplayIdForDisplayLookup?: boolean;
70-
customActions?: DeviceAction<any>[];
71-
screenshotResizeScale?: number;
72-
alwaysRefreshScreenInfo?: boolean; // If true, always fetch screen size and orientation from device on each call; if false (default), cache the first result
73-
} & AndroidDeviceInputOpt;
74-
7562
export class AndroidDevice implements AbstractInterface {
7663
private deviceId: string;
7764
private yadbPushed = false;

packages/cli/src/create-yaml-player.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ export async function createYamlPlayer(
185185
if (typeof clonedYamlScript.android !== 'undefined') {
186186
const androidTarget = clonedYamlScript.android;
187187
const agent = await agentFromAdbDevice(androidTarget?.deviceId, {
188+
...androidTarget, // Pass all Android config options
188189
cache: processCacheConfig(yamlScript.agent?.cache, fileName),
189190
});
190191

@@ -204,8 +205,8 @@ export async function createYamlPlayer(
204205
if (typeof clonedYamlScript.ios !== 'undefined') {
205206
const iosTarget = clonedYamlScript.ios;
206207
const agent = await agentFromWebDriverAgent({
207-
wdaPort: iosTarget?.wdaPort,
208-
wdaHost: iosTarget?.wdaHost,
208+
...iosTarget, // Pass all iOS config options
209+
cache: processCacheConfig(yamlScript.agent?.cache, fileName),
209210
});
210211

211212
if (iosTarget?.launch) {

0 commit comments

Comments
 (0)