appium-xcuitest-driver 10.8.4 → 10.9.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/app-utils.d.ts +2 -2
- package/build/lib/app-utils.d.ts.map +1 -1
- package/build/lib/app-utils.js +4 -1
- package/build/lib/app-utils.js.map +1 -1
- package/build/lib/commands/app-management.js +1 -1
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.js +2 -2
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/biometric.js +3 -3
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/certificate.d.ts.map +1 -1
- package/build/lib/commands/certificate.js +9 -3
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/context.d.ts +5 -5
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +6 -6
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/file-movement.js +3 -3
- package/build/lib/commands/file-movement.js.map +1 -1
- package/build/lib/commands/general.js +1 -1
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/gesture.js +1 -1
- package/build/lib/commands/gesture.js.map +1 -1
- package/build/lib/commands/keychains.js +1 -1
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.js +1 -1
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/location.js +1 -1
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/log.js +7 -7
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/notifications.js +1 -1
- package/build/lib/commands/notifications.js.map +1 -1
- package/build/lib/commands/pasteboard.js +2 -2
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/pcap.js +1 -1
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/permissions.js +2 -2
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/proxy-helper.d.ts.map +1 -1
- package/build/lib/commands/proxy-helper.js +0 -3
- package/build/lib/commands/proxy-helper.js.map +1 -1
- package/build/lib/commands/screenshots.js +1 -1
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/simctl.d.ts +1 -1
- package/build/lib/commands/simctl.d.ts.map +1 -1
- package/build/lib/commands/simctl.js +1 -1
- package/build/lib/commands/simctl.js.map +1 -1
- package/build/lib/commands/web.js +1 -1
- package/build/lib/commands/web.js.map +1 -1
- package/build/lib/commands/xctest-record-screen.js +1 -1
- package/build/lib/commands/xctest-record-screen.js.map +1 -1
- package/build/lib/desired-caps.d.ts +383 -507
- package/build/lib/desired-caps.d.ts.map +1 -1
- package/build/lib/desired-caps.js +6 -10
- package/build/lib/desired-caps.js.map +1 -1
- package/build/lib/device/clients/base-device-client.d.ts.map +1 -0
- package/build/lib/device/clients/base-device-client.js.map +1 -0
- package/build/lib/{real-device-clients → device/clients}/py-ios-device-client.d.ts +1 -1
- package/build/lib/device/clients/py-ios-device-client.d.ts.map +1 -0
- package/build/lib/device/clients/py-ios-device-client.js.map +1 -0
- package/build/lib/{device-log → device/log}/helpers.d.ts +1 -1
- package/build/lib/device/log/helpers.d.ts.map +1 -0
- package/build/lib/device/log/helpers.js.map +1 -0
- package/build/lib/{device-log → device/log}/ios-crash-log.d.ts +1 -1
- package/build/lib/device/log/ios-crash-log.d.ts.map +1 -0
- package/build/lib/{device-log → device/log}/ios-crash-log.js +1 -1
- package/build/lib/device/log/ios-crash-log.js.map +1 -0
- package/build/lib/device/log/ios-device-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-device-log.js.map +1 -0
- package/build/lib/{device-log → device/log}/ios-log.d.ts +1 -1
- package/build/lib/device/log/ios-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-log.js.map +1 -0
- package/build/lib/device/log/ios-performance-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-performance-log.js.map +1 -0
- package/build/lib/device/log/ios-simulator-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-simulator-log.js.map +1 -0
- package/build/lib/{device-log → device/log}/line-consuming-log.d.ts +1 -1
- package/build/lib/device/log/line-consuming-log.d.ts.map +1 -0
- package/build/lib/device/log/line-consuming-log.js.map +1 -0
- package/build/lib/{device-log → device/log}/safari-console-log.d.ts +1 -1
- package/build/lib/device/log/safari-console-log.d.ts.map +1 -0
- package/build/lib/device/log/safari-console-log.js.map +1 -0
- package/build/lib/device/log/safari-network-log.d.ts.map +1 -0
- package/build/lib/device/log/safari-network-log.js.map +1 -0
- package/build/lib/device/real-device-management.d.ts.map +1 -1
- package/build/lib/device/real-device-management.js +3 -2
- package/build/lib/device/real-device-management.js.map +1 -1
- package/build/lib/device/simulator-management.js +1 -1
- package/build/lib/device/simulator-management.js.map +1 -1
- package/build/lib/driver.d.ts +129 -1385
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +471 -594
- package/build/lib/driver.js.map +1 -1
- package/build/lib/method-map.d.ts +1 -1
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js +2 -2
- package/build/lib/method-map.js.map +1 -1
- package/lib/app-utils.js +5 -1
- package/lib/commands/app-management.js +1 -1
- package/lib/commands/appearance.js +2 -2
- package/lib/commands/biometric.js +3 -3
- package/lib/commands/certificate.js +9 -3
- package/lib/commands/context.js +6 -6
- package/lib/commands/file-movement.js +3 -3
- package/lib/commands/general.js +1 -1
- package/lib/commands/gesture.js +1 -1
- package/lib/commands/keychains.js +1 -1
- package/lib/commands/localization.js +1 -1
- package/lib/commands/location.js +1 -1
- package/lib/commands/log.js +7 -7
- package/lib/commands/notifications.js +1 -1
- package/lib/commands/pasteboard.js +2 -2
- package/lib/commands/pcap.js +1 -1
- package/lib/commands/permissions.js +2 -2
- package/lib/commands/proxy-helper.js +0 -3
- package/lib/commands/screenshots.js +1 -1
- package/lib/commands/simctl.js +1 -1
- package/lib/commands/web.js +1 -1
- package/lib/commands/xctest-record-screen.js +1 -1
- package/lib/{desired-caps.js → desired-caps.ts} +7 -6
- package/lib/{real-device-clients → device/clients}/py-ios-device-client.ts +1 -1
- package/lib/{device-log → device/log}/helpers.ts +1 -1
- package/lib/{device-log → device/log}/ios-crash-log.ts +3 -3
- package/lib/{device-log → device/log}/ios-log.ts +1 -1
- package/lib/{device-log → device/log}/line-consuming-log.ts +1 -1
- package/lib/{device-log → device/log}/safari-console-log.ts +1 -1
- package/lib/device/real-device-management.ts +3 -2
- package/lib/device/simulator-management.ts +1 -1
- package/lib/{driver.js → driver.ts} +616 -708
- package/lib/{method-map.js → method-map.ts} +5 -2
- package/npm-shrinkwrap.json +5 -5
- package/package.json +1 -1
- package/build/lib/device-log/helpers.d.ts.map +0 -1
- package/build/lib/device-log/helpers.js.map +0 -1
- package/build/lib/device-log/ios-crash-log.d.ts.map +0 -1
- package/build/lib/device-log/ios-crash-log.js.map +0 -1
- package/build/lib/device-log/ios-device-log.d.ts.map +0 -1
- package/build/lib/device-log/ios-device-log.js.map +0 -1
- package/build/lib/device-log/ios-log.d.ts.map +0 -1
- package/build/lib/device-log/ios-log.js.map +0 -1
- package/build/lib/device-log/ios-performance-log.d.ts.map +0 -1
- package/build/lib/device-log/ios-performance-log.js.map +0 -1
- package/build/lib/device-log/ios-simulator-log.d.ts.map +0 -1
- package/build/lib/device-log/ios-simulator-log.js.map +0 -1
- package/build/lib/device-log/line-consuming-log.d.ts.map +0 -1
- package/build/lib/device-log/line-consuming-log.js.map +0 -1
- package/build/lib/device-log/safari-console-log.d.ts.map +0 -1
- package/build/lib/device-log/safari-console-log.js.map +0 -1
- package/build/lib/device-log/safari-network-log.d.ts.map +0 -1
- package/build/lib/device-log/safari-network-log.js.map +0 -1
- package/build/lib/real-device-clients/base-device-client.d.ts.map +0 -1
- package/build/lib/real-device-clients/base-device-client.js.map +0 -1
- package/build/lib/real-device-clients/py-ios-device-client.d.ts.map +0 -1
- package/build/lib/real-device-clients/py-ios-device-client.js.map +0 -1
- /package/build/lib/{real-device-clients → device/clients}/base-device-client.d.ts +0 -0
- /package/build/lib/{real-device-clients → device/clients}/base-device-client.js +0 -0
- /package/build/lib/{real-device-clients → device/clients}/py-ios-device-client.js +0 -0
- /package/build/lib/{device-log → device/log}/helpers.js +0 -0
- /package/build/lib/{device-log → device/log}/ios-device-log.d.ts +0 -0
- /package/build/lib/{device-log → device/log}/ios-device-log.js +0 -0
- /package/build/lib/{device-log → device/log}/ios-log.js +0 -0
- /package/build/lib/{device-log → device/log}/ios-performance-log.d.ts +0 -0
- /package/build/lib/{device-log → device/log}/ios-performance-log.js +0 -0
- /package/build/lib/{device-log → device/log}/ios-simulator-log.d.ts +0 -0
- /package/build/lib/{device-log → device/log}/ios-simulator-log.js +0 -0
- /package/build/lib/{device-log → device/log}/line-consuming-log.js +0 -0
- /package/build/lib/{device-log → device/log}/safari-console-log.js +0 -0
- /package/build/lib/{device-log → device/log}/safari-network-log.d.ts +0 -0
- /package/build/lib/{device-log → device/log}/safari-network-log.js +0 -0
- /package/lib/{real-device-clients → device/clients}/base-device-client.ts +0 -0
- /package/lib/{device-log → device/log}/ios-device-log.ts +0 -0
- /package/lib/{device-log → device/log}/ios-performance-log.ts +0 -0
- /package/lib/{device-log → device/log}/ios-simulator-log.ts +0 -0
- /package/lib/{device-log → device/log}/safari-network-log.ts +0 -0
package/build/lib/driver.js
CHANGED
|
@@ -101,7 +101,7 @@ const desired_caps_1 = require("./desired-caps");
|
|
|
101
101
|
const device_connections_factory_1 = require("./device/device-connections-factory");
|
|
102
102
|
const execute_method_map_1 = require("./execute-method-map");
|
|
103
103
|
const method_map_1 = require("./method-map");
|
|
104
|
-
const py_ios_device_client_1 = require("./
|
|
104
|
+
const py_ios_device_client_1 = require("./device/clients/py-ios-device-client");
|
|
105
105
|
const real_device_management_1 = require("./device/real-device-management");
|
|
106
106
|
const simulator_management_1 = require("./device/simulator-management");
|
|
107
107
|
const utils_1 = require("./utils");
|
|
@@ -146,7 +146,6 @@ const WEB_ELEMENTS_CACHE_SIZE = 500;
|
|
|
146
146
|
const SUPPORTED_ORIENATIONS = ['LANDSCAPE', 'PORTRAIT'];
|
|
147
147
|
const DEFAULT_MJPEG_SERVER_PORT = 9100;
|
|
148
148
|
/* eslint-disable no-useless-escape */
|
|
149
|
-
/** @type {import('@appium/types').RouteMatcher[]} */
|
|
150
149
|
const NO_PROXY_NATIVE_LIST = [
|
|
151
150
|
['DELETE', /window/],
|
|
152
151
|
['GET', /^\/session\/[^\/]+$/],
|
|
@@ -193,7 +192,7 @@ const NO_PROXY_NATIVE_LIST = [
|
|
|
193
192
|
['GET', /cookie/],
|
|
194
193
|
['POST', /cookie/],
|
|
195
194
|
];
|
|
196
|
-
const NO_PROXY_WEB_LIST =
|
|
195
|
+
const NO_PROXY_WEB_LIST = [
|
|
197
196
|
['GET', /attribute/],
|
|
198
197
|
['GET', /element/],
|
|
199
198
|
['GET', /text/],
|
|
@@ -205,89 +204,55 @@ const NO_PROXY_WEB_LIST = /** @type {import('@appium/types').RouteMatcher[]} */
|
|
|
205
204
|
['POST', /frame/],
|
|
206
205
|
['POST', /keys/],
|
|
207
206
|
['POST', /refresh/],
|
|
208
|
-
|
|
207
|
+
...NO_PROXY_NATIVE_LIST,
|
|
208
|
+
];
|
|
209
209
|
/* eslint-enable no-useless-escape */
|
|
210
210
|
const MEMOIZED_FUNCTIONS = ['getStatusBarHeight', 'getDevicePixelRatio', 'getScreenInfo'];
|
|
211
211
|
// Capabilities that do not have xcodebuild process
|
|
212
212
|
const CAP_NAMES_NO_XCODEBUILD_REQUIRED = ['webDriverAgentUrl', 'usePreinstalledWDA'];
|
|
213
213
|
const BUNDLE_VERSION_PATTERN = /CFBundleVersion\s+=\s+"?([^(;|")]+)/;
|
|
214
|
-
/**
|
|
215
|
-
* @implements {ExternalDriver<XCUITestDriverConstraints, FullContext|string>}
|
|
216
|
-
* @extends {BaseDriver<XCUITestDriverConstraints>}
|
|
217
|
-
* @privateRemarks **This class should be considered "final"**. It cannot be extended
|
|
218
|
-
* due to use of public class field assignments. If extending this class becomes a hard requirement, refer to the implementation of `BaseDriver` on how to do so.
|
|
219
|
-
*/
|
|
220
214
|
class XCUITestDriver extends driver_1.BaseDriver {
|
|
221
215
|
static newMethodMap = method_map_1.newMethodMap;
|
|
222
216
|
static executeMethodMap = execute_method_map_1.executeMethodMap;
|
|
223
|
-
/** @type {string|null|undefined} */
|
|
224
217
|
curWindowHandle;
|
|
225
|
-
/**
|
|
226
|
-
* @type {boolean|undefined}
|
|
227
|
-
*/
|
|
228
218
|
selectingNewPage;
|
|
229
|
-
/** @type {string[]} */
|
|
230
219
|
contexts;
|
|
231
|
-
/** @type {string|null} */
|
|
232
220
|
curContext;
|
|
233
|
-
/** @type {string[]} */
|
|
234
221
|
curWebFrames;
|
|
235
|
-
/** @type {import('./types').CalibrationData|null} */
|
|
236
222
|
webviewCalibrationResult;
|
|
237
|
-
/** @type {import('./types').AsyncPromise|undefined} */
|
|
238
223
|
asyncPromise;
|
|
239
|
-
/** @type {number|undefined} */
|
|
240
224
|
asyncWaitMs;
|
|
241
|
-
/** @type {((logRecord: {message: string}) => void)|null} */
|
|
242
225
|
_syslogWebsocketListener;
|
|
243
|
-
/** @type {import('./commands/performance').PerfRecorder[]} */
|
|
244
226
|
_perfRecorders;
|
|
245
|
-
/** @type {LRUCache} */
|
|
246
227
|
webElementsCache;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
* @privateRemarks needs types
|
|
250
|
-
**/
|
|
251
|
-
_conditionInducerService;
|
|
252
|
-
/**
|
|
253
|
-
* @type {import('./commands/condition.js').DVTServiceWithConnection|null}
|
|
254
|
-
* @privateRemarks RemoteXPC DVT connection for iOS>=18 condition inducer
|
|
255
|
-
**/
|
|
256
|
-
_remoteXPCConditionInducerConnection;
|
|
257
|
-
/** @type {boolean|undefined} */
|
|
228
|
+
_conditionInducerService; // needs types
|
|
229
|
+
_remoteXPCConditionInducerConnection; // RemoteXPC DVT connection for iOS>=18 condition inducer
|
|
258
230
|
_isSafariIphone;
|
|
259
|
-
/** @type {boolean|undefined} */
|
|
260
231
|
_isSafariNotched;
|
|
261
|
-
/** @type {import('./commands/types').WaitingAtoms} */
|
|
262
232
|
_waitingAtoms;
|
|
263
|
-
/** @type {import('./types').LifecycleData} */
|
|
264
233
|
lifecycleData;
|
|
265
|
-
/** @type {import('./commands/record-audio').AudioRecorder|null} */
|
|
266
234
|
_audioRecorder;
|
|
267
|
-
/** @type {XcodeVersion|undefined} */
|
|
268
235
|
xcodeVersion;
|
|
269
|
-
/** @type {import('./commands/pcap').TrafficCapture|null} */
|
|
270
236
|
_trafficCapture;
|
|
271
|
-
/** @type {import('./commands/recordscreen').ScreenRecorder|null} */
|
|
272
237
|
_recentScreenRecorder;
|
|
273
|
-
/** @type {Simulator|RealDevice} */
|
|
274
238
|
_device;
|
|
275
|
-
/** @type {string|null} */
|
|
276
239
|
_iosSdkVersion;
|
|
277
|
-
|
|
278
|
-
wda;
|
|
279
|
-
/** @type {import('appium-remote-debugger').RemoteDebugger|null} */
|
|
240
|
+
_wda;
|
|
280
241
|
remote;
|
|
281
|
-
/** @type {DriverLogs} */
|
|
282
242
|
logs;
|
|
283
|
-
/** @type {import('./commands/types').LogListener|undefined} */
|
|
284
243
|
_bidiServerLogListener;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
244
|
+
// Additional properties that were missing
|
|
245
|
+
appInfosCache;
|
|
246
|
+
doesSupportBidi;
|
|
247
|
+
jwpProxyActive;
|
|
248
|
+
proxyReqRes;
|
|
249
|
+
safari;
|
|
250
|
+
cachedWdaStatus;
|
|
251
|
+
_currentUrl;
|
|
252
|
+
pageLoadMs;
|
|
253
|
+
landscapeWebCoordsOffset;
|
|
254
|
+
mjpegStream;
|
|
255
|
+
constructor(opts, shouldValidateCaps = true) {
|
|
291
256
|
super(opts, shouldValidateCaps);
|
|
292
257
|
this.locatorStrategies = [
|
|
293
258
|
'xpath',
|
|
@@ -331,7 +296,295 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
331
296
|
this.appInfosCache = new app_infos_cache_1.AppInfosCache(this.log);
|
|
332
297
|
this.remote = null;
|
|
333
298
|
this.doesSupportBidi = true;
|
|
299
|
+
this._wda = null;
|
|
300
|
+
}
|
|
301
|
+
// Override methods from BaseDriver
|
|
302
|
+
async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) {
|
|
303
|
+
try {
|
|
304
|
+
const [sessionId, initialCaps] = await super.createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData);
|
|
305
|
+
let caps = initialCaps;
|
|
306
|
+
// merge cli args to opts, and if we did merge any, revalidate opts to ensure the final set
|
|
307
|
+
// is also consistent
|
|
308
|
+
if (this.mergeCliArgsToOpts()) {
|
|
309
|
+
this.validateDesiredCaps({ ...caps, ...this.cliArgs });
|
|
310
|
+
}
|
|
311
|
+
await this.start();
|
|
312
|
+
// merge server capabilities + desired capabilities
|
|
313
|
+
caps = { ...defaultServerCaps, ...caps };
|
|
314
|
+
// update the udid with what is actually used
|
|
315
|
+
caps.udid = this.opts.udid;
|
|
316
|
+
// ensure we track nativeWebTap capability as a setting as well
|
|
317
|
+
if (lodash_1.default.has(this.opts, 'nativeWebTap')) {
|
|
318
|
+
await this.updateSettings({ nativeWebTap: this.opts.nativeWebTap });
|
|
319
|
+
}
|
|
320
|
+
// ensure we track nativeWebTapStrict capability as a setting as well
|
|
321
|
+
if (lodash_1.default.has(this.opts, 'nativeWebTapStrict')) {
|
|
322
|
+
await this.updateSettings({ nativeWebTapStrict: this.opts.nativeWebTapStrict });
|
|
323
|
+
}
|
|
324
|
+
// ensure we track useJSONSource capability as a setting as well
|
|
325
|
+
if (lodash_1.default.has(this.opts, 'useJSONSource')) {
|
|
326
|
+
await this.updateSettings({ useJSONSource: this.opts.useJSONSource });
|
|
327
|
+
}
|
|
328
|
+
const wdaSettings = {
|
|
329
|
+
elementResponseAttributes: DEFAULT_SETTINGS.elementResponseAttributes,
|
|
330
|
+
shouldUseCompactResponses: DEFAULT_SETTINGS.shouldUseCompactResponses,
|
|
331
|
+
};
|
|
332
|
+
if ('elementResponseAttributes' in this.opts && lodash_1.default.isString(this.opts.elementResponseAttributes)) {
|
|
333
|
+
wdaSettings.elementResponseAttributes = this.opts.elementResponseAttributes;
|
|
334
|
+
}
|
|
335
|
+
if ('shouldUseCompactResponses' in this.opts && lodash_1.default.isBoolean(this.opts.shouldUseCompactResponses)) {
|
|
336
|
+
wdaSettings.shouldUseCompactResponses = this.opts.shouldUseCompactResponses;
|
|
337
|
+
}
|
|
338
|
+
if ('mjpegServerScreenshotQuality' in this.opts && lodash_1.default.isNumber(this.opts.mjpegServerScreenshotQuality)) {
|
|
339
|
+
wdaSettings.mjpegServerScreenshotQuality = this.opts.mjpegServerScreenshotQuality;
|
|
340
|
+
}
|
|
341
|
+
if ('mjpegServerFramerate' in this.opts && lodash_1.default.isNumber(this.opts.mjpegServerFramerate)) {
|
|
342
|
+
wdaSettings.mjpegServerFramerate = this.opts.mjpegServerFramerate;
|
|
343
|
+
}
|
|
344
|
+
if (lodash_1.default.has(this.opts, 'screenshotQuality')) {
|
|
345
|
+
this.log.info(`Setting the quality of phone screenshot: '${this.opts.screenshotQuality}'`);
|
|
346
|
+
wdaSettings.screenshotQuality = this.opts.screenshotQuality;
|
|
347
|
+
}
|
|
348
|
+
// ensure WDA gets our defaults instead of whatever its own might be
|
|
349
|
+
await this.updateSettings(wdaSettings);
|
|
350
|
+
await this.handleMjpegOptions();
|
|
351
|
+
return [
|
|
352
|
+
sessionId,
|
|
353
|
+
caps,
|
|
354
|
+
];
|
|
355
|
+
}
|
|
356
|
+
catch (e) {
|
|
357
|
+
this.log.error(JSON.stringify(e));
|
|
358
|
+
await this.deleteSession();
|
|
359
|
+
throw e;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async deleteSession(sessionId) {
|
|
363
|
+
await utils_1.removeAllSessionWebSocketHandlers.bind(this)();
|
|
364
|
+
for (const recorder of lodash_1.default.compact([
|
|
365
|
+
this._recentScreenRecorder,
|
|
366
|
+
this._audioRecorder,
|
|
367
|
+
this._trafficCapture,
|
|
368
|
+
])) {
|
|
369
|
+
await recorder.interrupt(true);
|
|
370
|
+
await recorder.cleanup();
|
|
371
|
+
}
|
|
372
|
+
if (!lodash_1.default.isEmpty(this._perfRecorders)) {
|
|
373
|
+
await bluebird_1.default.all(this._perfRecorders.map((x) => x.stop(true)));
|
|
374
|
+
this._perfRecorders = [];
|
|
375
|
+
}
|
|
376
|
+
if (this._conditionInducerService || this._remoteXPCConditionInducerConnection) {
|
|
377
|
+
try {
|
|
378
|
+
await this.disableConditionInducer();
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
this.log.warn(`Cannot disable condition inducer: ${err.message}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
await this.stop();
|
|
385
|
+
if (this._wda && this.isXcodebuildNeeded()) {
|
|
386
|
+
if (this.opts.clearSystemFiles) {
|
|
387
|
+
let synchronizationKey = XCUITestDriver.name;
|
|
388
|
+
const derivedDataPath = await this.wda.retrieveDerivedDataPath();
|
|
389
|
+
if (derivedDataPath) {
|
|
390
|
+
synchronizationKey = node_path_1.default.normalize(derivedDataPath);
|
|
391
|
+
}
|
|
392
|
+
await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
|
|
393
|
+
await (0, utils_1.clearSystemFiles)(this.wda);
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
this.log.debug('Not clearing log files. Use `clearSystemFiles` capability to turn on.');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (this.remote) {
|
|
401
|
+
this.log.debug('Found a remote debugger session. Removing...');
|
|
402
|
+
await this.stopRemote();
|
|
403
|
+
}
|
|
404
|
+
if (this.opts.resetOnSessionStartOnly === false) {
|
|
405
|
+
await this.runReset(true);
|
|
406
|
+
}
|
|
407
|
+
const simulatorDevice = this.isSimulator() ? this.device : null;
|
|
408
|
+
if (simulatorDevice && this.lifecycleData.createSim) {
|
|
409
|
+
this.log.debug(`Deleting simulator created for this run (udid: '${simulatorDevice.udid}')`);
|
|
410
|
+
await simulator_management_1.shutdownSimulator.bind(this)();
|
|
411
|
+
await simulatorDevice.delete();
|
|
412
|
+
}
|
|
413
|
+
const shouldResetLocationService = this.isRealDevice() && !!this.opts.resetLocationService;
|
|
414
|
+
if (shouldResetLocationService) {
|
|
415
|
+
try {
|
|
416
|
+
await this.mobileResetLocationService();
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
/* Ignore this error since mobileResetLocationService already logged the error */
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
await this.logs.syslog?.stopCapture();
|
|
423
|
+
lodash_1.default.values(this.logs).forEach((x) => x?.removeAllListeners?.());
|
|
424
|
+
if (this._bidiServerLogListener) {
|
|
425
|
+
this.log.unwrap().off('log', this._bidiServerLogListener);
|
|
426
|
+
}
|
|
427
|
+
this.logs = {};
|
|
428
|
+
if (this.mjpegStream) {
|
|
429
|
+
this.log.info('Closing MJPEG stream');
|
|
430
|
+
this.mjpegStream.stop();
|
|
431
|
+
}
|
|
432
|
+
this.resetIos();
|
|
433
|
+
await super.deleteSession(sessionId);
|
|
434
|
+
}
|
|
435
|
+
async executeCommand(cmd, ...args) {
|
|
436
|
+
this.log.debug(`Executing command '${cmd}'`);
|
|
437
|
+
if (cmd === 'receiveAsyncResponse') {
|
|
438
|
+
return await this.receiveAsyncResponse(...args);
|
|
439
|
+
}
|
|
440
|
+
// TODO: once this fix gets into base driver remove from here
|
|
441
|
+
if (cmd === 'getStatus') {
|
|
442
|
+
return await this.getStatus();
|
|
443
|
+
}
|
|
444
|
+
return await super.executeCommand(cmd, ...args);
|
|
445
|
+
}
|
|
446
|
+
proxyActive() {
|
|
447
|
+
return Boolean(this.jwpProxyActive);
|
|
448
|
+
}
|
|
449
|
+
getProxyAvoidList() {
|
|
450
|
+
if (this.isWebview()) {
|
|
451
|
+
return NO_PROXY_WEB_LIST;
|
|
452
|
+
}
|
|
453
|
+
return NO_PROXY_NATIVE_LIST;
|
|
454
|
+
}
|
|
455
|
+
canProxy() {
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
validateLocatorStrategy(strategy) {
|
|
459
|
+
super.validateLocatorStrategy(strategy, this.isWebContext());
|
|
334
460
|
}
|
|
461
|
+
validateDesiredCaps(caps) {
|
|
462
|
+
if (!super.validateDesiredCaps(caps)) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
// make sure that the capabilities have one of `app` or `bundleId`
|
|
466
|
+
if (lodash_1.default.toLower(caps.browserName) !== 'safari' && !caps.app && !caps.bundleId) {
|
|
467
|
+
this.log.info('The desired capabilities include neither an app nor a bundleId. ' +
|
|
468
|
+
'WebDriverAgent will be started without the default app');
|
|
469
|
+
}
|
|
470
|
+
if (!support_1.util.coerceVersion(String(caps.platformVersion), false)) {
|
|
471
|
+
this.log.warn(`'platformVersion' capability ('${caps.platformVersion}') is not a valid version number. ` +
|
|
472
|
+
`Consider fixing it or be ready to experience an inconsistent driver behavior.`);
|
|
473
|
+
}
|
|
474
|
+
const verifyProcessArgument = (processArguments) => {
|
|
475
|
+
const { args, env } = processArguments;
|
|
476
|
+
if (!lodash_1.default.isNil(args) && !lodash_1.default.isArray(args)) {
|
|
477
|
+
throw this.log.errorWithException('processArguments.args must be an array of strings');
|
|
478
|
+
}
|
|
479
|
+
if (!lodash_1.default.isNil(env) && !lodash_1.default.isPlainObject(env)) {
|
|
480
|
+
throw this.log.errorWithException('processArguments.env must be an object <key,value> pair {a:b, c:d}');
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
// `processArguments` should be JSON string or an object with arguments and/ environment details
|
|
484
|
+
if (caps.processArguments) {
|
|
485
|
+
if (lodash_1.default.isString(caps.processArguments)) {
|
|
486
|
+
try {
|
|
487
|
+
// try to parse the string as JSON
|
|
488
|
+
caps.processArguments = JSON.parse(caps.processArguments);
|
|
489
|
+
verifyProcessArgument(caps.processArguments);
|
|
490
|
+
}
|
|
491
|
+
catch (err) {
|
|
492
|
+
throw this.log.errorWithException(`processArguments must be a JSON format or an object with format {args : [], env : {a:b, c:d}}. ` +
|
|
493
|
+
`Both environment and argument can be null. Error: ${err}`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
else if (lodash_1.default.isPlainObject(caps.processArguments)) {
|
|
497
|
+
verifyProcessArgument(caps.processArguments);
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
throw this.log.errorWithException(`'processArguments must be an object, or a string JSON object with format {args : [], env : {a:b, c:d}}. ` +
|
|
501
|
+
`Both environment and argument can be null.`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
// there is no point in having `keychainPath` without `keychainPassword`
|
|
505
|
+
if ((caps.keychainPath && !caps.keychainPassword) ||
|
|
506
|
+
(!caps.keychainPath && caps.keychainPassword)) {
|
|
507
|
+
throw this.log.errorWithException(`If 'keychainPath' is set, 'keychainPassword' must also be set (and vice versa).`);
|
|
508
|
+
}
|
|
509
|
+
// `resetOnSessionStartOnly` should be set to true by default
|
|
510
|
+
this.opts.resetOnSessionStartOnly =
|
|
511
|
+
!support_1.util.hasValue(this.opts.resetOnSessionStartOnly) || this.opts.resetOnSessionStartOnly;
|
|
512
|
+
this.opts.useNewWDA = support_1.util.hasValue(this.opts.useNewWDA) ? this.opts.useNewWDA : false;
|
|
513
|
+
if (caps.commandTimeouts) {
|
|
514
|
+
caps.commandTimeouts = (0, utils_1.normalizeCommandTimeouts)(caps.commandTimeouts);
|
|
515
|
+
}
|
|
516
|
+
if (lodash_1.default.isString(caps.webDriverAgentUrl)) {
|
|
517
|
+
const { protocol, host } = node_url_1.default.parse(caps.webDriverAgentUrl);
|
|
518
|
+
if (lodash_1.default.isEmpty(protocol) || lodash_1.default.isEmpty(host)) {
|
|
519
|
+
throw this.log.errorWithException(`'webDriverAgentUrl' capability is expected to contain a valid WebDriverAgent server URL. ` +
|
|
520
|
+
`'${caps.webDriverAgentUrl}' is given instead`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (caps.browserName) {
|
|
524
|
+
if (caps.bundleId) {
|
|
525
|
+
throw this.log.errorWithException(`'browserName' cannot be set together with 'bundleId' capability`);
|
|
526
|
+
}
|
|
527
|
+
// warn if the capabilities have both `app` and `browser, although this
|
|
528
|
+
// is common with selenium grid
|
|
529
|
+
if (caps.app) {
|
|
530
|
+
this.log.warn(`The capabilities should generally not include both an 'app' and a 'browserName'`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (caps.permissions) {
|
|
534
|
+
try {
|
|
535
|
+
for (const [bundleId, perms] of lodash_1.default.toPairs(JSON.parse(caps.permissions))) {
|
|
536
|
+
if (!lodash_1.default.isString(bundleId)) {
|
|
537
|
+
throw new Error(`'${JSON.stringify(bundleId)}' must be a string`);
|
|
538
|
+
}
|
|
539
|
+
if (!lodash_1.default.isPlainObject(perms)) {
|
|
540
|
+
throw new Error(`'${JSON.stringify(perms)}' must be a JSON object`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
catch (e) {
|
|
545
|
+
throw this.log.errorWithException(`'${caps.permissions}' is expected to be a valid object with format ` +
|
|
546
|
+
`{"<bundleId1>": {"<serviceName1>": "<serviceStatus1>", ...}, ...}. Original error: ${e.message}`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (caps.platformVersion && !support_1.util.coerceVersion(caps.platformVersion, false)) {
|
|
550
|
+
throw this.log.errorWithException(`'platformVersion' must be a valid version number. ` +
|
|
551
|
+
`'${caps.platformVersion}' is given instead.`);
|
|
552
|
+
}
|
|
553
|
+
// additionalWebviewBundleIds is an array, JSON array, or string
|
|
554
|
+
if (caps.additionalWebviewBundleIds) {
|
|
555
|
+
caps.additionalWebviewBundleIds = this.helpers.parseCapsArray(caps.additionalWebviewBundleIds);
|
|
556
|
+
}
|
|
557
|
+
// finally, return true since the superclass check passed, as did this
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
// Getter methods
|
|
561
|
+
get wda() {
|
|
562
|
+
if (!this._wda) {
|
|
563
|
+
throw new Error('WebDriverAgent is not initialized');
|
|
564
|
+
}
|
|
565
|
+
return this._wda;
|
|
566
|
+
}
|
|
567
|
+
get driverData() {
|
|
568
|
+
// TODO fill out resource info here
|
|
569
|
+
return {};
|
|
570
|
+
}
|
|
571
|
+
get device() {
|
|
572
|
+
return this._device;
|
|
573
|
+
}
|
|
574
|
+
// Utility methods
|
|
575
|
+
isSafari() {
|
|
576
|
+
return !!this.safari;
|
|
577
|
+
}
|
|
578
|
+
isRealDevice() {
|
|
579
|
+
return 'devicectl' in (this.device ?? {});
|
|
580
|
+
}
|
|
581
|
+
isSimulator() {
|
|
582
|
+
return 'simctl' in (this.device ?? {});
|
|
583
|
+
}
|
|
584
|
+
isXcodebuildNeeded() {
|
|
585
|
+
return !(CAP_NAMES_NO_XCODEBUILD_REQUIRED.some((x) => Boolean(this.opts[x])));
|
|
586
|
+
}
|
|
587
|
+
// Core driver methods
|
|
335
588
|
async onSettingsUpdate(key, value) {
|
|
336
589
|
// skip sending the update request to the WDA nor saving it in opts
|
|
337
590
|
// to not spend unnecessary time.
|
|
@@ -343,39 +596,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
343
596
|
settings: { [key]: value },
|
|
344
597
|
});
|
|
345
598
|
}
|
|
346
|
-
this.opts[key] = !!value;
|
|
347
|
-
}
|
|
348
|
-
resetIos() {
|
|
349
|
-
this.opts = this.opts || {};
|
|
350
|
-
// @ts-ignore this is ok
|
|
351
|
-
this.wda = null;
|
|
352
|
-
this.jwpProxyActive = false;
|
|
353
|
-
this.proxyReqRes = null;
|
|
354
|
-
this.safari = false;
|
|
355
|
-
this.cachedWdaStatus = null;
|
|
356
|
-
this.curWebFrames = [];
|
|
357
|
-
this._currentUrl = null;
|
|
358
|
-
this.curContext = null;
|
|
359
|
-
this.xcodeVersion = undefined;
|
|
360
|
-
this.contexts = [];
|
|
361
|
-
this.implicitWaitMs = 0;
|
|
362
|
-
this.pageLoadMs = 6000;
|
|
363
|
-
this.landscapeWebCoordsOffset = 0;
|
|
364
|
-
this.remote = null;
|
|
365
|
-
this._conditionInducerService = null;
|
|
366
|
-
this._remoteXPCConditionInducerConnection = null;
|
|
367
|
-
this.webElementsCache = new lru_cache_1.LRUCache({
|
|
368
|
-
max: WEB_ELEMENTS_CACHE_SIZE,
|
|
369
|
-
});
|
|
370
|
-
this._waitingAtoms = {
|
|
371
|
-
count: 0,
|
|
372
|
-
alertNotifier: new node_events_1.default(),
|
|
373
|
-
alertMonitor: bluebird_1.default.resolve(),
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
get driverData() {
|
|
377
|
-
// TODO fill out resource info here
|
|
378
|
-
return {};
|
|
599
|
+
this.opts[key] = !!value;
|
|
379
600
|
}
|
|
380
601
|
async getStatus() {
|
|
381
602
|
const status = {
|
|
@@ -400,79 +621,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
400
621
|
}
|
|
401
622
|
return didMerge;
|
|
402
623
|
}
|
|
403
|
-
/**
|
|
404
|
-
* @returns {Simulator|RealDevice}
|
|
405
|
-
*/
|
|
406
|
-
get device() {
|
|
407
|
-
return this._device;
|
|
408
|
-
}
|
|
409
|
-
isXcodebuildNeeded() {
|
|
410
|
-
return !(CAP_NAMES_NO_XCODEBUILD_REQUIRED.some((x) => Boolean(this.opts[x])));
|
|
411
|
-
}
|
|
412
|
-
async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) {
|
|
413
|
-
try {
|
|
414
|
-
let [sessionId, caps] = await super.createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData);
|
|
415
|
-
// merge cli args to opts, and if we did merge any, revalidate opts to ensure the final set
|
|
416
|
-
// is also consistent
|
|
417
|
-
if (this.mergeCliArgsToOpts()) {
|
|
418
|
-
this.validateDesiredCaps({ ...caps, ...this.cliArgs });
|
|
419
|
-
}
|
|
420
|
-
await this.start();
|
|
421
|
-
// merge server capabilities + desired capabilities
|
|
422
|
-
caps = { ...defaultServerCaps, ...caps };
|
|
423
|
-
// update the udid with what is actually used
|
|
424
|
-
caps.udid = this.opts.udid;
|
|
425
|
-
// ensure we track nativeWebTap capability as a setting as well
|
|
426
|
-
if (lodash_1.default.has(this.opts, 'nativeWebTap')) {
|
|
427
|
-
await this.updateSettings({ nativeWebTap: this.opts.nativeWebTap });
|
|
428
|
-
}
|
|
429
|
-
// ensure we track nativeWebTapStrict capability as a setting as well
|
|
430
|
-
if (lodash_1.default.has(this.opts, 'nativeWebTapStrict')) {
|
|
431
|
-
await this.updateSettings({ nativeWebTapStrict: this.opts.nativeWebTapStrict });
|
|
432
|
-
}
|
|
433
|
-
// ensure we track useJSONSource capability as a setting as well
|
|
434
|
-
if (lodash_1.default.has(this.opts, 'useJSONSource')) {
|
|
435
|
-
await this.updateSettings({ useJSONSource: this.opts.useJSONSource });
|
|
436
|
-
}
|
|
437
|
-
/** @type {import('appium-webdriveragent').WDASettings} */
|
|
438
|
-
let wdaSettings = {
|
|
439
|
-
elementResponseAttributes: DEFAULT_SETTINGS.elementResponseAttributes,
|
|
440
|
-
shouldUseCompactResponses: DEFAULT_SETTINGS.shouldUseCompactResponses,
|
|
441
|
-
};
|
|
442
|
-
if ('elementResponseAttributes' in this.opts && lodash_1.default.isString(this.opts.elementResponseAttributes)) {
|
|
443
|
-
wdaSettings.elementResponseAttributes = this.opts.elementResponseAttributes;
|
|
444
|
-
}
|
|
445
|
-
if ('shouldUseCompactResponses' in this.opts && lodash_1.default.isBoolean(this.opts.shouldUseCompactResponses)) {
|
|
446
|
-
wdaSettings.shouldUseCompactResponses = this.opts.shouldUseCompactResponses;
|
|
447
|
-
}
|
|
448
|
-
if ('mjpegServerScreenshotQuality' in this.opts && lodash_1.default.isNumber(this.opts.mjpegServerScreenshotQuality)) {
|
|
449
|
-
wdaSettings.mjpegServerScreenshotQuality = this.opts.mjpegServerScreenshotQuality;
|
|
450
|
-
}
|
|
451
|
-
if ('mjpegServerFramerate' in this.opts && lodash_1.default.isNumber(this.opts.mjpegServerFramerate)) {
|
|
452
|
-
wdaSettings.mjpegServerFramerate = this.opts.mjpegServerFramerate;
|
|
453
|
-
}
|
|
454
|
-
if (lodash_1.default.has(this.opts, 'screenshotQuality')) {
|
|
455
|
-
this.log.info(`Setting the quality of phone screenshot: '${this.opts.screenshotQuality}'`);
|
|
456
|
-
wdaSettings.screenshotQuality = this.opts.screenshotQuality;
|
|
457
|
-
}
|
|
458
|
-
// ensure WDA gets our defaults instead of whatever its own might be
|
|
459
|
-
await this.updateSettings(wdaSettings);
|
|
460
|
-
await this.handleMjpegOptions();
|
|
461
|
-
return /** @type {[string, import('@appium/types').DriverCaps<XCUITestDriverConstraints>]} */ ([
|
|
462
|
-
sessionId,
|
|
463
|
-
caps,
|
|
464
|
-
]);
|
|
465
|
-
}
|
|
466
|
-
catch (e) {
|
|
467
|
-
this.log.error(JSON.stringify(e));
|
|
468
|
-
await this.deleteSession();
|
|
469
|
-
throw e;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* Handles MJPEG server-related capabilities
|
|
474
|
-
* @returns {Promise<void>}
|
|
475
|
-
*/
|
|
476
624
|
async handleMjpegOptions() {
|
|
477
625
|
await this.allocateMjpegServerPort();
|
|
478
626
|
// turn on mjpeg stream reading if requested
|
|
@@ -482,11 +630,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
482
630
|
await this.mjpegStream.start();
|
|
483
631
|
}
|
|
484
632
|
}
|
|
485
|
-
/**
|
|
486
|
-
* Allocates and configures port forwarding for the MJPEG server
|
|
487
|
-
* @returns {Promise<void>}
|
|
488
|
-
* @throws {Error} If port forwarding fails and mjpegServerPort capability value is provided explicitly
|
|
489
|
-
*/
|
|
490
633
|
async allocateMjpegServerPort() {
|
|
491
634
|
const mjpegServerPort = this.opts.mjpegServerPort || DEFAULT_MJPEG_SERVER_PORT;
|
|
492
635
|
this.log.debug(`Forwarding MJPEG server port ${mjpegServerPort} to local port ${mjpegServerPort}`);
|
|
@@ -510,10 +653,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
510
653
|
}
|
|
511
654
|
}
|
|
512
655
|
}
|
|
513
|
-
/**
|
|
514
|
-
* Returns the default URL for Safari browser
|
|
515
|
-
* @returns {string} The default URL
|
|
516
|
-
*/
|
|
517
656
|
getDefaultUrl() {
|
|
518
657
|
// Setting this to some external URL slows down the session init
|
|
519
658
|
return `${this.getWdaLocalhostRoot()}/health`;
|
|
@@ -533,7 +672,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
533
672
|
}
|
|
534
673
|
else {
|
|
535
674
|
this.log.info(`Setting simulator devices set path to '${this.opts.simulatorDevicesSetPath}'`);
|
|
536
|
-
|
|
675
|
+
this.device.devicesSetPath = this.opts.simulatorDevicesSetPath;
|
|
537
676
|
}
|
|
538
677
|
}
|
|
539
678
|
// at this point if there is no platformVersion, get it from the device
|
|
@@ -574,21 +713,26 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
574
713
|
}
|
|
575
714
|
}
|
|
576
715
|
await this.runReset();
|
|
577
|
-
this.
|
|
578
|
-
|
|
716
|
+
this._wda = new appium_webdriveragent_1.WebDriverAgent(
|
|
717
|
+
// @ts-ignore This property is not used by WDA, and will be removed in the future
|
|
718
|
+
this.xcodeVersion, {
|
|
579
719
|
...this.opts,
|
|
580
720
|
device: this.device,
|
|
581
721
|
realDevice: this.isRealDevice(),
|
|
582
722
|
iosSdkVersion: this._iosSdkVersion ?? undefined,
|
|
583
723
|
reqBasePath: this.basePath,
|
|
584
|
-
},
|
|
585
|
-
// @ts-ignore this is ok
|
|
586
|
-
this.log);
|
|
724
|
+
}, this.log);
|
|
587
725
|
// Derived data path retrieval is an expensive operation
|
|
588
726
|
// We could start that now in background and get the cached result
|
|
589
727
|
// whenever it is needed
|
|
590
|
-
|
|
591
|
-
|
|
728
|
+
(async () => {
|
|
729
|
+
try {
|
|
730
|
+
await this.wda.retrieveDerivedDataPath();
|
|
731
|
+
}
|
|
732
|
+
catch (e) {
|
|
733
|
+
this.log.debug(e);
|
|
734
|
+
}
|
|
735
|
+
})();
|
|
592
736
|
const memoizedLogInfo = lodash_1.default.memoize(() => {
|
|
593
737
|
this.log.info("'skipLogCapture' is set. Skipping starting logs such as crash, system, safari console and safari network.");
|
|
594
738
|
});
|
|
@@ -631,7 +775,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
631
775
|
if (this.opts.permissions) {
|
|
632
776
|
this.log.debug('Setting the requested permissions before WDA is started');
|
|
633
777
|
for (const [bundleId, permissionsMapping] of lodash_1.default.toPairs(JSON.parse(this.opts.permissions))) {
|
|
634
|
-
await
|
|
778
|
+
await this.device.setPermissions(bundleId, permissionsMapping);
|
|
635
779
|
}
|
|
636
780
|
}
|
|
637
781
|
// TODO: Deprecate and remove this block together with calendarAccessAuthorized capability
|
|
@@ -670,11 +814,40 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
670
814
|
}
|
|
671
815
|
}
|
|
672
816
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
817
|
+
async runReset(enforceSimulatorShutdown = false) {
|
|
818
|
+
this.logEvent('resetStarted');
|
|
819
|
+
if (this.isRealDevice()) {
|
|
820
|
+
await real_device_management_1.runRealDeviceReset.bind(this)();
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
await simulator_management_1.runSimulatorReset.bind(this)(enforceSimulatorShutdown);
|
|
824
|
+
}
|
|
825
|
+
this.logEvent('resetComplete');
|
|
826
|
+
}
|
|
827
|
+
async stop() {
|
|
828
|
+
this.jwpProxyActive = false;
|
|
829
|
+
this.proxyReqRes = null;
|
|
830
|
+
if (this._wda?.fullyStarted) {
|
|
831
|
+
if (this.wda.jwproxy) {
|
|
832
|
+
try {
|
|
833
|
+
await this.proxyCommand(`/session/${this.sessionId}`, 'DELETE');
|
|
834
|
+
}
|
|
835
|
+
catch (err) {
|
|
836
|
+
// an error here should not short-circuit the rest of clean up
|
|
837
|
+
this.log.debug(`Unable to DELETE session on WDA: '${err.message}'. Continuing shutdown.`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
// The former could cache the xcodebuild, so should not quit the process.
|
|
841
|
+
// If the session skipped the xcodebuild (this.wda.canSkipXcodebuild), the this.wda instance
|
|
842
|
+
// should quit properly.
|
|
843
|
+
if ((!this.wda.webDriverAgentUrl && this.opts.useNewWDA) || this.wda.canSkipXcodebuild) {
|
|
844
|
+
await this.wda.quit();
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
device_connections_factory_1.DEVICE_CONNECTIONS_FACTORY.releaseConnection(this.opts.udid);
|
|
848
|
+
}
|
|
676
849
|
async initSimulator() {
|
|
677
|
-
const device =
|
|
850
|
+
const device = this.device;
|
|
678
851
|
if (this.opts.shutdownOtherSimulators) {
|
|
679
852
|
this.assertFeatureEnabled(SHUTDOWN_OTHER_FEAT_NAME);
|
|
680
853
|
await simulator_management_1.shutdownOtherSimulators.bind(this)();
|
|
@@ -691,7 +864,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
691
864
|
if (await simulator_management_1.setLocalizationPrefs.bind(this)()) {
|
|
692
865
|
this.log.debug('Localization preferences have been updated');
|
|
693
866
|
}
|
|
694
|
-
/** @type {Promise[]} */
|
|
695
867
|
const promises = ['reduceMotion', 'reduceTransparency', 'autoFillPasswords']
|
|
696
868
|
.filter((optName) => lodash_1.default.isBoolean(this.opts[optName]))
|
|
697
869
|
.map((optName) => {
|
|
@@ -713,9 +885,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
713
885
|
}
|
|
714
886
|
this.logEvent('simStarted');
|
|
715
887
|
}
|
|
716
|
-
/**
|
|
717
|
-
* Start WebDriverAgentRunner
|
|
718
|
-
*/
|
|
719
888
|
async startWda() {
|
|
720
889
|
// Don't cleanup the processes if webDriverAgentUrl is set
|
|
721
890
|
if (!support_1.util.hasValue(this.wda.webDriverAgentUrl)) {
|
|
@@ -786,7 +955,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
786
955
|
this.log.debug(`Trying to start WebDriverAgent once since at least one of ${CAP_NAMES_NO_XCODEBUILD_REQUIRED} capabilities is provided`);
|
|
787
956
|
startupRetries = 1;
|
|
788
957
|
}
|
|
789
|
-
/** @type {Error|null} */
|
|
790
958
|
let shortCircuitError = null;
|
|
791
959
|
let retryCount = 0;
|
|
792
960
|
await (0, asyncbox_1.retryInterval)(startupRetries, startupRetryInterval, async () => {
|
|
@@ -798,207 +966,84 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
798
966
|
if (this.opts.usePreinstalledWDA) {
|
|
799
967
|
await this.preparePreinstalledWda();
|
|
800
968
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
this.
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
if (this.
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
this.cachedWdaStatus = this.cachedWdaStatus || (await this.proxyCommand('/status', 'GET'));
|
|
839
|
-
await this.startWdaSession(this.opts.bundleId, this.opts.processArguments);
|
|
840
|
-
this.logEvent('wdaSessionStarted');
|
|
841
|
-
}
|
|
842
|
-
catch (err) {
|
|
843
|
-
this.logEvent('wdaSessionFailed');
|
|
844
|
-
this.log.debug(err.stack);
|
|
845
|
-
if (err instanceof driver_1.errors.TimeoutError) {
|
|
846
|
-
// Session startup timed out. There is no point to retry
|
|
847
|
-
shortCircuitError = err;
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
let errorMsg = `Unable to start WebDriverAgent session. Original error: ${err.message}`;
|
|
851
|
-
if (this.isRealDevice() && lodash_1.default.includes(err.message, 'xcodebuild')) {
|
|
852
|
-
errorMsg += ` Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}.`;
|
|
853
|
-
}
|
|
854
|
-
throw new Error(errorMsg);
|
|
855
|
-
}
|
|
856
|
-
if (this.opts.clearSystemFiles && this.isXcodebuildNeeded()) {
|
|
857
|
-
await (0, utils_1.markSystemFilesForCleanup)(this.wda);
|
|
858
|
-
}
|
|
859
|
-
// We don't restrict the version, but show what version of WDA is running on the device for debugging purposes.
|
|
860
|
-
if (this.cachedWdaStatus?.build) {
|
|
861
|
-
this.log.info(`WebDriverAgent version: '${this.cachedWdaStatus.build.version}'`);
|
|
862
|
-
}
|
|
863
|
-
else {
|
|
864
|
-
this.log.warn(`WebDriverAgent does not provide any version information. ` +
|
|
865
|
-
`This might indicate either a custom or an outdated build.`);
|
|
866
|
-
}
|
|
867
|
-
// we expect certain socket errors until this point, but now
|
|
868
|
-
// mark things as fully working
|
|
869
|
-
this.wda.fullyStarted = true;
|
|
870
|
-
this.logEvent('wdaStarted');
|
|
871
|
-
});
|
|
872
|
-
if (shortCircuitError) {
|
|
873
|
-
throw shortCircuitError;
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
*
|
|
879
|
-
* @param {boolean} [enforceSimulatorShutdown=false]
|
|
880
|
-
*/
|
|
881
|
-
async runReset(enforceSimulatorShutdown = false) {
|
|
882
|
-
this.logEvent('resetStarted');
|
|
883
|
-
if (this.isRealDevice()) {
|
|
884
|
-
await real_device_management_1.runRealDeviceReset.bind(this)();
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
await simulator_management_1.runSimulatorReset.bind(this)(enforceSimulatorShutdown);
|
|
888
|
-
}
|
|
889
|
-
this.logEvent('resetComplete');
|
|
890
|
-
}
|
|
891
|
-
async deleteSession(sessionId) {
|
|
892
|
-
await utils_1.removeAllSessionWebSocketHandlers.bind(this)();
|
|
893
|
-
for (const recorder of lodash_1.default.compact([
|
|
894
|
-
this._recentScreenRecorder,
|
|
895
|
-
this._audioRecorder,
|
|
896
|
-
this._trafficCapture,
|
|
897
|
-
])) {
|
|
898
|
-
await recorder.interrupt(true);
|
|
899
|
-
await recorder.cleanup();
|
|
900
|
-
}
|
|
901
|
-
if (!lodash_1.default.isEmpty(this._perfRecorders)) {
|
|
902
|
-
await bluebird_1.default.all(this._perfRecorders.map((x) => x.stop(true)));
|
|
903
|
-
this._perfRecorders = [];
|
|
904
|
-
}
|
|
905
|
-
if (this._conditionInducerService || this._remoteXPCConditionInducerConnection) {
|
|
906
|
-
try {
|
|
907
|
-
await this.disableConditionInducer();
|
|
908
|
-
}
|
|
909
|
-
catch (err) {
|
|
910
|
-
this.log.warn(`Cannot disable condition inducer: ${err.message}`);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
await this.stop();
|
|
914
|
-
if (this.wda && this.isXcodebuildNeeded()) {
|
|
915
|
-
if (this.opts.clearSystemFiles) {
|
|
916
|
-
let synchronizationKey = XCUITestDriver.name;
|
|
917
|
-
const derivedDataPath = await this.wda.retrieveDerivedDataPath();
|
|
918
|
-
if (derivedDataPath) {
|
|
919
|
-
synchronizationKey = node_path_1.default.normalize(derivedDataPath);
|
|
920
|
-
}
|
|
921
|
-
await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
|
|
922
|
-
await (0, utils_1.clearSystemFiles)(this.wda);
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
else {
|
|
926
|
-
this.log.debug('Not clearing log files. Use `clearSystemFiles` capability to turn on.');
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
if (this.remote) {
|
|
930
|
-
this.log.debug('Found a remote debugger session. Removing...');
|
|
931
|
-
await this.stopRemote();
|
|
932
|
-
}
|
|
933
|
-
if (this.opts.resetOnSessionStartOnly === false) {
|
|
934
|
-
await this.runReset(true);
|
|
935
|
-
}
|
|
936
|
-
const simulatorDevice = this.isSimulator() ? /** @type {Simulator} */ (this.device) : null;
|
|
937
|
-
if (simulatorDevice && this.lifecycleData.createSim) {
|
|
938
|
-
this.log.debug(`Deleting simulator created for this run (udid: '${simulatorDevice.udid}')`);
|
|
939
|
-
await simulator_management_1.shutdownSimulator.bind(this)();
|
|
940
|
-
await simulatorDevice.delete();
|
|
941
|
-
}
|
|
942
|
-
const shouldResetLocationService = this.isRealDevice() && !!this.opts.resetLocationService;
|
|
943
|
-
if (shouldResetLocationService) {
|
|
944
|
-
try {
|
|
945
|
-
await this.mobileResetLocationService();
|
|
946
|
-
}
|
|
947
|
-
catch {
|
|
948
|
-
/* Ignore this error since mobileResetLocationService already logged the error */
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
await this.logs.syslog?.stopCapture();
|
|
952
|
-
lodash_1.default.values(this.logs).forEach((x) => x.removeAllListeners());
|
|
953
|
-
if (this._bidiServerLogListener) {
|
|
954
|
-
this.log.unwrap().off('log', this._bidiServerLogListener);
|
|
955
|
-
}
|
|
956
|
-
this.logs = {};
|
|
957
|
-
if (this.mjpegStream) {
|
|
958
|
-
this.log.info('Closing MJPEG stream');
|
|
959
|
-
this.mjpegStream.stop();
|
|
960
|
-
}
|
|
961
|
-
this.resetIos();
|
|
962
|
-
await super.deleteSession(sessionId);
|
|
963
|
-
}
|
|
964
|
-
async stop() {
|
|
965
|
-
this.jwpProxyActive = false;
|
|
966
|
-
this.proxyReqRes = null;
|
|
967
|
-
if (this.wda?.fullyStarted) {
|
|
968
|
-
if (this.wda.jwproxy) {
|
|
969
|
+
if (!this.sessionId) {
|
|
970
|
+
throw new Error('Session ID is required but was not set');
|
|
971
|
+
}
|
|
972
|
+
this.cachedWdaStatus = await this.wda.launch(this.sessionId);
|
|
973
|
+
}
|
|
974
|
+
catch (err) {
|
|
975
|
+
this.logEvent('wdaStartFailed');
|
|
976
|
+
this.log.debug(err.stack);
|
|
977
|
+
retryCount++;
|
|
978
|
+
let errorMsg = `Unable to launch WebDriverAgent. Original error: ${err.message}`;
|
|
979
|
+
if (this.isRealDevice()) {
|
|
980
|
+
errorMsg += `. Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}`;
|
|
981
|
+
}
|
|
982
|
+
if (this.opts.usePreinstalledWDA) {
|
|
983
|
+
try {
|
|
984
|
+
// In case the bundle id process start got failed because of
|
|
985
|
+
// auth popup in the device. Then, the bundle id process itself started. It is safe to stop it here.
|
|
986
|
+
await this.mobileKillApp(this.wda.bundleIdForXctest);
|
|
987
|
+
}
|
|
988
|
+
catch { }
|
|
989
|
+
;
|
|
990
|
+
// Mostly it failed to start the WDA process as no the bundle id
|
|
991
|
+
// e.g. '<bundle id of WDA> not found on device <udid>'
|
|
992
|
+
errorMsg = `Unable to launch WebDriverAgent. Original error: ${err.message}. ` +
|
|
993
|
+
`Make sure the application ${this.wda.bundleIdForXctest} exists and it is launchable.`;
|
|
994
|
+
if (this.isRealDevice()) {
|
|
995
|
+
errorMsg += ` ${WDA_REAL_DEV_TUTORIAL_URL} may help to complete the preparation.`;
|
|
996
|
+
}
|
|
997
|
+
;
|
|
998
|
+
throw new Error(errorMsg);
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
await quitAndUninstall(errorMsg);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
this.proxyReqRes = this.wda.proxyReqRes.bind(this.wda);
|
|
1005
|
+
this.jwpProxyActive = true;
|
|
969
1006
|
try {
|
|
970
|
-
|
|
1007
|
+
this.logEvent('wdaSessionAttempted');
|
|
1008
|
+
this.log.debug('Sending createSession command to WDA');
|
|
1009
|
+
this.cachedWdaStatus = this.cachedWdaStatus || (await this.proxyCommand('/status', 'GET'));
|
|
1010
|
+
await this.startWdaSession(this.opts.bundleId, this.opts.processArguments);
|
|
1011
|
+
this.logEvent('wdaSessionStarted');
|
|
971
1012
|
}
|
|
972
1013
|
catch (err) {
|
|
973
|
-
|
|
974
|
-
this.log.debug(
|
|
1014
|
+
this.logEvent('wdaSessionFailed');
|
|
1015
|
+
this.log.debug(err.stack);
|
|
1016
|
+
if (err instanceof driver_1.errors.TimeoutError) {
|
|
1017
|
+
// Session startup timed out. There is no point to retry
|
|
1018
|
+
shortCircuitError = err;
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
let errorMsg = `Unable to start WebDriverAgent session. Original error: ${err.message}`;
|
|
1022
|
+
if (this.isRealDevice() && lodash_1.default.includes(err.message, 'xcodebuild')) {
|
|
1023
|
+
errorMsg += ` Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}.`;
|
|
1024
|
+
}
|
|
1025
|
+
throw new Error(errorMsg);
|
|
975
1026
|
}
|
|
1027
|
+
if (this.opts.clearSystemFiles && this.isXcodebuildNeeded()) {
|
|
1028
|
+
await (0, utils_1.markSystemFilesForCleanup)(this.wda);
|
|
1029
|
+
}
|
|
1030
|
+
// We don't restrict the version, but show what version of WDA is running on the device for debugging purposes.
|
|
1031
|
+
if (this.cachedWdaStatus?.build) {
|
|
1032
|
+
this.log.info(`WebDriverAgent version: '${this.cachedWdaStatus.build.version}'`);
|
|
1033
|
+
}
|
|
1034
|
+
else {
|
|
1035
|
+
this.log.warn(`WebDriverAgent does not provide any version information. ` +
|
|
1036
|
+
`This might indicate either a custom or an outdated build.`);
|
|
1037
|
+
}
|
|
1038
|
+
// we expect certain socket errors until this point, but now
|
|
1039
|
+
// mark things as fully working
|
|
1040
|
+
this.wda.fullyStarted = true;
|
|
1041
|
+
this.logEvent('wdaStarted');
|
|
1042
|
+
});
|
|
1043
|
+
if (shortCircuitError) {
|
|
1044
|
+
throw shortCircuitError;
|
|
976
1045
|
}
|
|
977
|
-
|
|
978
|
-
// If the session skipped the xcodebuild (this.wda.canSkipXcodebuild), the this.wda instance
|
|
979
|
-
// should quit properly.
|
|
980
|
-
if ((!this.wda.webDriverAgentUrl && this.opts.useNewWDA) || this.wda.canSkipXcodebuild) {
|
|
981
|
-
await this.wda.quit();
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
device_connections_factory_1.DEVICE_CONNECTIONS_FACTORY.releaseConnection(this.opts.udid);
|
|
985
|
-
}
|
|
986
|
-
/**
|
|
987
|
-
*
|
|
988
|
-
* @param {string} cmd
|
|
989
|
-
* @param {...any} args
|
|
990
|
-
* @returns {Promise<any>}
|
|
991
|
-
*/
|
|
992
|
-
async executeCommand(cmd, ...args) {
|
|
993
|
-
this.log.debug(`Executing command '${cmd}'`);
|
|
994
|
-
if (cmd === 'receiveAsyncResponse') {
|
|
995
|
-
return await this.receiveAsyncResponse(...args);
|
|
996
|
-
}
|
|
997
|
-
// TODO: once this fix gets into base driver remove from here
|
|
998
|
-
if (cmd === 'getStatus') {
|
|
999
|
-
return await this.getStatus();
|
|
1000
|
-
}
|
|
1001
|
-
return await super.executeCommand(cmd, ...args);
|
|
1046
|
+
});
|
|
1002
1047
|
}
|
|
1003
1048
|
async configureApp() {
|
|
1004
1049
|
function appIsPackageOrBundle(app) {
|
|
@@ -1020,11 +1065,11 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1020
1065
|
switch (lodash_1.default.toLower(this.opts.app)) {
|
|
1021
1066
|
case 'settings':
|
|
1022
1067
|
this.opts.bundleId = 'com.apple.Preferences';
|
|
1023
|
-
this.opts.app =
|
|
1068
|
+
this.opts.app = undefined;
|
|
1024
1069
|
return;
|
|
1025
1070
|
case 'calendar':
|
|
1026
1071
|
this.opts.bundleId = 'com.apple.mobilecal';
|
|
1027
|
-
this.opts.app =
|
|
1072
|
+
this.opts.app = undefined;
|
|
1028
1073
|
return;
|
|
1029
1074
|
}
|
|
1030
1075
|
this.opts.app = await this.helpers.configureApp(this.opts.app, {
|
|
@@ -1114,9 +1159,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1114
1159
|
return { device, realDevice: false, udid: device.udid };
|
|
1115
1160
|
}
|
|
1116
1161
|
async startSim() {
|
|
1117
|
-
/** @type {import('appium-ios-simulator').DevicePreferences} */
|
|
1118
1162
|
const devicePreferences = {};
|
|
1119
|
-
/** @type {import('appium-ios-simulator').RunOptions} */
|
|
1120
1163
|
const runOpts = {
|
|
1121
1164
|
scaleFactor: this.opts.scaleFactor,
|
|
1122
1165
|
connectHardwareKeyboard: !!this.opts.connectHardwareKeyboard,
|
|
@@ -1145,7 +1188,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1145
1188
|
devicePreferences.SimulatorWindowRotationAngle = 0;
|
|
1146
1189
|
break;
|
|
1147
1190
|
}
|
|
1148
|
-
await
|
|
1191
|
+
await this.device.run(runOpts);
|
|
1149
1192
|
}
|
|
1150
1193
|
async createSim() {
|
|
1151
1194
|
this.lifecycleData.createSim = true;
|
|
@@ -1184,7 +1227,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1184
1227
|
// https://developer.apple.com/forums/thread/86951?answerId=263395022#263395022
|
|
1185
1228
|
env.TZ = this.opts.appTimeZone;
|
|
1186
1229
|
}
|
|
1187
|
-
/** @type {import('appium-webdriveragent').WDACapabilities} */
|
|
1188
1230
|
const wdaCaps = {
|
|
1189
1231
|
bundleId: this.opts.autoLaunch === false ? undefined : bundleId,
|
|
1190
1232
|
arguments: args,
|
|
@@ -1226,155 +1268,9 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1226
1268
|
});
|
|
1227
1269
|
this.log.info(`WDA session startup took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
1228
1270
|
}
|
|
1229
|
-
// Override Proxy methods from BaseDriver
|
|
1230
|
-
proxyActive() {
|
|
1231
|
-
return Boolean(this.jwpProxyActive);
|
|
1232
|
-
}
|
|
1233
|
-
getProxyAvoidList() {
|
|
1234
|
-
if (this.isWebview()) {
|
|
1235
|
-
return NO_PROXY_WEB_LIST;
|
|
1236
|
-
}
|
|
1237
|
-
return NO_PROXY_NATIVE_LIST;
|
|
1238
|
-
}
|
|
1239
|
-
canProxy() {
|
|
1240
|
-
return true;
|
|
1241
|
-
}
|
|
1242
|
-
/**
|
|
1243
|
-
* @returns {boolean}
|
|
1244
|
-
*/
|
|
1245
|
-
isSafari() {
|
|
1246
|
-
return !!this.safari;
|
|
1247
|
-
}
|
|
1248
|
-
/**
|
|
1249
|
-
* @returns {boolean}
|
|
1250
|
-
*/
|
|
1251
|
-
isRealDevice() {
|
|
1252
|
-
return 'devicectl' in (this.device ?? {});
|
|
1253
|
-
}
|
|
1254
|
-
/**
|
|
1255
|
-
* @returns {boolean}
|
|
1256
|
-
*/
|
|
1257
|
-
isSimulator() {
|
|
1258
|
-
return 'simctl' in (this.device ?? {});
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* @param {string} strategy
|
|
1262
|
-
*/
|
|
1263
|
-
validateLocatorStrategy(strategy) {
|
|
1264
|
-
super.validateLocatorStrategy(strategy, this.isWebContext());
|
|
1265
|
-
}
|
|
1266
|
-
/**
|
|
1267
|
-
* @param {any} caps
|
|
1268
|
-
* @returns {caps is import('@appium/types').DriverCaps<XCUITestDriverConstraints>}
|
|
1269
|
-
*/
|
|
1270
|
-
validateDesiredCaps(caps) {
|
|
1271
|
-
if (!super.validateDesiredCaps(caps)) {
|
|
1272
|
-
return false;
|
|
1273
|
-
}
|
|
1274
|
-
// make sure that the capabilities have one of `app` or `bundleId`
|
|
1275
|
-
if (lodash_1.default.toLower(caps.browserName) !== 'safari' && !caps.app && !caps.bundleId) {
|
|
1276
|
-
this.log.info('The desired capabilities include neither an app nor a bundleId. ' +
|
|
1277
|
-
'WebDriverAgent will be started without the default app');
|
|
1278
|
-
}
|
|
1279
|
-
if (!support_1.util.coerceVersion(String(caps.platformVersion), false)) {
|
|
1280
|
-
this.log.warn(`'platformVersion' capability ('${caps.platformVersion}') is not a valid version number. ` +
|
|
1281
|
-
`Consider fixing it or be ready to experience an inconsistent driver behavior.`);
|
|
1282
|
-
}
|
|
1283
|
-
let verifyProcessArgument = (processArguments) => {
|
|
1284
|
-
const { args, env } = processArguments;
|
|
1285
|
-
if (!lodash_1.default.isNil(args) && !lodash_1.default.isArray(args)) {
|
|
1286
|
-
throw this.log.errorWithException('processArguments.args must be an array of strings');
|
|
1287
|
-
}
|
|
1288
|
-
if (!lodash_1.default.isNil(env) && !lodash_1.default.isPlainObject(env)) {
|
|
1289
|
-
throw this.log.errorWithException('processArguments.env must be an object <key,value> pair {a:b, c:d}');
|
|
1290
|
-
}
|
|
1291
|
-
};
|
|
1292
|
-
// `processArguments` should be JSON string or an object with arguments and/ environment details
|
|
1293
|
-
if (caps.processArguments) {
|
|
1294
|
-
if (lodash_1.default.isString(caps.processArguments)) {
|
|
1295
|
-
try {
|
|
1296
|
-
// try to parse the string as JSON
|
|
1297
|
-
caps.processArguments = JSON.parse(caps.processArguments);
|
|
1298
|
-
verifyProcessArgument(caps.processArguments);
|
|
1299
|
-
}
|
|
1300
|
-
catch (err) {
|
|
1301
|
-
throw this.log.errorWithException(`processArguments must be a JSON format or an object with format {args : [], env : {a:b, c:d}}. ` +
|
|
1302
|
-
`Both environment and argument can be null. Error: ${err}`);
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
else if (lodash_1.default.isPlainObject(caps.processArguments)) {
|
|
1306
|
-
verifyProcessArgument(caps.processArguments);
|
|
1307
|
-
}
|
|
1308
|
-
else {
|
|
1309
|
-
throw this.log.errorWithException(`'processArguments must be an object, or a string JSON object with format {args : [], env : {a:b, c:d}}. ` +
|
|
1310
|
-
`Both environment and argument can be null.`);
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
// there is no point in having `keychainPath` without `keychainPassword`
|
|
1314
|
-
if ((caps.keychainPath && !caps.keychainPassword) ||
|
|
1315
|
-
(!caps.keychainPath && caps.keychainPassword)) {
|
|
1316
|
-
throw this.log.errorWithException(`If 'keychainPath' is set, 'keychainPassword' must also be set (and vice versa).`);
|
|
1317
|
-
}
|
|
1318
|
-
// `resetOnSessionStartOnly` should be set to true by default
|
|
1319
|
-
this.opts.resetOnSessionStartOnly =
|
|
1320
|
-
!support_1.util.hasValue(this.opts.resetOnSessionStartOnly) || this.opts.resetOnSessionStartOnly;
|
|
1321
|
-
this.opts.useNewWDA = support_1.util.hasValue(this.opts.useNewWDA) ? this.opts.useNewWDA : false;
|
|
1322
|
-
if (caps.commandTimeouts) {
|
|
1323
|
-
caps.commandTimeouts = (0, utils_1.normalizeCommandTimeouts)(caps.commandTimeouts);
|
|
1324
|
-
}
|
|
1325
|
-
if (lodash_1.default.isString(caps.webDriverAgentUrl)) {
|
|
1326
|
-
const { protocol, host } = node_url_1.default.parse(caps.webDriverAgentUrl);
|
|
1327
|
-
if (lodash_1.default.isEmpty(protocol) || lodash_1.default.isEmpty(host)) {
|
|
1328
|
-
throw this.log.errorWithException(`'webDriverAgentUrl' capability is expected to contain a valid WebDriverAgent server URL. ` +
|
|
1329
|
-
`'${caps.webDriverAgentUrl}' is given instead`);
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
if (caps.browserName) {
|
|
1333
|
-
if (caps.bundleId) {
|
|
1334
|
-
throw this.log.errorWithException(`'browserName' cannot be set together with 'bundleId' capability`);
|
|
1335
|
-
}
|
|
1336
|
-
// warn if the capabilities have both `app` and `browser, although this
|
|
1337
|
-
// is common with selenium grid
|
|
1338
|
-
if (caps.app) {
|
|
1339
|
-
this.log.warn(`The capabilities should generally not include both an 'app' and a 'browserName'`);
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
if (caps.permissions) {
|
|
1343
|
-
try {
|
|
1344
|
-
for (const [bundleId, perms] of lodash_1.default.toPairs(JSON.parse(caps.permissions))) {
|
|
1345
|
-
if (!lodash_1.default.isString(bundleId)) {
|
|
1346
|
-
throw new Error(`'${JSON.stringify(bundleId)}' must be a string`);
|
|
1347
|
-
}
|
|
1348
|
-
if (!lodash_1.default.isPlainObject(perms)) {
|
|
1349
|
-
throw new Error(`'${JSON.stringify(perms)}' must be a JSON object`);
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
catch (e) {
|
|
1354
|
-
throw this.log.errorWithException(`'${caps.permissions}' is expected to be a valid object with format ` +
|
|
1355
|
-
`{"<bundleId1>": {"<serviceName1>": "<serviceStatus1>", ...}, ...}. Original error: ${e.message}`);
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
if (caps.platformVersion && !support_1.util.coerceVersion(caps.platformVersion, false)) {
|
|
1359
|
-
throw this.log.errorWithException(`'platformVersion' must be a valid version number. ` +
|
|
1360
|
-
`'${caps.platformVersion}' is given instead.`);
|
|
1361
|
-
}
|
|
1362
|
-
// additionalWebviewBundleIds is an array, JSON array, or string
|
|
1363
|
-
if (caps.additionalWebviewBundleIds) {
|
|
1364
|
-
caps.additionalWebviewBundleIds = this.helpers.parseCapsArray(caps.additionalWebviewBundleIds);
|
|
1365
|
-
}
|
|
1366
|
-
// finally, return true since the superclass check passed, as did this
|
|
1367
|
-
return true;
|
|
1368
|
-
}
|
|
1369
|
-
/**
|
|
1370
|
-
* Check if the given app can be installed, or should uninstall before installing it.
|
|
1371
|
-
*
|
|
1372
|
-
* @param {AutInstallationStateOptions} [opts]
|
|
1373
|
-
* @returns {Promise<AutInstallationState>}
|
|
1374
|
-
*/
|
|
1375
1271
|
async checkAutInstallationState(opts) {
|
|
1376
1272
|
const { enforceAppInstall, fullReset, noReset, bundleId, app } = opts ?? this.opts;
|
|
1377
|
-
const wasAppInstalled = await this.device.isAppInstalled(bundleId);
|
|
1273
|
+
const wasAppInstalled = !!bundleId && await this.device.isAppInstalled(bundleId);
|
|
1378
1274
|
if (wasAppInstalled) {
|
|
1379
1275
|
this.log.info(`App '${bundleId}' is already installed`);
|
|
1380
1276
|
if (noReset) {
|
|
@@ -1395,7 +1291,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1395
1291
|
skipUninstall: !wasAppInstalled,
|
|
1396
1292
|
};
|
|
1397
1293
|
}
|
|
1398
|
-
const candidateBundleVersion = await this.appInfosCache.extractBundleVersion(app);
|
|
1294
|
+
const candidateBundleVersion = app ? await this.appInfosCache.extractBundleVersion(app) : undefined;
|
|
1399
1295
|
this.log.debug(`CFBundleVersion from Info.plist: ${candidateBundleVersion}`);
|
|
1400
1296
|
if (!candidateBundleVersion) {
|
|
1401
1297
|
return {
|
|
@@ -1404,8 +1300,8 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1404
1300
|
};
|
|
1405
1301
|
}
|
|
1406
1302
|
const appBundleVersion = this.isRealDevice()
|
|
1407
|
-
? (await
|
|
1408
|
-
: BUNDLE_VERSION_PATTERN.exec(await
|
|
1303
|
+
? (await this.device.fetchAppInfo(bundleId))?.CFBundleVersion
|
|
1304
|
+
: BUNDLE_VERSION_PATTERN.exec(await this.device.simctl.appInfo(bundleId))?.[1];
|
|
1409
1305
|
this.log.debug(`CFBundleVersion from installed app info: ${appBundleVersion}`);
|
|
1410
1306
|
if (!appBundleVersion) {
|
|
1411
1307
|
return {
|
|
@@ -1462,19 +1358,14 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1462
1358
|
}
|
|
1463
1359
|
if (support_1.util.hasValue(this.opts.iosInstallPause)) {
|
|
1464
1360
|
// https://github.com/appium/appium/issues/6889
|
|
1465
|
-
const pauseMs =
|
|
1361
|
+
const pauseMs = this.opts.iosInstallPause;
|
|
1466
1362
|
this.log.debug(`iosInstallPause set. Pausing ${pauseMs} ms before continuing`);
|
|
1467
1363
|
await bluebird_1.default.delay(pauseMs);
|
|
1468
1364
|
}
|
|
1469
1365
|
this.logEvent('appInstalled');
|
|
1470
1366
|
}
|
|
1471
1367
|
}
|
|
1472
|
-
/**
|
|
1473
|
-
* @param {string|string[]} otherApps
|
|
1474
|
-
* @returns {Promise<void>}
|
|
1475
|
-
*/
|
|
1476
1368
|
async installOtherApps(otherApps) {
|
|
1477
|
-
/** @type {string[]|undefined} */
|
|
1478
1369
|
let appsList;
|
|
1479
1370
|
try {
|
|
1480
1371
|
appsList = this.helpers.parseCapsArray(otherApps);
|
|
@@ -1486,13 +1377,11 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1486
1377
|
this.log.info(`Got zero apps from 'otherApps' capability value. Doing nothing`);
|
|
1487
1378
|
return;
|
|
1488
1379
|
}
|
|
1489
|
-
/** @type {string[]} */
|
|
1490
1380
|
const appPaths = await bluebird_1.default.all(appsList.map((app) => this.helpers.configureApp(app, {
|
|
1491
1381
|
onPostProcess: app_utils_1.onPostConfigureApp.bind(this),
|
|
1492
1382
|
onDownload: app_utils_1.onDownloadApp.bind(this),
|
|
1493
1383
|
supportedExtensions: app_utils_1.SUPPORTED_EXTENSIONS,
|
|
1494
1384
|
})));
|
|
1495
|
-
/** @type {string[]} */
|
|
1496
1385
|
const appIds = await bluebird_1.default.all(appPaths.map((appPath) => this.appInfosCache.extractBundleId(appPath)));
|
|
1497
1386
|
for (const [appId, appPath] of lodash_1.default.zip(appIds, appPaths)) {
|
|
1498
1387
|
if (this.isRealDevice()) {
|
|
@@ -1508,10 +1397,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1508
1397
|
}
|
|
1509
1398
|
}
|
|
1510
1399
|
}
|
|
1511
|
-
/**
|
|
1512
|
-
* @param {string} orientation
|
|
1513
|
-
* @returns {Promise<void>}
|
|
1514
|
-
*/
|
|
1515
1400
|
async setInitialOrientation(orientation) {
|
|
1516
1401
|
const dstOrientation = lodash_1.default.toUpper(orientation);
|
|
1517
1402
|
if (!SUPPORTED_ORIENATIONS.includes(dstOrientation)) {
|
|
@@ -1527,21 +1412,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1527
1412
|
this.log.warn(`Setting initial orientation failed with: ${err.message}`);
|
|
1528
1413
|
}
|
|
1529
1414
|
}
|
|
1530
|
-
/**
|
|
1531
|
-
* @param {string} [cmdName]
|
|
1532
|
-
* @returns {number|undefined}
|
|
1533
|
-
*/
|
|
1534
|
-
_getCommandTimeout(cmdName) {
|
|
1535
|
-
if (this.opts.commandTimeouts) {
|
|
1536
|
-
if (cmdName && lodash_1.default.has(this.opts.commandTimeouts, cmdName)) {
|
|
1537
|
-
return this.opts.commandTimeouts[cmdName];
|
|
1538
|
-
}
|
|
1539
|
-
return this.opts.commandTimeouts[utils_1.DEFAULT_TIMEOUT_KEY];
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
/**
|
|
1543
|
-
* Reset the current session (run the delete session and create session subroutines)
|
|
1544
|
-
*/
|
|
1545
1415
|
async reset() {
|
|
1546
1416
|
throw new Error(`The reset API has been deprecated and is not supported anymore. ` +
|
|
1547
1417
|
`Consider using corresponding 'mobile:' extensions to manage the state of the app under test.`);
|
|
@@ -1570,6 +1440,41 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1570
1440
|
await simulator_management_1.installToSimulator.bind(this)(this.opts.prebuiltWDAPath, candidateBundleId);
|
|
1571
1441
|
}
|
|
1572
1442
|
}
|
|
1443
|
+
resetIos() {
|
|
1444
|
+
this.opts = this.opts || {};
|
|
1445
|
+
this._wda = null;
|
|
1446
|
+
this.jwpProxyActive = false;
|
|
1447
|
+
this.proxyReqRes = null;
|
|
1448
|
+
this.safari = false;
|
|
1449
|
+
this.cachedWdaStatus = null;
|
|
1450
|
+
this.curWebFrames = [];
|
|
1451
|
+
this._currentUrl = null;
|
|
1452
|
+
this.curContext = null;
|
|
1453
|
+
this.xcodeVersion = undefined;
|
|
1454
|
+
this.contexts = [];
|
|
1455
|
+
this.implicitWaitMs = 0;
|
|
1456
|
+
this.pageLoadMs = 6000;
|
|
1457
|
+
this.landscapeWebCoordsOffset = 0;
|
|
1458
|
+
this.remote = null;
|
|
1459
|
+
this._conditionInducerService = null;
|
|
1460
|
+
this._remoteXPCConditionInducerConnection = null;
|
|
1461
|
+
this.webElementsCache = new lru_cache_1.LRUCache({
|
|
1462
|
+
max: WEB_ELEMENTS_CACHE_SIZE,
|
|
1463
|
+
});
|
|
1464
|
+
this._waitingAtoms = {
|
|
1465
|
+
count: 0,
|
|
1466
|
+
alertNotifier: new node_events_1.default(),
|
|
1467
|
+
alertMonitor: bluebird_1.default.resolve(),
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
_getCommandTimeout(cmdName) {
|
|
1471
|
+
if (this.opts.commandTimeouts) {
|
|
1472
|
+
if (cmdName && lodash_1.default.has(this.opts.commandTimeouts, cmdName)) {
|
|
1473
|
+
return this.opts.commandTimeouts[cmdName];
|
|
1474
|
+
}
|
|
1475
|
+
return this.opts.commandTimeouts[utils_1.DEFAULT_TIMEOUT_KEY];
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1573
1478
|
/*---------------+
|
|
1574
1479
|
| ACTIVEAPPINFO |
|
|
1575
1480
|
+---------------+*/
|
|
@@ -1945,32 +1850,4 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1945
1850
|
}
|
|
1946
1851
|
exports.XCUITestDriver = XCUITestDriver;
|
|
1947
1852
|
exports.default = XCUITestDriver;
|
|
1948
|
-
/**
|
|
1949
|
-
* @template {import('@appium/types').Constraints} C
|
|
1950
|
-
* @template [Ctx=string]
|
|
1951
|
-
* @typedef {import('@appium/types').ExternalDriver<C, Ctx>} ExternalDriver
|
|
1952
|
-
*/
|
|
1953
|
-
/**
|
|
1954
|
-
* @typedef {Pick<XCUITestDriverOpts, 'enforceAppInstall' | 'fullReset' | 'noReset' | 'bundleId' | 'app'>} AutInstallationStateOptions
|
|
1955
|
-
*/
|
|
1956
|
-
/**
|
|
1957
|
-
* @typedef {Object} AutInstallationState
|
|
1958
|
-
* @property {boolean} install - If the given app should install, or not need to install.
|
|
1959
|
-
* @property {boolean} skipUninstall - If the installed app should be uninstalled, or not.
|
|
1960
|
-
*/
|
|
1961
|
-
/**
|
|
1962
|
-
* @typedef {typeof desiredCapConstraints} XCUITestDriverConstraints
|
|
1963
|
-
* @typedef {import('@appium/types').DriverOpts<XCUITestDriverConstraints>} XCUITestDriverOpts
|
|
1964
|
-
* @typedef {import('./commands/types').FullContext} FullContext
|
|
1965
|
-
* @typedef {import('appium-xcode').XcodeVersion} XcodeVersion
|
|
1966
|
-
* @typedef {import('appium-ios-simulator').Simulator} Simulator
|
|
1967
|
-
*/
|
|
1968
|
-
/**
|
|
1969
|
-
* @typedef {Object} DriverLogs
|
|
1970
|
-
* @property {import('./device-log/ios-device-log').IOSDeviceLog|import('./device-log/ios-simulator-log').IOSSimulatorLog} [syslog]
|
|
1971
|
-
* @property {import('./device-log/ios-crash-log').IOSCrashLog} [crashlog]
|
|
1972
|
-
* @property {import('./device-log/safari-console-log').SafariConsoleLog} [safariConsole]
|
|
1973
|
-
* @property {import('./device-log/safari-network-log').SafariNetworkLog} [safariNetwork]
|
|
1974
|
-
* @property {import('./device-log/ios-performance-log').IOSPerformanceLog} [performance]
|
|
1975
|
-
*/
|
|
1976
1853
|
//# sourceMappingURL=driver.js.map
|