android-midscene-automation 0.1.6 → 0.1.9
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/README.md +8 -10
- package/package.json +3 -3
- package/server/appium-recorder/appium-runner.ts +362 -26
- package/server/appium-recorder/repository.ts +89 -12
- package/src/appium-recorder/AppiumPage.vue +504 -124
- package/src/appium-recorder/components/ComponentTree.vue +14 -1
- package/src/appium-recorder/components/NodeDetail.vue +24 -118
- package/src/appium-recorder/components/RecordedSteps.vue +898 -36
- package/src/appium-recorder/tree.ts +55 -9
- package/src/appium-recorder/types.ts +33 -1
- package/src/style.css +659 -11
|
@@ -39,6 +39,19 @@ watch(
|
|
|
39
39
|
highlight-current
|
|
40
40
|
default-expand-all
|
|
41
41
|
@node-click="$emit('select', $event)"
|
|
42
|
-
|
|
42
|
+
>
|
|
43
|
+
<template #default="{ data }">
|
|
44
|
+
<span class="appium-tree-node">
|
|
45
|
+
<span class="appium-tree-node__label">{{ data.label }}</span>
|
|
46
|
+
<span
|
|
47
|
+
v-if="data.selector?.matchCount"
|
|
48
|
+
class="appium-tree-node__badge"
|
|
49
|
+
:class="{ 'appium-tree-node__badge--duplicate': data.selector.matchCount > 1 }"
|
|
50
|
+
>
|
|
51
|
+
{{ data.selector.matchCount > 1 ? `重复 ${data.selector.matchCount}` : '唯一' }}
|
|
52
|
+
</span>
|
|
53
|
+
</span>
|
|
54
|
+
</template>
|
|
55
|
+
</el-tree>
|
|
43
56
|
</div>
|
|
44
57
|
</template>
|
|
@@ -1,97 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { AppiumNode } from '../types';
|
|
3
|
-
import tapIcon from '../../assets/appium-actions/crosshair.svg';
|
|
4
|
-
import inputIcon from '../../assets/appium-actions/text.svg';
|
|
5
|
-
import assertIcon from '../../assets/appium-actions/select.svg';
|
|
6
|
-
import backIcon from '../../assets/appium-actions/back.svg';
|
|
7
|
-
import homeIcon from '../../assets/appium-actions/phone.svg';
|
|
8
|
-
import activityIcon from '../../assets/appium-actions/browser.svg';
|
|
9
|
-
import swipeIcon from '../../assets/appium-actions/bidirection.svg';
|
|
10
|
-
import clearIcon from '../../assets/appium-actions/clear.svg';
|
|
11
|
-
import coordinateIcon from '../../assets/appium-actions/pin.svg';
|
|
12
|
-
import launchIcon from '../../assets/appium-actions/android.svg';
|
|
13
|
-
import disappearIcon from '../../assets/appium-actions/eye.svg';
|
|
14
|
-
import powerIcon from '../../assets/appium-actions/power.svg';
|
|
15
|
-
import tasksIcon from '../../assets/appium-actions/sidebar.svg';
|
|
16
|
-
import longPressIcon from '../../assets/appium-actions/pin.svg';
|
|
17
|
-
import pinchIcon from '../../assets/appium-actions/zoom.svg';
|
|
18
|
-
import delayIcon from '../../assets/appium-actions/pause.svg';
|
|
19
|
-
import addIcon from '../../assets/appium-actions/add.svg';
|
|
20
|
-
|
|
21
|
-
type RecorderAction =
|
|
22
|
-
| 'delay'
|
|
23
|
-
| 'tap'
|
|
24
|
-
| 'input'
|
|
25
|
-
| 'assertExists'
|
|
26
|
-
| 'keyBack'
|
|
27
|
-
| 'keyHome'
|
|
28
|
-
| 'keyRecent'
|
|
29
|
-
| 'keyPower'
|
|
30
|
-
| 'waitActivity'
|
|
31
|
-
| 'swipe'
|
|
32
|
-
| 'clearInput'
|
|
33
|
-
| 'coordinateTap'
|
|
34
|
-
| 'launchApp'
|
|
35
|
-
| 'waitDisappear'
|
|
36
|
-
| 'assertText'
|
|
37
|
-
| 'longPress'
|
|
38
|
-
| 'pinch';
|
|
39
|
-
|
|
40
|
-
type ActionItem = {
|
|
41
|
-
type: RecorderAction;
|
|
42
|
-
label: string;
|
|
43
|
-
icon: string;
|
|
44
|
-
requiresNode: boolean;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const actionGroups: Array<{ title: string; actions: ActionItem[] }> = [
|
|
48
|
-
{
|
|
49
|
-
title: '组件操作',
|
|
50
|
-
actions: [
|
|
51
|
-
{ type: 'tap', label: '录制点击', icon: tapIcon, requiresNode: true },
|
|
52
|
-
{ type: 'input', label: '录制输入', icon: inputIcon, requiresNode: true },
|
|
53
|
-
{ type: 'clearInput', label: '清空输入', icon: clearIcon, requiresNode: true },
|
|
54
|
-
{ type: 'coordinateTap', label: '点击坐标', icon: coordinateIcon, requiresNode: true },
|
|
55
|
-
{ type: 'longPress', label: '长按', icon: longPressIcon, requiresNode: true },
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
title: '设备操作',
|
|
60
|
-
actions: [
|
|
61
|
-
{ type: 'keyBack', label: '返回键', icon: backIcon, requiresNode: false },
|
|
62
|
-
{ type: 'keyHome', label: 'Home 键', icon: homeIcon, requiresNode: false },
|
|
63
|
-
{ type: 'keyRecent', label: '最近任务', icon: tasksIcon, requiresNode: false },
|
|
64
|
-
{ type: 'keyPower', label: '电源键', icon: powerIcon, requiresNode: false },
|
|
65
|
-
{ type: 'swipe', label: '滑动', icon: swipeIcon, requiresNode: false },
|
|
66
|
-
{ type: 'pinch', label: '双指缩放', icon: pinchIcon, requiresNode: false },
|
|
67
|
-
{ type: 'launchApp', label: '启动 App', icon: launchIcon, requiresNode: false },
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
title: '等待断言',
|
|
72
|
-
actions: [
|
|
73
|
-
{ type: 'delay', label: '添加延时', icon: delayIcon, requiresNode: false },
|
|
74
|
-
{ type: 'assertExists', label: '断言存在', icon: assertIcon, requiresNode: true },
|
|
75
|
-
{ type: 'assertText', label: '断言文本', icon: inputIcon, requiresNode: true },
|
|
76
|
-
{ type: 'waitDisappear', label: '等待元素消失', icon: disappearIcon, requiresNode: true },
|
|
77
|
-
{ type: 'waitActivity', label: '等待 Activity', icon: activityIcon, requiresNode: false },
|
|
78
|
-
],
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
3
|
|
|
82
4
|
defineProps<{
|
|
83
5
|
node: AppiumNode | null;
|
|
84
|
-
|
|
6
|
+
currentActivity?: string;
|
|
85
7
|
loading?: boolean;
|
|
86
8
|
}>();
|
|
87
|
-
|
|
88
|
-
const emit = defineEmits<{
|
|
89
|
-
addAction: [type: RecorderAction];
|
|
90
|
-
}>();
|
|
91
|
-
|
|
92
|
-
function selectAction(command: string | number | object) {
|
|
93
|
-
emit('addAction', command as RecorderAction);
|
|
94
|
-
}
|
|
95
9
|
</script>
|
|
96
10
|
|
|
97
11
|
<template>
|
|
@@ -107,7 +21,29 @@ function selectAction(command: string | number | object) {
|
|
|
107
21
|
<el-descriptions-item label="content-desc">{{ node.contentDesc || '-' }}</el-descriptions-item>
|
|
108
22
|
<el-descriptions-item label="text">{{ node.text || '-' }}</el-descriptions-item>
|
|
109
23
|
<el-descriptions-item label="class">{{ node.className || '-' }}</el-descriptions-item>
|
|
110
|
-
<el-descriptions-item label="
|
|
24
|
+
<el-descriptions-item label="当前 Activity">{{ currentActivity || '-' }}</el-descriptions-item>
|
|
25
|
+
<el-descriptions-item label="selector">
|
|
26
|
+
<span v-if="currentActivity">Activity {{ currentActivity }} · </span>
|
|
27
|
+
{{ node.selector.strategy }} {{ node.selector.value || '' }}
|
|
28
|
+
<el-tag
|
|
29
|
+
v-if="node.selector.matchCount"
|
|
30
|
+
size="small"
|
|
31
|
+
:type="node.selector.matchCount > 1 ? 'warning' : 'success'"
|
|
32
|
+
>
|
|
33
|
+
{{ node.selector.matchCount > 1 ? `重复 ${node.selector.matchCount}` : '唯一' }}
|
|
34
|
+
</el-tag>
|
|
35
|
+
</el-descriptions-item>
|
|
36
|
+
<el-descriptions-item label="推荐定位">
|
|
37
|
+
<span v-if="node.contextSelector">
|
|
38
|
+
<template v-if="currentActivity">Activity {{ currentActivity }} + </template>
|
|
39
|
+
父级 {{ node.contextSelector.strategy }} {{ node.contextSelector.value || '' }}
|
|
40
|
+
+ 子级 {{ node.selector.strategy }} {{ node.selector.value || '' }}
|
|
41
|
+
</span>
|
|
42
|
+
<span v-else>
|
|
43
|
+
<template v-if="currentActivity">Activity {{ currentActivity }} + </template>
|
|
44
|
+
{{ node.selector.unique ? '当前 selector 唯一' : '使用当前 selector 或坐标兜底' }}
|
|
45
|
+
</span>
|
|
46
|
+
</el-descriptions-item>
|
|
111
47
|
<el-descriptions-item label="bounds">
|
|
112
48
|
<span v-if="node.bounds">
|
|
113
49
|
[{{ node.bounds.left }},{{ node.bounds.top }}][{{ node.bounds.right }},{{ node.bounds.bottom }}]
|
|
@@ -118,35 +54,5 @@ function selectAction(command: string | number | object) {
|
|
|
118
54
|
</template>
|
|
119
55
|
<el-empty v-else description="请选择组件" />
|
|
120
56
|
|
|
121
|
-
<el-dropdown
|
|
122
|
-
trigger="click"
|
|
123
|
-
:disabled="disabled"
|
|
124
|
-
max-height="320px"
|
|
125
|
-
popper-class="appium-action-dropdown"
|
|
126
|
-
@command="selectAction"
|
|
127
|
-
>
|
|
128
|
-
<el-button class="appium-action-trigger" :disabled="disabled">
|
|
129
|
-
<img :src="addIcon" alt="" class="appium-action-trigger__icon" />
|
|
130
|
-
添加操作
|
|
131
|
-
</el-button>
|
|
132
|
-
<template #dropdown>
|
|
133
|
-
<el-dropdown-menu>
|
|
134
|
-
<template v-for="group in actionGroups" :key="group.title">
|
|
135
|
-
<div class="appium-action-dropdown__group">{{ group.title }}</div>
|
|
136
|
-
<el-dropdown-item
|
|
137
|
-
v-for="action in group.actions"
|
|
138
|
-
:key="action.type"
|
|
139
|
-
:command="action.type"
|
|
140
|
-
:disabled="action.requiresNode && !node"
|
|
141
|
-
>
|
|
142
|
-
<span class="appium-action-dropdown__item">
|
|
143
|
-
<img :src="action.icon" :alt="action.label" />
|
|
144
|
-
<span>{{ action.label }}</span>
|
|
145
|
-
</span>
|
|
146
|
-
</el-dropdown-item>
|
|
147
|
-
</template>
|
|
148
|
-
</el-dropdown-menu>
|
|
149
|
-
</template>
|
|
150
|
-
</el-dropdown>
|
|
151
57
|
</div>
|
|
152
58
|
</template>
|