appium-xcuitest-driver 7.1.2 → 7.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 +24 -0
- package/build/lib/app-utils.js.map +1 -1
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +2 -2
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +4 -1
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +41 -49
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/deviceInfo.js.map +1 -1
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-movement.js.map +1 -1
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/gesture.js.map +1 -1
- package/build/lib/commands/index.d.ts +2 -0
- package/build/lib/commands/index.d.ts.map +1 -1
- package/build/lib/commands/index.js +2 -0
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/iohid.js.map +1 -1
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/lock.js.map +1 -1
- package/build/lib/commands/log.js +1 -1
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/navigation.js.map +1 -1
- package/build/lib/commands/notifications.js.map +1 -1
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/proxy-helper.js.map +1 -1
- package/build/lib/commands/record-audio.js.map +1 -1
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/source.js.map +1 -1
- package/build/lib/commands/timeouts.js.map +1 -1
- package/build/lib/commands/web.d.ts.map +1 -1
- package/build/lib/commands/web.js +11 -8
- package/build/lib/commands/web.js.map +1 -1
- package/build/lib/commands/xctest-record-screen.d.ts +94 -0
- package/build/lib/commands/xctest-record-screen.d.ts.map +1 -0
- package/build/lib/commands/xctest-record-screen.js +193 -0
- package/build/lib/commands/xctest-record-screen.js.map +1 -0
- package/build/lib/commands/xctest.js.map +1 -1
- package/build/lib/cookies.js.map +1 -1
- package/build/lib/css-converter.js.map +1 -1
- package/build/lib/desired-caps.d.ts +12 -8
- package/build/lib/desired-caps.d.ts.map +1 -1
- package/build/lib/desired-caps.js +3 -0
- package/build/lib/desired-caps.js.map +1 -1
- package/build/lib/device-connections-factory.js.map +1 -1
- package/build/lib/device-log/ios-crash-log.js.map +1 -1
- package/build/lib/device-log/ios-device-log.js.map +1 -1
- package/build/lib/device-log/ios-log.d.ts +1 -1
- package/build/lib/device-log/ios-log.js.map +1 -1
- package/build/lib/device-log/ios-performance-log.js.map +1 -1
- package/build/lib/device-log/ios-simulator-log.js.map +1 -1
- package/build/lib/device-log/rotating-log.d.ts +1 -1
- package/build/lib/device-log/rotating-log.d.ts.map +1 -1
- package/build/lib/device-log/rotating-log.js.map +1 -1
- package/build/lib/device-log/safari-console-log.js.map +1 -1
- package/build/lib/device-log/safari-network-log.js.map +1 -1
- package/build/lib/devicectl.d.ts +72 -0
- package/build/lib/devicectl.d.ts.map +1 -1
- package/build/lib/devicectl.js +72 -2
- package/build/lib/devicectl.js.map +1 -1
- package/build/lib/doctor/optional-checks.js.map +1 -1
- package/build/lib/doctor/required-checks.js.map +1 -1
- package/build/lib/doctor/utils.js.map +1 -1
- package/build/lib/driver.d.ts +44 -23
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +12 -6
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts +15 -0
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +15 -0
- package/build/lib/execute-method-map.js.map +1 -1
- package/build/lib/ios-deploy.js.map +1 -1
- package/build/lib/ios-fs-helpers.js.map +1 -1
- package/build/lib/py-ios-device-client.js.map +1 -1
- package/build/lib/real-device-management.js.map +1 -1
- package/build/lib/simulator-management.js.map +1 -1
- package/build/lib/utils.js.map +1 -1
- package/build/lib/xcrun.js.map +1 -1
- package/lib/commands/app-management.js +4 -1
- package/lib/commands/context.js +40 -52
- package/lib/commands/index.js +2 -0
- package/lib/commands/log.js +1 -1
- package/lib/commands/web.js +4 -1
- package/lib/commands/xctest-record-screen.js +206 -0
- package/lib/desired-caps.js +3 -0
- package/lib/devicectl.js +76 -1
- package/lib/driver.js +9 -2
- package/lib/execute-method-map.ts +15 -0
- package/npm-shrinkwrap.json +49 -47
- package/package.json +3 -3
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {fs, util} from 'appium/support';
|
|
3
|
+
import {encodeBase64OrUpload} from '../utils';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {Devicectl} from '../devicectl';
|
|
6
|
+
|
|
7
|
+
const MOV_EXT = '.mov';
|
|
8
|
+
const FEATURE_NAME = 'xctest_screen_record';
|
|
9
|
+
const DOMAIN_IDENTIFIER = 'com.apple.testmanagerd';
|
|
10
|
+
const DOMAIN_TYPE = 'appDataContainer';
|
|
11
|
+
const USERNAME = 'mobile';
|
|
12
|
+
const SUBDIRECTORY = 'Attachments';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} XcTestScreenRecordingInfo
|
|
16
|
+
* @property {string} uuid Unique identifier of the video being recorded
|
|
17
|
+
* @property {number} fps FPS value
|
|
18
|
+
* @property {number} codec Video codec, where 0 is h264
|
|
19
|
+
* @property {number} startedAt The timestamp when the screen recording has started in float Unix seconds
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} XcTestScreenRecordingType
|
|
24
|
+
* @property {string} payload Base64-encoded content of the recorded media
|
|
25
|
+
* file if `remotePath` parameter is empty or null or an empty string otherwise.
|
|
26
|
+
* The media is expected to a be a valid QuickTime movie (.mov).
|
|
27
|
+
* @typedef {XcTestScreenRecordingInfo & XcTestScreenRecordingType} XcTestScreenRecording
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @this {XCUITestDriver}
|
|
32
|
+
* @param {string} uuid Unique identifier of the video being recorded
|
|
33
|
+
* @returns {Promise<string>} The full path to the screen recording movie
|
|
34
|
+
*/
|
|
35
|
+
async function retrieveRecodingFromSimulator(uuid) {
|
|
36
|
+
// @ts-ignore The property is there
|
|
37
|
+
const device = this.opts.device;
|
|
38
|
+
const dataRoot = /** @type {string} */ (device.getDir());
|
|
39
|
+
// On Simulators the path looks like
|
|
40
|
+
// $HOME/Library/Developer/CoreSimulator/Devices/F8E1968A-8443-4A9A-AB86-27C54C36A2F6/data/Containers/Data/InternalDaemon/4E3FE8DF-AD0A-41DA-B6EC-C35E5798C219/Attachments/A044DAF7-4A58-4CD5-95C3-29B4FE80C377
|
|
41
|
+
const internalDaemonRoot = path.resolve(dataRoot, 'Containers', 'Data', 'InternalDaemon');
|
|
42
|
+
const videoPaths = await fs.glob(`*/Attachments/${uuid}`, {
|
|
43
|
+
cwd: internalDaemonRoot,
|
|
44
|
+
absolute: true,
|
|
45
|
+
});
|
|
46
|
+
if (_.isEmpty(videoPaths)) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Unable to locate XCTest screen recording identified by '${uuid}' for the Simulator ${device.udid}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const videoPath = videoPaths[0];
|
|
52
|
+
const {size} = await fs.stat(videoPath);
|
|
53
|
+
this.log.debug(`Located the video at '${videoPath}' (${util.toReadableSizeString(size)})`);
|
|
54
|
+
return videoPath;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @this {XCUITestDriver}
|
|
59
|
+
* @param {string} uuid Unique identifier of the video being recorded
|
|
60
|
+
* @returns {Promise<string>} The full path to the screen recording movie
|
|
61
|
+
*/
|
|
62
|
+
async function retrieveRecodingFromRealDevice(uuid) {
|
|
63
|
+
const devicectl = new Devicectl(this.opts.udid, this.log);
|
|
64
|
+
const fileNames = await devicectl.listFiles(DOMAIN_TYPE, DOMAIN_IDENTIFIER, {
|
|
65
|
+
username: USERNAME,
|
|
66
|
+
subdirectory: SUBDIRECTORY,
|
|
67
|
+
});
|
|
68
|
+
if (!fileNames.includes(uuid)) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Unable to locate XCTest screen recording identified by '${uuid}' for the device ${this.opts.udid}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const videoPath = path.join(/** @type {string} */ (this.opts.tmpDir), `${uuid}${MOV_EXT}`);
|
|
74
|
+
await devicectl.pullFile(`${SUBDIRECTORY}/${uuid}`, videoPath, {
|
|
75
|
+
username: USERNAME,
|
|
76
|
+
domainIdentifier: DOMAIN_IDENTIFIER,
|
|
77
|
+
domainType: DOMAIN_TYPE,
|
|
78
|
+
});
|
|
79
|
+
const {size} = await fs.stat(videoPath);
|
|
80
|
+
this.log.debug(`Pulled the video to '${videoPath}' (${util.toReadableSizeString(size)})`);
|
|
81
|
+
return videoPath;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @this {XCUITestDriver}
|
|
86
|
+
* @param {string} uuid Unique identifier of the video being recorded
|
|
87
|
+
* @returns {Promise<string>} The full path to the screen recording movie
|
|
88
|
+
*/
|
|
89
|
+
async function retrieveXcTestScreenRecording(uuid) {
|
|
90
|
+
return this.isRealDevice()
|
|
91
|
+
? await retrieveRecodingFromRealDevice.bind(this)(uuid)
|
|
92
|
+
: await retrieveRecodingFromSimulator.bind(this)(uuid);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default {
|
|
96
|
+
/**
|
|
97
|
+
* Start a new screen recording via XCTest.
|
|
98
|
+
*
|
|
99
|
+
* Even though the feature is available for real devices
|
|
100
|
+
* there is no possibility to delete stored video files yet,
|
|
101
|
+
* which may lead to internal storage overload.
|
|
102
|
+
* That is why it was put under a security feature flag.
|
|
103
|
+
*
|
|
104
|
+
* If the recording is already running this API is a noop.
|
|
105
|
+
*
|
|
106
|
+
* @since Xcode 15/iOS 17
|
|
107
|
+
* @param {number} [fps] FPS value
|
|
108
|
+
* @param {number} [codec] Video codec, where 0 is h264, 1 is HEVC
|
|
109
|
+
* @returns {Promise<XcTestScreenRecordingInfo>} The information
|
|
110
|
+
* about a newly created or a running the screen recording.
|
|
111
|
+
* @throws {Error} If screen recording has failed to start.
|
|
112
|
+
* @this {XCUITestDriver}
|
|
113
|
+
*/
|
|
114
|
+
async mobileStartXctestScreenRecording(fps, codec) {
|
|
115
|
+
if (this.isRealDevice()) {
|
|
116
|
+
// This feature might be used to abuse real devices as there is no
|
|
117
|
+
// reliable way (yet) to cleanup video recordings stored there
|
|
118
|
+
// by the testmanagerd daemon
|
|
119
|
+
this.assertFeatureEnabled(FEATURE_NAME);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const opts = {};
|
|
123
|
+
if (_.isInteger(codec)) {
|
|
124
|
+
opts.codec = codec;
|
|
125
|
+
}
|
|
126
|
+
if (_.isInteger(fps)) {
|
|
127
|
+
opts.fps = fps;
|
|
128
|
+
}
|
|
129
|
+
const response = /** @type {XcTestScreenRecordingInfo} */ (
|
|
130
|
+
await this.proxyCommand('/wda/video/start', 'POST', opts)
|
|
131
|
+
);
|
|
132
|
+
this.log.info(`Started a new screen recording: ${JSON.stringify(response)}`);
|
|
133
|
+
return response;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Retrieves information about the current running screen recording.
|
|
138
|
+
* If no screen recording is running then `null` is returned.
|
|
139
|
+
*
|
|
140
|
+
* @returns {Promise<XcTestScreenRecordingInfo?>}
|
|
141
|
+
*/
|
|
142
|
+
async mobileGetXctestScreenRecordingInfo() {
|
|
143
|
+
return /** @type {XcTestScreenRecordingInfo?} */ (
|
|
144
|
+
await this.proxyCommand('/wda/video', 'GET')
|
|
145
|
+
);
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Stop screen recording previously started by mobileStartXctestScreenRecording API.
|
|
150
|
+
*
|
|
151
|
+
* An error is thrown if no screen recording is running.
|
|
152
|
+
*
|
|
153
|
+
* The resulting movie is returned as base-64 string or is uploaded to
|
|
154
|
+
* a remote location if corresponding options have been provided.
|
|
155
|
+
*
|
|
156
|
+
* The resulting movie is automatically deleted FOR SIMULATORS ONLY.
|
|
157
|
+
* In order to clean it up from a real device it is necessary to properly
|
|
158
|
+
* shut down XCTest by calling `POST /wda/shutdown` API or by doing factory reset.
|
|
159
|
+
*
|
|
160
|
+
* @since Xcode 15/iOS 17
|
|
161
|
+
* @param {string} [remotePath] The path to the remote location, where the resulting video should be
|
|
162
|
+
* uploaded.
|
|
163
|
+
* The following protocols are supported: `http`, `https`, `ftp`. Null or empty
|
|
164
|
+
* string value (the default setting) means the content of resulting file
|
|
165
|
+
* should be encoded as Base64 and passed as the endpoint response value. An
|
|
166
|
+
* exception will be thrown if the generated media file is too big to fit into
|
|
167
|
+
* the available process memory.
|
|
168
|
+
* @param {string} [user] The name of the user for the remote authentication.
|
|
169
|
+
* Only works if `remotePath` is provided.
|
|
170
|
+
* @param {string} [pass] The password for the remote authentication.
|
|
171
|
+
* Only works if `remotePath` is provided.
|
|
172
|
+
* @param {import('@appium/types').HTTPHeaders} [headers] Additional headers mapping for multipart http(s) uploads
|
|
173
|
+
* @param {string} [fileFieldName] The name of the form field where the file content BLOB should be stored for
|
|
174
|
+
* http(s) uploads
|
|
175
|
+
* @param {Record<string, any> | [string, any][]} [formFields] Additional form fields for multipart http(s) uploads
|
|
176
|
+
* @param {'PUT' | 'POST' | 'PATCH'} [method='PUT'] The http multipart upload method name.
|
|
177
|
+
* Only works if `remotePath` is provided.
|
|
178
|
+
* @returns {Promise<XcTestScreenRecording>}
|
|
179
|
+
* @throws {Error} If there was an error while retrieving the video
|
|
180
|
+
* file or the file content cannot be uploaded to the remote location.
|
|
181
|
+
* @this {XCUITestDriver}
|
|
182
|
+
*/
|
|
183
|
+
async mobileStopXctestScreenRecording(remotePath, user, pass, headers, fileFieldName, formFields, method) {
|
|
184
|
+
const screenRecordingInfo = await this.mobileGetXctestScreenRecordingInfo();
|
|
185
|
+
if (!screenRecordingInfo) {
|
|
186
|
+
throw new Error('There is no active screen recording. Did you start one beforehand?');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.log.debug(`Stopping the active screen recording: ${JSON.stringify(screenRecordingInfo)}`);
|
|
190
|
+
await this.proxyCommand('/wda/video/stop', 'POST', {});
|
|
191
|
+
const videoPath = await retrieveXcTestScreenRecording.bind(this)(screenRecordingInfo.uuid);
|
|
192
|
+
const result = /** @type {XcTestScreenRecording} */ (screenRecordingInfo);
|
|
193
|
+
try {
|
|
194
|
+
result.payload = await encodeBase64OrUpload(videoPath, remotePath, {
|
|
195
|
+
user, pass, headers, fileFieldName, formFields, method
|
|
196
|
+
});
|
|
197
|
+
} finally {
|
|
198
|
+
await fs.rimraf(videoPath);
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
206
|
+
*/
|
package/lib/desired-caps.js
CHANGED
package/lib/devicectl.js
CHANGED
|
@@ -56,12 +56,31 @@ const XCRUN = 'xcrun';
|
|
|
56
56
|
* @property {boolean} [asJson=true]
|
|
57
57
|
* @property {boolean} [asynchronous=false]
|
|
58
58
|
* @property {string[]|string} [subcommandOptions]
|
|
59
|
+
* @property {number} [timeout]
|
|
59
60
|
*/
|
|
60
61
|
|
|
61
62
|
/**
|
|
62
63
|
* @typedef {{asynchronous: true}} TAsyncOpts
|
|
63
64
|
*/
|
|
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
|
+
|
|
65
84
|
export class Devicectl {
|
|
66
85
|
/**
|
|
67
86
|
* @since Xcode 15, iOS 17
|
|
@@ -85,6 +104,7 @@ export class Devicectl {
|
|
|
85
104
|
asynchronous = false,
|
|
86
105
|
asJson = true,
|
|
87
106
|
subcommandOptions,
|
|
107
|
+
timeout,
|
|
88
108
|
} = opts ?? {};
|
|
89
109
|
|
|
90
110
|
const finalArgs = [
|
|
@@ -108,7 +128,7 @@ export class Devicectl {
|
|
|
108
128
|
// @ts-ignore TS does not understand it
|
|
109
129
|
return result;
|
|
110
130
|
}
|
|
111
|
-
const result = await exec(XCRUN, finalArgs);
|
|
131
|
+
const result = await exec(XCRUN, finalArgs, {timeout});
|
|
112
132
|
if (logStdout) {
|
|
113
133
|
this.log.debug(`Command output: ${result.stdout}`);
|
|
114
134
|
}
|
|
@@ -141,6 +161,61 @@ export class Devicectl {
|
|
|
141
161
|
return JSON.parse(stdout).result.runningProcesses;
|
|
142
162
|
}
|
|
143
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Lists files at a specified path on the device
|
|
166
|
+
*
|
|
167
|
+
* @param {string} domainType The file service domain. Valid values are: temporary, rootStaging, appDataContainer, appGroupDataContainer,
|
|
168
|
+
* systemCrashLogs. You must specify a valid domain and identifier pair. Each domain is accompanied by an identifier
|
|
169
|
+
* that provides additional context. For example, if the domain is an app data container, the identifier is the bundle
|
|
170
|
+
* ID of the app. For temporary directories and root staging areas, the identifier is a unique client-provided string
|
|
171
|
+
* which is used to get your own space, separate from those of other clients.
|
|
172
|
+
* @param {string} domainIdentifier A unique string used to provide additional context to the domain.
|
|
173
|
+
* @param {ListFilesOptions} [opts={}]
|
|
174
|
+
* @returns {Promise<string[]>} List of file names (could be empty)
|
|
175
|
+
*/
|
|
176
|
+
async listFiles(domainType, domainIdentifier, opts = {}) {
|
|
177
|
+
const subcommandOptions = [
|
|
178
|
+
'--domain-type', domainType,
|
|
179
|
+
'--domain-identifier', domainIdentifier,
|
|
180
|
+
];
|
|
181
|
+
if (opts.username) {
|
|
182
|
+
subcommandOptions.push('--username', opts.username);
|
|
183
|
+
}
|
|
184
|
+
if (opts.subdirectory) {
|
|
185
|
+
subcommandOptions.push('--subdirectory', opts.subdirectory);
|
|
186
|
+
}
|
|
187
|
+
const {stdout} = await this.execute(['device', 'info', 'files'], {
|
|
188
|
+
subcommandOptions,
|
|
189
|
+
});
|
|
190
|
+
return JSON.parse(stdout).result.files.map(({name}) => name);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Pulls a file from the specified path on the device to a local file system
|
|
195
|
+
*
|
|
196
|
+
* @param {string} from The item which should be copied.
|
|
197
|
+
* @param {string} to The location to which the item should be copied.
|
|
198
|
+
* @param {PullFileOptions} opts
|
|
199
|
+
* @returns {Promise<string>} The destination path (same as `to`)
|
|
200
|
+
*/
|
|
201
|
+
async pullFile(from, to, opts) {
|
|
202
|
+
const subcommandOptions = [
|
|
203
|
+
'--domain-type', opts.domainType,
|
|
204
|
+
'--domain-identifier', opts.domainIdentifier,
|
|
205
|
+
'--source', from,
|
|
206
|
+
'--destination', to,
|
|
207
|
+
];
|
|
208
|
+
if (opts.username) {
|
|
209
|
+
subcommandOptions.push('--user', opts.username);
|
|
210
|
+
}
|
|
211
|
+
await this.execute(['device', 'copy', 'from'], {
|
|
212
|
+
subcommandOptions,
|
|
213
|
+
timeout: opts.timeout ?? 120000,
|
|
214
|
+
asJson: false,
|
|
215
|
+
});
|
|
216
|
+
return to;
|
|
217
|
+
}
|
|
218
|
+
|
|
144
219
|
/**
|
|
145
220
|
* Send POSIX signal to the running process
|
|
146
221
|
*
|
package/lib/driver.js
CHANGED
|
@@ -664,7 +664,7 @@ class XCUITestDriver extends BaseDriver {
|
|
|
664
664
|
const device = this.opts.device;
|
|
665
665
|
|
|
666
666
|
if (this.opts.shutdownOtherSimulators) {
|
|
667
|
-
this.
|
|
667
|
+
this.assertFeatureEnabled(SHUTDOWN_OTHER_FEAT_NAME);
|
|
668
668
|
await shutdownOtherSimulators(device);
|
|
669
669
|
}
|
|
670
670
|
|
|
@@ -789,7 +789,7 @@ class XCUITestDriver extends BaseDriver {
|
|
|
789
789
|
|
|
790
790
|
// Used in the following WDA build
|
|
791
791
|
if (this.opts.resultBundlePath) {
|
|
792
|
-
this.
|
|
792
|
+
this.assertFeatureEnabled(CUSTOMIZE_RESULT_BUNDPE_PATH);
|
|
793
793
|
}
|
|
794
794
|
|
|
795
795
|
const startupRetries =
|
|
@@ -2222,6 +2222,13 @@ class XCUITestDriver extends BaseDriver {
|
|
|
2222
2222
|
mobileInstallXCTestBundle = commands.xctestExtensions.mobileInstallXCTestBundle;
|
|
2223
2223
|
mobileListXCTestBundles = commands.xctestExtensions.mobileListXCTestBundles;
|
|
2224
2224
|
mobileListXCTestsInTestBundle = commands.xctestExtensions.mobileListXCTestsInTestBundle;
|
|
2225
|
+
|
|
2226
|
+
/*----------------------+
|
|
2227
|
+
| XCTEST SCREEN RECORD |
|
|
2228
|
+
+---------------------+*/
|
|
2229
|
+
mobileStartXctestScreenRecording = commands.xctestRecordScreenExtensions.mobileStartXctestScreenRecording;
|
|
2230
|
+
mobileGetXctestScreenRecordingInfo = commands.xctestRecordScreenExtensions.mobileGetXctestScreenRecordingInfo;
|
|
2231
|
+
mobileStopXctestScreenRecording = commands.xctestRecordScreenExtensions.mobileStopXctestScreenRecording;
|
|
2225
2232
|
}
|
|
2226
2233
|
|
|
2227
2234
|
/**
|
|
@@ -391,6 +391,21 @@ export const executeMethodMap = {
|
|
|
391
391
|
required: ['bundle'],
|
|
392
392
|
},
|
|
393
393
|
},
|
|
394
|
+
'mobile: startXCTestScreenRecording': {
|
|
395
|
+
command: 'mobileStartXctestScreenRecording',
|
|
396
|
+
params: {
|
|
397
|
+
optional: ['fps', 'codec'],
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
'mobile: getXCTestScreenRecordingInfo': {
|
|
401
|
+
command: 'mobileGetXctestScreenRecordingInfo',
|
|
402
|
+
},
|
|
403
|
+
'mobile: stopXCTestScreenRecording': {
|
|
404
|
+
command: 'mobileStopXctestScreenRecording',
|
|
405
|
+
params: {
|
|
406
|
+
optional: ['remotePath', 'user', 'pass', 'headers', 'fileFieldName', 'formFields', 'method'],
|
|
407
|
+
},
|
|
408
|
+
},
|
|
394
409
|
'mobile: pushNotification': {
|
|
395
410
|
command: 'mobilePushNotification',
|
|
396
411
|
params: {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-xcuitest-driver",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "appium-xcuitest-driver",
|
|
9
|
-
"version": "7.
|
|
9
|
+
"version": "7.3.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@colors/colors": "^1.6.0",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"appium-ios-device": "^2.5.4",
|
|
15
15
|
"appium-ios-simulator": "^5.5.1",
|
|
16
16
|
"appium-remote-debugger": "^11.0.0",
|
|
17
|
-
"appium-webdriveragent": "^7.0
|
|
17
|
+
"appium-webdriveragent": "^7.1.0",
|
|
18
18
|
"appium-xcode": "^5.1.4",
|
|
19
19
|
"async-lock": "^1.4.0",
|
|
20
20
|
"asyncbox": "^3.0.0",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"sinon-chai": "^3.7.0",
|
|
79
79
|
"ts-node": "^10.9.1",
|
|
80
80
|
"type-fest": "^4.1.0",
|
|
81
|
-
"typescript": "
|
|
81
|
+
"typescript": "^5.4.2",
|
|
82
82
|
"webdriverio": "^8.14.3"
|
|
83
83
|
},
|
|
84
84
|
"engines": {
|
|
@@ -669,9 +669,9 @@
|
|
|
669
669
|
}
|
|
670
670
|
},
|
|
671
671
|
"node_modules/@types/node": {
|
|
672
|
-
"version": "20.11.
|
|
673
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.
|
|
674
|
-
"integrity": "sha512-
|
|
672
|
+
"version": "20.11.25",
|
|
673
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
|
|
674
|
+
"integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==",
|
|
675
675
|
"dependencies": {
|
|
676
676
|
"undici-types": "~5.26.4"
|
|
677
677
|
}
|
|
@@ -695,9 +695,9 @@
|
|
|
695
695
|
"integrity": "sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg=="
|
|
696
696
|
},
|
|
697
697
|
"node_modules/@types/qs": {
|
|
698
|
-
"version": "6.9.
|
|
699
|
-
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.
|
|
700
|
-
"integrity": "sha512-
|
|
698
|
+
"version": "6.9.12",
|
|
699
|
+
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz",
|
|
700
|
+
"integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg=="
|
|
701
701
|
},
|
|
702
702
|
"node_modules/@types/range-parser": {
|
|
703
703
|
"version": "1.2.7",
|
|
@@ -823,9 +823,9 @@
|
|
|
823
823
|
}
|
|
824
824
|
},
|
|
825
825
|
"node_modules/appium-idb": {
|
|
826
|
-
"version": "1.8.
|
|
827
|
-
"resolved": "https://registry.npmjs.org/appium-idb/-/appium-idb-1.8.
|
|
828
|
-
"integrity": "sha512-
|
|
826
|
+
"version": "1.8.11",
|
|
827
|
+
"resolved": "https://registry.npmjs.org/appium-idb/-/appium-idb-1.8.11.tgz",
|
|
828
|
+
"integrity": "sha512-6LD+m+L+JdoTeXW3fAmKLsfE7+u0uBz76N0GWTOuSB6XnrNaZoPntG5TuJ0bj0oGFBVKLy8duYlF1W0CpFyjVg==",
|
|
829
829
|
"dependencies": {
|
|
830
830
|
"@appium/support": "^4.0.0",
|
|
831
831
|
"asyncbox": "^3.0.0",
|
|
@@ -840,12 +840,13 @@
|
|
|
840
840
|
}
|
|
841
841
|
},
|
|
842
842
|
"node_modules/appium-ios-device": {
|
|
843
|
-
"version": "2.7.
|
|
844
|
-
"resolved": "https://registry.npmjs.org/appium-ios-device/-/appium-ios-device-2.7.
|
|
845
|
-
"integrity": "sha512-
|
|
843
|
+
"version": "2.7.13",
|
|
844
|
+
"resolved": "https://registry.npmjs.org/appium-ios-device/-/appium-ios-device-2.7.13.tgz",
|
|
845
|
+
"integrity": "sha512-07IJBER57XqKSa/bS+DrXM9n+DYbb0ybyDMWoIKGx2g+GYpr25lQGiLCQBV17INSCGv0HbyP83hkNsKPVcHSUg==",
|
|
846
846
|
"dependencies": {
|
|
847
847
|
"@appium/support": "^4.0.0",
|
|
848
848
|
"asyncbox": "^3.0.0",
|
|
849
|
+
"axios": "^1.6.7",
|
|
849
850
|
"bluebird": "^3.1.1",
|
|
850
851
|
"bplist-creator": "^0.x",
|
|
851
852
|
"bplist-parser": "^0.x",
|
|
@@ -860,9 +861,9 @@
|
|
|
860
861
|
}
|
|
861
862
|
},
|
|
862
863
|
"node_modules/appium-ios-simulator": {
|
|
863
|
-
"version": "5.5.
|
|
864
|
-
"resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-5.5.
|
|
865
|
-
"integrity": "sha512-
|
|
864
|
+
"version": "5.5.3",
|
|
865
|
+
"resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-5.5.3.tgz",
|
|
866
|
+
"integrity": "sha512-dP3MMFXcewYIfd6Efewae6X0o/XU8/GPyY2alhMCMqdLucoR/tx7+mL7UJyMEPJsvPVRPXrej7yKOoljDVEU0w==",
|
|
866
867
|
"dependencies": {
|
|
867
868
|
"@appium/support": "^4.0.0",
|
|
868
869
|
"@xmldom/xmldom": "^0.x",
|
|
@@ -882,9 +883,9 @@
|
|
|
882
883
|
}
|
|
883
884
|
},
|
|
884
885
|
"node_modules/appium-remote-debugger": {
|
|
885
|
-
"version": "11.0.
|
|
886
|
-
"resolved": "https://registry.npmjs.org/appium-remote-debugger/-/appium-remote-debugger-11.0.
|
|
887
|
-
"integrity": "sha512-
|
|
886
|
+
"version": "11.0.4",
|
|
887
|
+
"resolved": "https://registry.npmjs.org/appium-remote-debugger/-/appium-remote-debugger-11.0.4.tgz",
|
|
888
|
+
"integrity": "sha512-sRgmNm1vmkyrHFbtgM9GT4LWEuyFpKCV0hn1FRL5jWn7SQDi3Q3oB5hbmFhUKtbpU4nanGeZY6v7VXwrF2DMUg==",
|
|
888
889
|
"dependencies": {
|
|
889
890
|
"@appium/base-driver": "^9.0.0",
|
|
890
891
|
"@appium/support": "^4.0.0",
|
|
@@ -904,9 +905,9 @@
|
|
|
904
905
|
}
|
|
905
906
|
},
|
|
906
907
|
"node_modules/appium-webdriveragent": {
|
|
907
|
-
"version": "7.0
|
|
908
|
-
"resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-7.0.
|
|
909
|
-
"integrity": "sha512-
|
|
908
|
+
"version": "7.1.0",
|
|
909
|
+
"resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-7.1.0.tgz",
|
|
910
|
+
"integrity": "sha512-HHMIbfeu8SV6lKf7E9YyM8GQBPmEVLySe0KYRq9ciHiI/jrqt7xpoTqObSVz2YXUqgbNIiuIB8roEjsK674G5Q==",
|
|
910
911
|
"dependencies": {
|
|
911
912
|
"@appium/base-driver": "^9.0.0",
|
|
912
913
|
"@appium/strongbox": "^0.x",
|
|
@@ -928,14 +929,15 @@
|
|
|
928
929
|
}
|
|
929
930
|
},
|
|
930
931
|
"node_modules/appium-xcode": {
|
|
931
|
-
"version": "5.2.
|
|
932
|
-
"resolved": "https://registry.npmjs.org/appium-xcode/-/appium-xcode-5.2.
|
|
933
|
-
"integrity": "sha512-
|
|
932
|
+
"version": "5.2.11",
|
|
933
|
+
"resolved": "https://registry.npmjs.org/appium-xcode/-/appium-xcode-5.2.11.tgz",
|
|
934
|
+
"integrity": "sha512-N4r3d/JkoB8PzPLxSFT+qiaVVEQOUJuyNVB3VWv7WfFovqtnJ0JLm7SLjd3GNKuTlR3FddVE7D19tEXPQmMTHQ==",
|
|
934
935
|
"dependencies": {
|
|
935
936
|
"@appium/support": "^4.0.0",
|
|
936
937
|
"@types/lodash": "^4.14.192",
|
|
937
938
|
"@types/teen_process": "^2.0.0",
|
|
938
939
|
"asyncbox": "^3.0.0",
|
|
940
|
+
"bluebird": "^3.7.2",
|
|
939
941
|
"lodash": "^4.17.4",
|
|
940
942
|
"plist": "^3.0.1",
|
|
941
943
|
"semver": "^7.0.0",
|
|
@@ -1076,9 +1078,9 @@
|
|
|
1076
1078
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
|
1077
1079
|
},
|
|
1078
1080
|
"node_modules/bare-events": {
|
|
1079
|
-
"version": "2.2.
|
|
1080
|
-
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.
|
|
1081
|
-
"integrity": "sha512-
|
|
1081
|
+
"version": "2.2.1",
|
|
1082
|
+
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.1.tgz",
|
|
1083
|
+
"integrity": "sha512-9GYPpsPFvrWBkelIhOhTWtkeZxVxZOdb3VnFTCzlOo3OjvmTvzLoZFUT8kNFACx0vJej6QPney1Cf9BvzCNE/A==",
|
|
1082
1084
|
"optional": true
|
|
1083
1085
|
},
|
|
1084
1086
|
"node_modules/base64-js": {
|
|
@@ -1321,9 +1323,9 @@
|
|
|
1321
1323
|
}
|
|
1322
1324
|
},
|
|
1323
1325
|
"node_modules/compress-commons": {
|
|
1324
|
-
"version": "5.0.
|
|
1325
|
-
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-5.0.
|
|
1326
|
-
"integrity": "sha512
|
|
1326
|
+
"version": "5.0.3",
|
|
1327
|
+
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-5.0.3.tgz",
|
|
1328
|
+
"integrity": "sha512-/UIcLWvwAQyVibgpQDPtfNM3SvqN7G9elAPAV7GM0L53EbNWwWiCsWtK8Fwed/APEbptPHXs5PuW+y8Bq8lFTA==",
|
|
1327
1329
|
"dependencies": {
|
|
1328
1330
|
"crc-32": "^1.2.0",
|
|
1329
1331
|
"crc32-stream": "^5.0.0",
|
|
@@ -1393,9 +1395,9 @@
|
|
|
1393
1395
|
}
|
|
1394
1396
|
},
|
|
1395
1397
|
"node_modules/crc32-stream": {
|
|
1396
|
-
"version": "5.0.
|
|
1397
|
-
"resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-5.0.
|
|
1398
|
-
"integrity": "sha512-
|
|
1398
|
+
"version": "5.0.1",
|
|
1399
|
+
"resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-5.0.1.tgz",
|
|
1400
|
+
"integrity": "sha512-lO1dFui+CEUh/ztYIpgpKItKW9Bb4NWakCRJrnqAbFIYD+OZAwb2VfD5T5eXMw2FNcsDHkQcNl/Wh3iVXYwU6g==",
|
|
1399
1401
|
"dependencies": {
|
|
1400
1402
|
"crc-32": "^1.2.0",
|
|
1401
1403
|
"readable-stream": "^3.4.0"
|
|
@@ -1437,9 +1439,9 @@
|
|
|
1437
1439
|
}
|
|
1438
1440
|
},
|
|
1439
1441
|
"node_modules/css-selector-parser": {
|
|
1440
|
-
"version": "3.0.
|
|
1441
|
-
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.0.
|
|
1442
|
-
"integrity": "sha512-
|
|
1442
|
+
"version": "3.0.5",
|
|
1443
|
+
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.0.5.tgz",
|
|
1444
|
+
"integrity": "sha512-3itoDFbKUNx1eKmVpYMFyqKX04Ww9osZ+dLgrk6GEv6KMVeXUhUnp4I5X+evw+u3ZxVU6RFXSSRxlTeMh8bA+g==",
|
|
1443
1445
|
"funding": [
|
|
1444
1446
|
{
|
|
1445
1447
|
"type": "github",
|
|
@@ -3334,11 +3336,11 @@
|
|
|
3334
3336
|
}
|
|
3335
3337
|
},
|
|
3336
3338
|
"node_modules/side-channel": {
|
|
3337
|
-
"version": "1.0.
|
|
3338
|
-
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.
|
|
3339
|
-
"integrity": "sha512-
|
|
3339
|
+
"version": "1.0.6",
|
|
3340
|
+
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
|
3341
|
+
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
|
3340
3342
|
"dependencies": {
|
|
3341
|
-
"call-bind": "^1.0.
|
|
3343
|
+
"call-bind": "^1.0.7",
|
|
3342
3344
|
"es-errors": "^1.3.0",
|
|
3343
3345
|
"get-intrinsic": "^1.2.4",
|
|
3344
3346
|
"object-inspect": "^1.13.1"
|
|
@@ -3880,9 +3882,9 @@
|
|
|
3880
3882
|
}
|
|
3881
3883
|
},
|
|
3882
3884
|
"node_modules/zip-stream": {
|
|
3883
|
-
"version": "5.0.
|
|
3884
|
-
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-5.0.
|
|
3885
|
-
"integrity": "sha512-
|
|
3885
|
+
"version": "5.0.2",
|
|
3886
|
+
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-5.0.2.tgz",
|
|
3887
|
+
"integrity": "sha512-LfOdrUvPB8ZoXtvOBz6DlNClfvi//b5d56mSWyJi7XbH/HfhOHfUhOqxhT/rUiR7yiktlunqRo+jY6y/cWC/5g==",
|
|
3886
3888
|
"dependencies": {
|
|
3887
3889
|
"archiver-utils": "^4.0.1",
|
|
3888
3890
|
"compress-commons": "^5.0.1",
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"xcuitest",
|
|
9
9
|
"xctest"
|
|
10
10
|
],
|
|
11
|
-
"version": "7.
|
|
11
|
+
"version": "7.3.0",
|
|
12
12
|
"author": "Appium Contributors",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"repository": {
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"appium-ios-device": "^2.5.4",
|
|
82
82
|
"appium-ios-simulator": "^5.5.1",
|
|
83
83
|
"appium-remote-debugger": "^11.0.0",
|
|
84
|
-
"appium-webdriveragent": "^7.0
|
|
84
|
+
"appium-webdriveragent": "^7.1.0",
|
|
85
85
|
"appium-xcode": "^5.1.4",
|
|
86
86
|
"async-lock": "^1.4.0",
|
|
87
87
|
"asyncbox": "^3.0.0",
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
"sinon-chai": "^3.7.0",
|
|
179
179
|
"ts-node": "^10.9.1",
|
|
180
180
|
"type-fest": "^4.1.0",
|
|
181
|
-
"typescript": "
|
|
181
|
+
"typescript": "^5.4.2",
|
|
182
182
|
"webdriverio": "^8.14.3"
|
|
183
183
|
},
|
|
184
184
|
"overrides": {
|