appium-xcuitest-driver 10.2.2 → 10.3.0
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/CHANGELOG.md +6 -0
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +0 -1
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/driver.js +1 -1
- package/build/lib/driver.js.map +1 -1
- package/build/lib/real-device.d.ts +1 -1
- package/build/lib/real-device.d.ts.map +1 -1
- package/build/lib/real-device.js +2 -2
- package/build/lib/real-device.js.map +1 -1
- package/lib/commands/memory.js +0 -1
- package/lib/driver.js +1 -1
- package/lib/real-device.js +2 -2
- package/npm-shrinkwrap.json +440 -76
- package/package.json +2 -1
- package/build/lib/real-device-clients/devicectl.d.ts +0 -204
- package/build/lib/real-device-clients/devicectl.d.ts.map +0 -1
- package/build/lib/real-device-clients/devicectl.js +0 -264
- package/build/lib/real-device-clients/devicectl.js.map +0 -1
- package/lib/real-device-clients/devicectl.js +0 -291
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
import {exec, SubProcess} from 'teen_process';
|
|
2
|
-
import {util} from 'appium/support';
|
|
3
|
-
import _ from 'lodash';
|
|
4
|
-
|
|
5
|
-
const XCRUN = 'xcrun';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {Object} ProcessInfo
|
|
9
|
-
* @property {number} processIdentifier
|
|
10
|
-
* @property {string} executable
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/*
|
|
14
|
-
Example:
|
|
15
|
-
{
|
|
16
|
-
"executable" : "file:///sbin/launchd",
|
|
17
|
-
"processIdentifier" : 1
|
|
18
|
-
},
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef {Object} AppInfo
|
|
23
|
-
* @property {boolean} appClip
|
|
24
|
-
* @property {boolean} builtByDeveloper
|
|
25
|
-
* @property {string} bundleIdentifier
|
|
26
|
-
* @property {string} bundleVersion
|
|
27
|
-
* @property {boolean} defaultApp
|
|
28
|
-
* @property {boolean} hidden
|
|
29
|
-
* @property {boolean} internalApp
|
|
30
|
-
* @property {string} name
|
|
31
|
-
* @property {boolean} removable
|
|
32
|
-
* @property {string} url
|
|
33
|
-
* @property {string} version
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/*
|
|
37
|
-
Example:
|
|
38
|
-
{
|
|
39
|
-
"appClip" : false,
|
|
40
|
-
"builtByDeveloper" : false,
|
|
41
|
-
"bundleIdentifier" : "com.apple.mobilesafari",
|
|
42
|
-
"bundleVersion" : "8617.1.17.10.9",
|
|
43
|
-
"defaultApp" : true,
|
|
44
|
-
"hidden" : false,
|
|
45
|
-
"internalApp" : false,
|
|
46
|
-
"name" : "Safari",
|
|
47
|
-
"removable" : false,
|
|
48
|
-
"url" : "file:///Applications/MobileSafari.app/",
|
|
49
|
-
"version" : "17.2"
|
|
50
|
-
}
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @typedef {Object} ExecuteOptions
|
|
55
|
-
* @property {boolean} [logStdout=false]
|
|
56
|
-
* @property {boolean} [asJson=true]
|
|
57
|
-
* @property {boolean} [asynchronous=false]
|
|
58
|
-
* @property {string[]|string} [subcommandOptions]
|
|
59
|
-
* @property {number} [timeout]
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @typedef {{asynchronous: true}} TAsyncOpts
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @typedef {Object} ListFilesOptions
|
|
68
|
-
* @property {string} [username] The username of the user we should target. Only relevant for certain domains.
|
|
69
|
-
* @property {string} [subdirectory] A subdirectory within the domain. If not specified, defaults to the root.
|
|
70
|
-
*/
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @typedef {Object} PullFileOptions
|
|
74
|
-
* @property {string} [username] The username of the user we should target. Only relevant for certain domains.
|
|
75
|
-
* @property {string} domainType The file service domain. Valid values are: temporary, rootStaging, appDataContainer, appGroupDataContainer,
|
|
76
|
-
* systemCrashLogs. You must specify a valid domain and identifier pair. Each domain is accompanied by an identifier
|
|
77
|
-
* that provides additional context. For example, if the domain is an app data container, the identifier is the bundle
|
|
78
|
-
* ID of the app. For temporary directories and root staging areas, the identifier is a unique client-provided string
|
|
79
|
-
* which is used to get your own space, separate from those of other clients.
|
|
80
|
-
* @property {string} domainIdentifier A unique string used to provide additional context to the domain.
|
|
81
|
-
* @property {number} [timeout=120000] The timeout for pulling a file in milliseconds.
|
|
82
|
-
*/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* An option for launchApp method by devicectl.
|
|
87
|
-
* @typedef {Object} LaunchAppOptions
|
|
88
|
-
* @property {import('@appium/types').StringRecord<string|number>} [env] Bundle id to Environment variables for the launching app process.
|
|
89
|
-
* @property {boolean} [terminateExisting=false] Whether terminating the already running app.
|
|
90
|
-
*/
|
|
91
|
-
|
|
92
|
-
export class Devicectl {
|
|
93
|
-
/**
|
|
94
|
-
* @since Xcode 15, iOS 17
|
|
95
|
-
* @param {string} udid
|
|
96
|
-
* @param {import('@appium/types').AppiumLogger} log
|
|
97
|
-
*/
|
|
98
|
-
constructor(udid, log) {
|
|
99
|
-
this.udid = udid;
|
|
100
|
-
this.log = log;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* @template {ExecuteOptions} TExecOpts
|
|
105
|
-
* @param {string[]} subcommand
|
|
106
|
-
* @param {TExecOpts} [opts]
|
|
107
|
-
* @return {Promise<TExecOpts extends TAsyncOpts ? import('teen_process').SubProcess : import('teen_process').TeenProcessExecResult>}
|
|
108
|
-
*/
|
|
109
|
-
async execute(subcommand, opts) {
|
|
110
|
-
const {
|
|
111
|
-
logStdout = false,
|
|
112
|
-
asynchronous = false,
|
|
113
|
-
asJson = true,
|
|
114
|
-
subcommandOptions,
|
|
115
|
-
timeout,
|
|
116
|
-
} = opts ?? {};
|
|
117
|
-
|
|
118
|
-
const finalArgs = [
|
|
119
|
-
'devicectl', ...subcommand,
|
|
120
|
-
'--device', this.udid,
|
|
121
|
-
];
|
|
122
|
-
if (subcommandOptions && !_.isEmpty(subcommandOptions)) {
|
|
123
|
-
finalArgs.push(
|
|
124
|
-
...(Array.isArray(subcommandOptions) ? subcommandOptions : [subcommandOptions])
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
if (asJson) {
|
|
128
|
-
finalArgs.push('--quiet', '--json-output', '-');
|
|
129
|
-
}
|
|
130
|
-
const cmdStr = util.quote([XCRUN, ...finalArgs]);
|
|
131
|
-
this.log.debug(`Executing ${cmdStr}`);
|
|
132
|
-
try {
|
|
133
|
-
if (asynchronous) {
|
|
134
|
-
const result = new SubProcess(XCRUN, finalArgs);
|
|
135
|
-
await result.start(0);
|
|
136
|
-
// @ts-ignore TS does not understand it
|
|
137
|
-
return result;
|
|
138
|
-
}
|
|
139
|
-
const result = await exec(
|
|
140
|
-
XCRUN,
|
|
141
|
-
finalArgs,
|
|
142
|
-
...(_.isNumber(timeout) ? [{timeout}] : []),
|
|
143
|
-
);
|
|
144
|
-
if (logStdout) {
|
|
145
|
-
this.log.debug(`Command output: ${result.stdout}`);
|
|
146
|
-
}
|
|
147
|
-
// @ts-ignore TS does not understand it
|
|
148
|
-
return result;
|
|
149
|
-
} catch (e) {
|
|
150
|
-
throw new Error(`'${cmdStr}' failed. Original error: ${e.stderr || e.stdout || e.message}`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Simulates memory warning for the process with the given PID
|
|
156
|
-
*
|
|
157
|
-
* @param {number|string} pid The process identifier to simulate the Low Memory warning for
|
|
158
|
-
* @return {Promise<void>}
|
|
159
|
-
*/
|
|
160
|
-
async sendMemoryWarning(pid) {
|
|
161
|
-
await this.execute(['device', 'process', 'sendMemoryWarning'], {
|
|
162
|
-
subcommandOptions: ['--pid', `${pid}`]
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Lists running processes on the device
|
|
168
|
-
*
|
|
169
|
-
* @returns {Promise<ProcessInfo[]>}
|
|
170
|
-
*/
|
|
171
|
-
async listProcesses() {
|
|
172
|
-
const {stdout} = await this.execute(['device', 'info', 'processes']);
|
|
173
|
-
return JSON.parse(stdout).result.runningProcesses;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Lists files at a specified path on the device
|
|
178
|
-
*
|
|
179
|
-
* @param {string} domainType The file service domain. Valid values are: temporary, rootStaging, appDataContainer, appGroupDataContainer,
|
|
180
|
-
* systemCrashLogs. You must specify a valid domain and identifier pair. Each domain is accompanied by an identifier
|
|
181
|
-
* that provides additional context. For example, if the domain is an app data container, the identifier is the bundle
|
|
182
|
-
* ID of the app. For temporary directories and root staging areas, the identifier is a unique client-provided string
|
|
183
|
-
* which is used to get your own space, separate from those of other clients.
|
|
184
|
-
* @param {string} domainIdentifier A unique string used to provide additional context to the domain.
|
|
185
|
-
* @param {ListFilesOptions} [opts={}]
|
|
186
|
-
* @returns {Promise<string[]>} List of file names (could be empty)
|
|
187
|
-
*/
|
|
188
|
-
async listFiles(domainType, domainIdentifier, opts = {}) {
|
|
189
|
-
const subcommandOptions = [
|
|
190
|
-
'--domain-type', domainType,
|
|
191
|
-
'--domain-identifier', domainIdentifier,
|
|
192
|
-
];
|
|
193
|
-
if (opts.username) {
|
|
194
|
-
subcommandOptions.push('--username', opts.username);
|
|
195
|
-
}
|
|
196
|
-
if (opts.subdirectory) {
|
|
197
|
-
subcommandOptions.push('--subdirectory', opts.subdirectory);
|
|
198
|
-
}
|
|
199
|
-
const {stdout} = await this.execute(['device', 'info', 'files'], {
|
|
200
|
-
subcommandOptions,
|
|
201
|
-
});
|
|
202
|
-
return JSON.parse(stdout).result.files.map(({name}) => name);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Pulls a file from the specified path on the device to a local file system
|
|
207
|
-
*
|
|
208
|
-
* @param {string} from The item which should be copied.
|
|
209
|
-
* @param {string} to The location to which the item should be copied.
|
|
210
|
-
* @param {PullFileOptions} opts
|
|
211
|
-
* @returns {Promise<string>} The destination path (same as `to`)
|
|
212
|
-
*/
|
|
213
|
-
async pullFile(from, to, opts) {
|
|
214
|
-
const subcommandOptions = [
|
|
215
|
-
'--domain-type', opts.domainType,
|
|
216
|
-
'--domain-identifier', opts.domainIdentifier,
|
|
217
|
-
'--source', from,
|
|
218
|
-
'--destination', to,
|
|
219
|
-
];
|
|
220
|
-
if (opts.username) {
|
|
221
|
-
subcommandOptions.push('--user', opts.username);
|
|
222
|
-
}
|
|
223
|
-
await this.execute(['device', 'copy', 'from'], {
|
|
224
|
-
subcommandOptions,
|
|
225
|
-
timeout: opts.timeout ?? 120000,
|
|
226
|
-
asJson: false,
|
|
227
|
-
});
|
|
228
|
-
return to;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Send POSIX signal to the running process
|
|
233
|
-
*
|
|
234
|
-
* @param {number|string} pid The process identifier to send a signal to
|
|
235
|
-
* @param {number|string} signal The signal to send to a process. See 'man signal' for a list of signals
|
|
236
|
-
* @returns {Promise<void>}
|
|
237
|
-
*/
|
|
238
|
-
async sendSignalToProcess(pid, signal) {
|
|
239
|
-
await this.execute(['device', 'process', 'signal'], {
|
|
240
|
-
subcommandOptions: ['--signal', `${signal}`, '--pid', `${pid}`]
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Retrieves the list of installed apps from the device
|
|
246
|
-
*
|
|
247
|
-
* @param {string?} [bundleId=null] Provide the target bundle identifier
|
|
248
|
-
* to speed up the lookup.
|
|
249
|
-
* @returns {Promise<AppInfo[]>} Empty array is returned if no matching apps are found
|
|
250
|
-
*/
|
|
251
|
-
async listApps(bundleId = null) {
|
|
252
|
-
const subcommandOptions = ['--include-all-apps'];
|
|
253
|
-
if (bundleId) {
|
|
254
|
-
subcommandOptions.push('--bundle-id', bundleId);
|
|
255
|
-
}
|
|
256
|
-
const {stdout} = await this.execute(['device', 'info', 'apps'], {
|
|
257
|
-
subcommandOptions,
|
|
258
|
-
});
|
|
259
|
-
return JSON.parse(stdout).result.apps;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Launch the given bundle id application with the given environment variable.
|
|
264
|
-
* This method is over devicectl command, this it may take additional seconds to launch the app.
|
|
265
|
-
* Please use via WDA or via appium-ios-device as primary method to launch app if possible.
|
|
266
|
-
*
|
|
267
|
-
* @param {string} bundleId Bundle id to launch.
|
|
268
|
-
* @param {LaunchAppOptions} opts launching app with devicectl command options.
|
|
269
|
-
* @returns {Promise<void>}
|
|
270
|
-
* @throws {Error} If the launching app command fails. For example, the given bundle id did not exist.
|
|
271
|
-
*/
|
|
272
|
-
async launchApp(bundleId, opts) {
|
|
273
|
-
const {
|
|
274
|
-
env,
|
|
275
|
-
terminateExisting = false
|
|
276
|
-
} = opts;
|
|
277
|
-
|
|
278
|
-
const subcommandOptions = [];
|
|
279
|
-
if (terminateExisting) {
|
|
280
|
-
subcommandOptions.push('--terminate-existing');
|
|
281
|
-
};
|
|
282
|
-
if (!_.isEmpty(env)) {
|
|
283
|
-
subcommandOptions.push('--environment-variables', JSON.stringify(_.mapValues(env, (v) => _.toString(v))));
|
|
284
|
-
};
|
|
285
|
-
// The bundle id should be the last to apply arguments properly.
|
|
286
|
-
// devicectl command might not raise exception while the order is wrong.
|
|
287
|
-
subcommandOptions.push(bundleId);
|
|
288
|
-
|
|
289
|
-
await this.execute(['device', 'process', 'launch'], { subcommandOptions, asJson: false});
|
|
290
|
-
}
|
|
291
|
-
}
|