@limrun/appium-xcuitest-driver 10.4.3-lim.1 → 10.10.1-lim.1
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 +84 -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 +2 -2
- 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/bidi/models.d.ts.map +1 -1
- package/build/lib/commands/bidi/models.js +1 -0
- package/build/lib/commands/bidi/models.js.map +1 -1
- package/build/lib/commands/bidi/types.d.ts +1 -0
- package/build/lib/commands/bidi/types.d.ts.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/condition.d.ts +2 -0
- package/build/lib/commands/condition.d.ts.map +1 -1
- package/build/lib/commands/condition.js +75 -2
- package/build/lib/commands/condition.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.d.ts.map +1 -1
- package/build/lib/commands/file-movement.js +7 -7
- 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.d.ts +3 -2
- package/build/lib/commands/location.d.ts.map +1 -1
- package/build/lib/commands/location.js +10 -4
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/log.js +9 -9
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.js +1 -1
- package/build/lib/commands/memory.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/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +13 -4
- package/build/lib/commands/performance.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 +2 -2
- package/build/lib/commands/xctest-record-screen.js.map +1 -1
- package/build/lib/desired-caps.d.ts +392 -505
- package/build/lib/desired-caps.d.ts.map +1 -1
- package/build/lib/desired-caps.js +19 -10
- package/build/lib/desired-caps.js.map +1 -1
- package/build/lib/device/clients/base-device-client.d.ts +22 -0
- package/build/lib/device/clients/base-device-client.d.ts.map +1 -0
- package/build/lib/device/clients/base-device-client.js +14 -0
- package/build/lib/device/clients/base-device-client.js.map +1 -0
- package/build/lib/device/clients/py-ios-device-client.d.ts +21 -0
- package/build/lib/device/clients/py-ios-device-client.d.ts.map +1 -0
- package/build/lib/device/clients/py-ios-device-client.js +125 -0
- package/build/lib/device/clients/py-ios-device-client.js.map +1 -0
- package/build/lib/device/device-connections-factory.d.ts +18 -0
- package/build/lib/device/device-connections-factory.d.ts.map +1 -0
- package/build/lib/device/device-connections-factory.js +260 -0
- package/build/lib/device/device-connections-factory.js.map +1 -0
- package/build/lib/device/log/helpers.d.ts +10 -0
- package/build/lib/device/log/helpers.d.ts.map +1 -0
- package/build/lib/device/log/helpers.js +37 -0
- package/build/lib/device/log/helpers.js.map +1 -0
- package/build/lib/device/log/ios-crash-log.d.ts +34 -0
- package/build/lib/device/log/ios-crash-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-crash-log.js +141 -0
- package/build/lib/device/log/ios-crash-log.js.map +1 -0
- package/build/lib/device/log/ios-device-log.d.ts +19 -0
- package/build/lib/device/log/ios-device-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-device-log.js +42 -0
- package/build/lib/device/log/ios-device-log.js.map +1 -0
- package/build/lib/device/log/ios-log.d.ts +24 -0
- package/build/lib/device/log/ios-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-log.js +50 -0
- package/build/lib/device/log/ios-log.js.map +1 -0
- package/build/lib/device/log/ios-performance-log.d.ts +18 -0
- package/build/lib/device/log/ios-performance-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-performance-log.js +43 -0
- package/build/lib/device/log/ios-performance-log.js.map +1 -0
- package/build/lib/device/log/ios-simulator-log.d.ts +38 -0
- package/build/lib/device/log/ios-simulator-log.d.ts.map +1 -0
- package/build/lib/device/log/ios-simulator-log.js +184 -0
- package/build/lib/device/log/ios-simulator-log.js.map +1 -0
- package/build/lib/device/log/line-consuming-log.d.ts +9 -0
- package/build/lib/device/log/line-consuming-log.d.ts.map +1 -0
- package/build/lib/device/log/line-consuming-log.js +16 -0
- package/build/lib/device/log/line-consuming-log.js.map +1 -0
- package/build/lib/device/log/safari-console-log.d.ts +67 -0
- package/build/lib/device/log/safari-console-log.d.ts.map +1 -0
- package/build/lib/device/log/safari-console-log.js +81 -0
- package/build/lib/device/log/safari-console-log.js.map +1 -0
- package/build/lib/device/log/safari-network-log.d.ts +75 -0
- package/build/lib/device/log/safari-network-log.d.ts.map +1 -0
- package/build/lib/device/log/safari-network-log.js +47 -0
- package/build/lib/device/log/safari-network-log.js.map +1 -0
- package/build/lib/device/real-device-management.d.ts +146 -0
- package/build/lib/device/real-device-management.d.ts.map +1 -0
- package/build/lib/device/real-device-management.js +740 -0
- package/build/lib/device/real-device-management.js.map +1 -0
- package/build/lib/device/simulator-management.d.ts +65 -0
- package/build/lib/device/simulator-management.d.ts.map +1 -0
- package/build/lib/device/simulator-management.js +261 -0
- package/build/lib/device/simulator-management.js.map +1 -0
- package/build/lib/device-log/ios-crash-log.d.ts +1 -1
- package/build/lib/device-log/ios-crash-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-simulator-log.d.ts +1 -1
- package/build/lib/device-log/ios-simulator-log.d.ts.map +1 -1
- package/build/lib/doctor/required-checks.js +1 -1
- package/build/lib/doctor/required-checks.js.map +1 -1
- package/build/lib/driver.d.ts +129 -1377
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +461 -573
- 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/build/lib/simulator-management.d.ts +10 -0
- package/build/lib/simulator-management.d.ts.map +1 -1
- package/build/lib/simulator-management.js +9 -5
- package/build/lib/simulator-management.js.map +1 -1
- package/build/lib/utils.d.ts +2 -9
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +3 -47
- package/build/lib/utils.js.map +1 -1
- package/lib/app-utils.js +5 -1
- package/lib/commands/app-management.js +2 -2
- package/lib/commands/appearance.js +2 -2
- package/lib/commands/bidi/models.ts +1 -0
- package/lib/commands/bidi/types.ts +1 -0
- package/lib/commands/biometric.js +3 -3
- package/lib/commands/certificate.js +9 -3
- package/lib/commands/condition.js +85 -2
- package/lib/commands/context.js +6 -6
- package/lib/commands/file-movement.js +11 -7
- 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 +11 -4
- package/lib/commands/log.js +9 -9
- package/lib/commands/memory.js +1 -1
- package/lib/commands/notifications.js +1 -1
- package/lib/commands/pasteboard.js +2 -2
- package/lib/commands/pcap.js +1 -1
- package/lib/commands/performance.js +12 -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 +2 -2
- package/lib/{desired-caps.js → desired-caps.ts} +20 -6
- package/lib/{real-device-clients → device/clients}/py-ios-device-client.ts +1 -1
- package/lib/{device-connections-factory.js → device/device-connections-factory.ts} +96 -60
- package/lib/{device-log → device/log}/helpers.ts +1 -1
- package/lib/{device-log → device/log}/ios-crash-log.ts +4 -4
- package/lib/{device-log → device/log}/ios-log.ts +1 -1
- package/lib/{device-log → device/log}/ios-simulator-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 +831 -0
- package/lib/{simulator-management.js → device/simulator-management.ts} +75 -64
- package/lib/doctor/required-checks.ts +1 -1
- package/lib/{driver.js → driver.ts} +623 -707
- package/lib/{method-map.js → method-map.ts} +5 -2
- package/lib/utils.js +3 -54
- package/package.json +17 -19
- package/scripts/build-wda.js +3 -3
- package/lib/ios-fs-helpers.js +0 -355
- package/lib/ios-generic-simulators.js +0 -11
- package/lib/real-device-management.js +0 -133
- package/lib/real-device.js +0 -347
- package/lib/xcrun.js +0 -16
- /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}/safari-network-log.ts +0 -0
package/build/lib/driver.js
CHANGED
|
@@ -38,7 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.XCUITestDriver = void 0;
|
|
40
40
|
const appium_idb_1 = __importDefault(require("appium-idb"));
|
|
41
|
-
const appium_ios_simulator_1 = require("
|
|
41
|
+
const appium_ios_simulator_1 = require("appium-ios-simulator");
|
|
42
42
|
const appium_webdriveragent_1 = require("appium-webdriveragent");
|
|
43
43
|
const driver_1 = require("appium/driver");
|
|
44
44
|
const support_1 = require("appium/support");
|
|
@@ -98,13 +98,12 @@ const xctestCommands = __importStar(require("./commands/xctest"));
|
|
|
98
98
|
const xctestRecordScreenCommands = __importStar(require("./commands/xctest-record-screen"));
|
|
99
99
|
const increaseContrastCommands = __importStar(require("./commands/increase-contrast"));
|
|
100
100
|
const desired_caps_1 = require("./desired-caps");
|
|
101
|
-
const device_connections_factory_1 = require("./device-connections-factory");
|
|
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("./
|
|
105
|
-
const real_device_management_1 = require("./real-device-management");
|
|
106
|
-
const
|
|
107
|
-
const simulator_management_1 = require("./simulator-management");
|
|
104
|
+
const py_ios_device_client_1 = require("./device/clients/py-ios-device-client");
|
|
105
|
+
const real_device_management_1 = require("./device/real-device-management");
|
|
106
|
+
const simulator_management_1 = require("./device/simulator-management");
|
|
108
107
|
const utils_1 = require("./utils");
|
|
109
108
|
const app_infos_cache_1 = require("./app-infos-cache");
|
|
110
109
|
const context_1 = require("./commands/context");
|
|
@@ -147,7 +146,6 @@ const WEB_ELEMENTS_CACHE_SIZE = 500;
|
|
|
147
146
|
const SUPPORTED_ORIENATIONS = ['LANDSCAPE', 'PORTRAIT'];
|
|
148
147
|
const DEFAULT_MJPEG_SERVER_PORT = 9100;
|
|
149
148
|
/* eslint-disable no-useless-escape */
|
|
150
|
-
/** @type {import('@appium/types').RouteMatcher[]} */
|
|
151
149
|
const NO_PROXY_NATIVE_LIST = [
|
|
152
150
|
['DELETE', /window/],
|
|
153
151
|
['GET', /^\/session\/[^\/]+$/],
|
|
@@ -194,7 +192,7 @@ const NO_PROXY_NATIVE_LIST = [
|
|
|
194
192
|
['GET', /cookie/],
|
|
195
193
|
['POST', /cookie/],
|
|
196
194
|
];
|
|
197
|
-
const NO_PROXY_WEB_LIST =
|
|
195
|
+
const NO_PROXY_WEB_LIST = [
|
|
198
196
|
['GET', /attribute/],
|
|
199
197
|
['GET', /element/],
|
|
200
198
|
['GET', /text/],
|
|
@@ -206,84 +204,55 @@ const NO_PROXY_WEB_LIST = /** @type {import('@appium/types').RouteMatcher[]} */
|
|
|
206
204
|
['POST', /frame/],
|
|
207
205
|
['POST', /keys/],
|
|
208
206
|
['POST', /refresh/],
|
|
209
|
-
|
|
207
|
+
...NO_PROXY_NATIVE_LIST,
|
|
208
|
+
];
|
|
210
209
|
/* eslint-enable no-useless-escape */
|
|
211
210
|
const MEMOIZED_FUNCTIONS = ['getStatusBarHeight', 'getDevicePixelRatio', 'getScreenInfo'];
|
|
212
211
|
// Capabilities that do not have xcodebuild process
|
|
213
212
|
const CAP_NAMES_NO_XCODEBUILD_REQUIRED = ['webDriverAgentUrl', 'usePreinstalledWDA'];
|
|
214
213
|
const BUNDLE_VERSION_PATTERN = /CFBundleVersion\s+=\s+"?([^(;|")]+)/;
|
|
215
|
-
/**
|
|
216
|
-
* @implements {ExternalDriver<XCUITestDriverConstraints, FullContext|string>}
|
|
217
|
-
* @extends {BaseDriver<XCUITestDriverConstraints>}
|
|
218
|
-
* @privateRemarks **This class should be considered "final"**. It cannot be extended
|
|
219
|
-
* 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.
|
|
220
|
-
*/
|
|
221
214
|
class XCUITestDriver extends driver_1.BaseDriver {
|
|
222
215
|
static newMethodMap = method_map_1.newMethodMap;
|
|
223
216
|
static executeMethodMap = execute_method_map_1.executeMethodMap;
|
|
224
|
-
/** @type {string|null|undefined} */
|
|
225
217
|
curWindowHandle;
|
|
226
|
-
/**
|
|
227
|
-
* @type {boolean|undefined}
|
|
228
|
-
*/
|
|
229
218
|
selectingNewPage;
|
|
230
|
-
/** @type {string[]} */
|
|
231
219
|
contexts;
|
|
232
|
-
/** @type {string|null} */
|
|
233
220
|
curContext;
|
|
234
|
-
/** @type {string[]} */
|
|
235
221
|
curWebFrames;
|
|
236
|
-
/** @type {import('./types').CalibrationData|null} */
|
|
237
222
|
webviewCalibrationResult;
|
|
238
|
-
/** @type {import('./types').AsyncPromise|undefined} */
|
|
239
223
|
asyncPromise;
|
|
240
|
-
/** @type {number|undefined} */
|
|
241
224
|
asyncWaitMs;
|
|
242
|
-
/** @type {((logRecord: {message: string}) => void)|null} */
|
|
243
225
|
_syslogWebsocketListener;
|
|
244
|
-
/** @type {import('./commands/performance').PerfRecorder[]} */
|
|
245
226
|
_perfRecorders;
|
|
246
|
-
/** @type {LRUCache} */
|
|
247
227
|
webElementsCache;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
* @privateRemarks needs types
|
|
251
|
-
**/
|
|
252
|
-
_conditionInducerService;
|
|
253
|
-
/** @type {boolean|undefined} */
|
|
228
|
+
_conditionInducerService; // needs types
|
|
229
|
+
_remoteXPCConditionInducerConnection; // RemoteXPC DVT connection for iOS>=18 condition inducer
|
|
254
230
|
_isSafariIphone;
|
|
255
|
-
/** @type {boolean|undefined} */
|
|
256
231
|
_isSafariNotched;
|
|
257
|
-
/** @type {import('./commands/types').WaitingAtoms} */
|
|
258
232
|
_waitingAtoms;
|
|
259
|
-
/** @type {import('./types').LifecycleData} */
|
|
260
233
|
lifecycleData;
|
|
261
|
-
/** @type {import('./commands/record-audio').AudioRecorder|null} */
|
|
262
234
|
_audioRecorder;
|
|
263
|
-
/** @type {XcodeVersion|undefined} */
|
|
264
235
|
xcodeVersion;
|
|
265
|
-
/** @type {import('./commands/pcap').TrafficCapture|null} */
|
|
266
236
|
_trafficCapture;
|
|
267
|
-
/** @type {import('./commands/recordscreen').ScreenRecorder|null} */
|
|
268
237
|
_recentScreenRecorder;
|
|
269
|
-
/** @type {Simulator|RealDevice} */
|
|
270
238
|
_device;
|
|
271
|
-
/** @type {string|null} */
|
|
272
239
|
_iosSdkVersion;
|
|
273
|
-
|
|
274
|
-
wda;
|
|
275
|
-
/** @type {import('appium-remote-debugger').RemoteDebugger|null} */
|
|
240
|
+
_wda;
|
|
276
241
|
remote;
|
|
277
|
-
/** @type {DriverLogs} */
|
|
278
242
|
logs;
|
|
279
|
-
/** @type {import('./commands/types').LogListener|undefined} */
|
|
280
243
|
_bidiServerLogListener;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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) {
|
|
287
256
|
super(opts, shouldValidateCaps);
|
|
288
257
|
this.locatorStrategies = [
|
|
289
258
|
'xpath',
|
|
@@ -327,86 +296,13 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
327
296
|
this.appInfosCache = new app_infos_cache_1.AppInfosCache(this.log);
|
|
328
297
|
this.remote = null;
|
|
329
298
|
this.doesSupportBidi = true;
|
|
299
|
+
this._wda = null;
|
|
330
300
|
}
|
|
331
|
-
|
|
332
|
-
// skip sending the update request to the WDA nor saving it in opts
|
|
333
|
-
// to not spend unnecessary time.
|
|
334
|
-
if (['pageSourceExcludedAttributes'].includes(key)) {
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
if (key !== 'nativeWebTap' && key !== 'nativeWebTapStrict') {
|
|
338
|
-
return await this.proxyCommand('/appium/settings', 'POST', {
|
|
339
|
-
settings: { [key]: value },
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
this.opts[key] = !!value;
|
|
343
|
-
}
|
|
344
|
-
resetIos() {
|
|
345
|
-
this.opts = this.opts || {};
|
|
346
|
-
// @ts-ignore this is ok
|
|
347
|
-
this.wda = null;
|
|
348
|
-
this.jwpProxyActive = false;
|
|
349
|
-
this.proxyReqRes = null;
|
|
350
|
-
this.safari = false;
|
|
351
|
-
this.cachedWdaStatus = null;
|
|
352
|
-
this.curWebFrames = [];
|
|
353
|
-
this._currentUrl = null;
|
|
354
|
-
this.curContext = null;
|
|
355
|
-
this.xcodeVersion = undefined;
|
|
356
|
-
this.contexts = [];
|
|
357
|
-
this.implicitWaitMs = 0;
|
|
358
|
-
this.pageLoadMs = 6000;
|
|
359
|
-
this.landscapeWebCoordsOffset = 0;
|
|
360
|
-
this.remote = null;
|
|
361
|
-
this._conditionInducerService = null;
|
|
362
|
-
this.webElementsCache = new lru_cache_1.LRUCache({
|
|
363
|
-
max: WEB_ELEMENTS_CACHE_SIZE,
|
|
364
|
-
});
|
|
365
|
-
this._waitingAtoms = {
|
|
366
|
-
count: 0,
|
|
367
|
-
alertNotifier: new node_events_1.default(),
|
|
368
|
-
alertMonitor: bluebird_1.default.resolve(),
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
get driverData() {
|
|
372
|
-
// TODO fill out resource info here
|
|
373
|
-
return {};
|
|
374
|
-
}
|
|
375
|
-
async getStatus() {
|
|
376
|
-
const status = {
|
|
377
|
-
ready: true,
|
|
378
|
-
message: 'The driver is ready to accept new connections',
|
|
379
|
-
build: await (0, utils_1.getDriverInfo)(),
|
|
380
|
-
};
|
|
381
|
-
if (this.cachedWdaStatus) {
|
|
382
|
-
status.wda = this.cachedWdaStatus;
|
|
383
|
-
}
|
|
384
|
-
return status;
|
|
385
|
-
}
|
|
386
|
-
mergeCliArgsToOpts() {
|
|
387
|
-
let didMerge = false;
|
|
388
|
-
// this.cliArgs should never include anything we do not expect.
|
|
389
|
-
for (const [key, value] of Object.entries(this.cliArgs ?? {})) {
|
|
390
|
-
if (lodash_1.default.has(this.opts, key)) {
|
|
391
|
-
this.log.info(`CLI arg '${key}' with value '${value}' overwrites value '${this.opts[key]}' sent in via caps)`);
|
|
392
|
-
didMerge = true;
|
|
393
|
-
}
|
|
394
|
-
this.opts[key] = value;
|
|
395
|
-
}
|
|
396
|
-
return didMerge;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* @returns {Simulator|RealDevice}
|
|
400
|
-
*/
|
|
401
|
-
get device() {
|
|
402
|
-
return this._device;
|
|
403
|
-
}
|
|
404
|
-
isXcodebuildNeeded() {
|
|
405
|
-
return !(CAP_NAMES_NO_XCODEBUILD_REQUIRED.some((x) => Boolean(this.opts[x])));
|
|
406
|
-
}
|
|
301
|
+
// Override methods from BaseDriver
|
|
407
302
|
async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) {
|
|
408
303
|
try {
|
|
409
|
-
|
|
304
|
+
const [sessionId, initialCaps] = await super.createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData);
|
|
305
|
+
let caps = initialCaps;
|
|
410
306
|
// merge cli args to opts, and if we did merge any, revalidate opts to ensure the final set
|
|
411
307
|
// is also consistent
|
|
412
308
|
if (this.mergeCliArgsToOpts()) {
|
|
@@ -429,8 +325,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
429
325
|
if (lodash_1.default.has(this.opts, 'useJSONSource')) {
|
|
430
326
|
await this.updateSettings({ useJSONSource: this.opts.useJSONSource });
|
|
431
327
|
}
|
|
432
|
-
|
|
433
|
-
let wdaSettings = {
|
|
328
|
+
const wdaSettings = {
|
|
434
329
|
elementResponseAttributes: DEFAULT_SETTINGS.elementResponseAttributes,
|
|
435
330
|
shouldUseCompactResponses: DEFAULT_SETTINGS.shouldUseCompactResponses,
|
|
436
331
|
};
|
|
@@ -453,10 +348,10 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
453
348
|
// ensure WDA gets our defaults instead of whatever its own might be
|
|
454
349
|
await this.updateSettings(wdaSettings);
|
|
455
350
|
await this.handleMjpegOptions();
|
|
456
|
-
return
|
|
351
|
+
return [
|
|
457
352
|
sessionId,
|
|
458
353
|
caps,
|
|
459
|
-
]
|
|
354
|
+
];
|
|
460
355
|
}
|
|
461
356
|
catch (e) {
|
|
462
357
|
this.log.error(JSON.stringify(e));
|
|
@@ -464,10 +359,268 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
464
359
|
throw e;
|
|
465
360
|
}
|
|
466
361
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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());
|
|
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
|
|
588
|
+
async onSettingsUpdate(key, value) {
|
|
589
|
+
// skip sending the update request to the WDA nor saving it in opts
|
|
590
|
+
// to not spend unnecessary time.
|
|
591
|
+
if (['pageSourceExcludedAttributes'].includes(key)) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (key !== 'nativeWebTap' && key !== 'nativeWebTapStrict') {
|
|
595
|
+
return await this.proxyCommand('/appium/settings', 'POST', {
|
|
596
|
+
settings: { [key]: value },
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
this.opts[key] = !!value;
|
|
600
|
+
}
|
|
601
|
+
async getStatus() {
|
|
602
|
+
const status = {
|
|
603
|
+
ready: true,
|
|
604
|
+
message: 'The driver is ready to accept new connections',
|
|
605
|
+
build: await (0, utils_1.getDriverInfo)(),
|
|
606
|
+
};
|
|
607
|
+
if (this.cachedWdaStatus) {
|
|
608
|
+
status.wda = this.cachedWdaStatus;
|
|
609
|
+
}
|
|
610
|
+
return status;
|
|
611
|
+
}
|
|
612
|
+
mergeCliArgsToOpts() {
|
|
613
|
+
let didMerge = false;
|
|
614
|
+
// this.cliArgs should never include anything we do not expect.
|
|
615
|
+
for (const [key, value] of Object.entries(this.cliArgs ?? {})) {
|
|
616
|
+
if (lodash_1.default.has(this.opts, key)) {
|
|
617
|
+
this.log.info(`CLI arg '${key}' with value '${value}' overwrites value '${this.opts[key]}' sent in via caps)`);
|
|
618
|
+
didMerge = true;
|
|
619
|
+
}
|
|
620
|
+
this.opts[key] = value;
|
|
621
|
+
}
|
|
622
|
+
return didMerge;
|
|
623
|
+
}
|
|
471
624
|
async handleMjpegOptions() {
|
|
472
625
|
await this.allocateMjpegServerPort();
|
|
473
626
|
// turn on mjpeg stream reading if requested
|
|
@@ -477,11 +630,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
477
630
|
await this.mjpegStream.start();
|
|
478
631
|
}
|
|
479
632
|
}
|
|
480
|
-
/**
|
|
481
|
-
* Allocates and configures port forwarding for the MJPEG server
|
|
482
|
-
* @returns {Promise<void>}
|
|
483
|
-
* @throws {Error} If port forwarding fails and mjpegServerPort capability value is provided explicitly
|
|
484
|
-
*/
|
|
485
633
|
async allocateMjpegServerPort() {
|
|
486
634
|
const mjpegServerPort = this.opts.mjpegServerPort || DEFAULT_MJPEG_SERVER_PORT;
|
|
487
635
|
this.log.debug(`Forwarding MJPEG server port ${mjpegServerPort} to local port ${mjpegServerPort}`);
|
|
@@ -505,10 +653,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
505
653
|
}
|
|
506
654
|
}
|
|
507
655
|
}
|
|
508
|
-
/**
|
|
509
|
-
* Returns the default URL for Safari browser
|
|
510
|
-
* @returns {string} The default URL
|
|
511
|
-
*/
|
|
512
656
|
getDefaultUrl() {
|
|
513
657
|
// Setting this to some external URL slows down the session init
|
|
514
658
|
return `${this.getWdaLocalhostRoot()}/health`;
|
|
@@ -528,7 +672,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
528
672
|
}
|
|
529
673
|
else {
|
|
530
674
|
this.log.info(`Setting simulator devices set path to '${this.opts.simulatorDevicesSetPath}'`);
|
|
531
|
-
|
|
675
|
+
this.device.devicesSetPath = this.opts.simulatorDevicesSetPath;
|
|
532
676
|
}
|
|
533
677
|
}
|
|
534
678
|
// at this point if there is no platformVersion, get it from the device
|
|
@@ -569,21 +713,26 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
569
713
|
}
|
|
570
714
|
}
|
|
571
715
|
await this.runReset();
|
|
572
|
-
this.
|
|
573
|
-
|
|
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, {
|
|
574
719
|
...this.opts,
|
|
575
720
|
device: this.device,
|
|
576
721
|
realDevice: this.isRealDevice(),
|
|
577
722
|
iosSdkVersion: this._iosSdkVersion ?? undefined,
|
|
578
723
|
reqBasePath: this.basePath,
|
|
579
|
-
},
|
|
580
|
-
// @ts-ignore this is ok
|
|
581
|
-
this.log);
|
|
724
|
+
}, this.log);
|
|
582
725
|
// Derived data path retrieval is an expensive operation
|
|
583
726
|
// We could start that now in background and get the cached result
|
|
584
727
|
// whenever it is needed
|
|
585
|
-
|
|
586
|
-
|
|
728
|
+
(async () => {
|
|
729
|
+
try {
|
|
730
|
+
await this.wda.retrieveDerivedDataPath();
|
|
731
|
+
}
|
|
732
|
+
catch (e) {
|
|
733
|
+
this.log.debug(e);
|
|
734
|
+
}
|
|
735
|
+
})();
|
|
587
736
|
const memoizedLogInfo = lodash_1.default.memoize(() => {
|
|
588
737
|
this.log.info("'skipLogCapture' is set. Skipping starting logs such as crash, system, safari console and safari network.");
|
|
589
738
|
});
|
|
@@ -626,7 +775,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
626
775
|
if (this.opts.permissions) {
|
|
627
776
|
this.log.debug('Setting the requested permissions before WDA is started');
|
|
628
777
|
for (const [bundleId, permissionsMapping] of lodash_1.default.toPairs(JSON.parse(this.opts.permissions))) {
|
|
629
|
-
await
|
|
778
|
+
await this.device.setPermissions(bundleId, permissionsMapping);
|
|
630
779
|
}
|
|
631
780
|
}
|
|
632
781
|
// TODO: Deprecate and remove this block together with calendarAccessAuthorized capability
|
|
@@ -665,11 +814,40 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
665
814
|
}
|
|
666
815
|
}
|
|
667
816
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
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
|
+
}
|
|
671
849
|
async initSimulator() {
|
|
672
|
-
const device =
|
|
850
|
+
const device = this.device;
|
|
673
851
|
if (this.opts.shutdownOtherSimulators) {
|
|
674
852
|
this.assertFeatureEnabled(SHUTDOWN_OTHER_FEAT_NAME);
|
|
675
853
|
await simulator_management_1.shutdownOtherSimulators.bind(this)();
|
|
@@ -686,7 +864,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
686
864
|
if (await simulator_management_1.setLocalizationPrefs.bind(this)()) {
|
|
687
865
|
this.log.debug('Localization preferences have been updated');
|
|
688
866
|
}
|
|
689
|
-
/** @type {Promise[]} */
|
|
690
867
|
const promises = ['reduceMotion', 'reduceTransparency', 'autoFillPasswords']
|
|
691
868
|
.filter((optName) => lodash_1.default.isBoolean(this.opts[optName]))
|
|
692
869
|
.map((optName) => {
|
|
@@ -698,6 +875,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
698
875
|
try {
|
|
699
876
|
const idb = new appium_idb_1.default({ udid: this.opts.udid });
|
|
700
877
|
await idb.connect();
|
|
878
|
+
// @ts-ignore This is ok. We are going to ditch idb soon anyway
|
|
701
879
|
device.idb = idb;
|
|
702
880
|
}
|
|
703
881
|
catch (e) {
|
|
@@ -707,9 +885,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
707
885
|
}
|
|
708
886
|
this.logEvent('simStarted');
|
|
709
887
|
}
|
|
710
|
-
/**
|
|
711
|
-
* Start WebDriverAgentRunner
|
|
712
|
-
*/
|
|
713
888
|
async startWda() {
|
|
714
889
|
// Don't cleanup the processes if webDriverAgentUrl is set
|
|
715
890
|
if (!support_1.util.hasValue(this.wda.webDriverAgentUrl)) {
|
|
@@ -780,7 +955,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
780
955
|
this.log.debug(`Trying to start WebDriverAgent once since at least one of ${CAP_NAMES_NO_XCODEBUILD_REQUIRED} capabilities is provided`);
|
|
781
956
|
startupRetries = 1;
|
|
782
957
|
}
|
|
783
|
-
/** @type {Error|null} */
|
|
784
958
|
let shortCircuitError = null;
|
|
785
959
|
let retryCount = 0;
|
|
786
960
|
await (0, asyncbox_1.retryInterval)(startupRetries, startupRetryInterval, async () => {
|
|
@@ -791,203 +965,85 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
791
965
|
try {
|
|
792
966
|
if (this.opts.usePreinstalledWDA) {
|
|
793
967
|
await this.preparePreinstalledWda();
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
this.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
}
|
|
805
|
-
if (this.
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
this.cachedWdaStatus = this.cachedWdaStatus || (await this.proxyCommand('/status', 'GET'));
|
|
833
|
-
await this.startWdaSession(this.opts.bundleId, this.opts.processArguments);
|
|
834
|
-
this.logEvent('wdaSessionStarted');
|
|
835
|
-
}
|
|
836
|
-
catch (err) {
|
|
837
|
-
this.logEvent('wdaSessionFailed');
|
|
838
|
-
this.log.debug(err.stack);
|
|
839
|
-
if (err instanceof driver_1.errors.TimeoutError) {
|
|
840
|
-
// Session startup timed out. There is no point to retry
|
|
841
|
-
shortCircuitError = err;
|
|
842
|
-
return;
|
|
843
|
-
}
|
|
844
|
-
let errorMsg = `Unable to start WebDriverAgent session. Original error: ${err.message}`;
|
|
845
|
-
if (this.isRealDevice() && lodash_1.default.includes(err.message, 'xcodebuild')) {
|
|
846
|
-
errorMsg += ` Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}.`;
|
|
847
|
-
}
|
|
848
|
-
throw new Error(errorMsg);
|
|
849
|
-
}
|
|
850
|
-
if (this.opts.clearSystemFiles && this.isXcodebuildNeeded()) {
|
|
851
|
-
await (0, utils_1.markSystemFilesForCleanup)(this.wda);
|
|
852
|
-
}
|
|
853
|
-
// We don't restrict the version, but show what version of WDA is running on the device for debugging purposes.
|
|
854
|
-
if (this.cachedWdaStatus?.build) {
|
|
855
|
-
this.log.info(`WebDriverAgent version: '${this.cachedWdaStatus.build.version}'`);
|
|
856
|
-
}
|
|
857
|
-
else {
|
|
858
|
-
this.log.warn(`WebDriverAgent does not provide any version information. ` +
|
|
859
|
-
`This might indicate either a custom or an outdated build.`);
|
|
860
|
-
}
|
|
861
|
-
// we expect certain socket errors until this point, but now
|
|
862
|
-
// mark things as fully working
|
|
863
|
-
this.wda.fullyStarted = true;
|
|
864
|
-
this.logEvent('wdaStarted');
|
|
865
|
-
});
|
|
866
|
-
if (shortCircuitError) {
|
|
867
|
-
throw shortCircuitError;
|
|
868
|
-
}
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
/**
|
|
872
|
-
*
|
|
873
|
-
* @param {boolean} [enforceSimulatorShutdown=false]
|
|
874
|
-
*/
|
|
875
|
-
async runReset(enforceSimulatorShutdown = false) {
|
|
876
|
-
this.logEvent('resetStarted');
|
|
877
|
-
if (this.isRealDevice()) {
|
|
878
|
-
await real_device_management_1.runRealDeviceReset.bind(this)();
|
|
879
|
-
}
|
|
880
|
-
else {
|
|
881
|
-
await simulator_management_1.runSimulatorReset.bind(this)(enforceSimulatorShutdown);
|
|
882
|
-
}
|
|
883
|
-
this.logEvent('resetComplete');
|
|
884
|
-
}
|
|
885
|
-
async deleteSession(sessionId) {
|
|
886
|
-
await utils_1.removeAllSessionWebSocketHandlers.bind(this)();
|
|
887
|
-
for (const recorder of lodash_1.default.compact([
|
|
888
|
-
this._recentScreenRecorder,
|
|
889
|
-
this._audioRecorder,
|
|
890
|
-
this._trafficCapture,
|
|
891
|
-
])) {
|
|
892
|
-
await recorder.interrupt(true);
|
|
893
|
-
await recorder.cleanup();
|
|
894
|
-
}
|
|
895
|
-
if (!lodash_1.default.isEmpty(this._perfRecorders)) {
|
|
896
|
-
await bluebird_1.default.all(this._perfRecorders.map((x) => x.stop(true)));
|
|
897
|
-
this._perfRecorders = [];
|
|
898
|
-
}
|
|
899
|
-
if (this._conditionInducerService) {
|
|
900
|
-
this.disableConditionInducer();
|
|
901
|
-
}
|
|
902
|
-
await this.stop();
|
|
903
|
-
if (this.wda && this.isXcodebuildNeeded()) {
|
|
904
|
-
if (this.opts.clearSystemFiles) {
|
|
905
|
-
let synchronizationKey = XCUITestDriver.name;
|
|
906
|
-
const derivedDataPath = await this.wda.retrieveDerivedDataPath();
|
|
907
|
-
if (derivedDataPath) {
|
|
908
|
-
synchronizationKey = node_path_1.default.normalize(derivedDataPath);
|
|
909
|
-
}
|
|
910
|
-
await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
|
|
911
|
-
await (0, utils_1.clearSystemFiles)(this.wda);
|
|
912
|
-
});
|
|
913
|
-
}
|
|
914
|
-
else {
|
|
915
|
-
this.log.debug('Not clearing log files. Use `clearSystemFiles` capability to turn on.');
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
if (this.remote) {
|
|
919
|
-
this.log.debug('Found a remote debugger session. Removing...');
|
|
920
|
-
await this.stopRemote();
|
|
921
|
-
}
|
|
922
|
-
if (this.opts.resetOnSessionStartOnly === false) {
|
|
923
|
-
await this.runReset(true);
|
|
924
|
-
}
|
|
925
|
-
const simulatorDevice = this.isSimulator() ? /** @type {Simulator} */ (this.device) : null;
|
|
926
|
-
if (simulatorDevice && this.lifecycleData.createSim) {
|
|
927
|
-
this.log.debug(`Deleting simulator created for this run (udid: '${simulatorDevice.udid}')`);
|
|
928
|
-
await simulator_management_1.shutdownSimulator.bind(this)();
|
|
929
|
-
await simulatorDevice.delete();
|
|
930
|
-
}
|
|
931
|
-
const shouldResetLocationService = this.isRealDevice() && !!this.opts.resetLocationService;
|
|
932
|
-
if (shouldResetLocationService) {
|
|
933
|
-
try {
|
|
934
|
-
await this.mobileResetLocationService();
|
|
935
|
-
}
|
|
936
|
-
catch {
|
|
937
|
-
/* Ignore this error since mobileResetLocationService already logged the error */
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
await this.logs.syslog?.stopCapture();
|
|
941
|
-
lodash_1.default.values(this.logs).forEach((x) => x.removeAllListeners());
|
|
942
|
-
if (this._bidiServerLogListener) {
|
|
943
|
-
this.log.unwrap().off('log', this._bidiServerLogListener);
|
|
944
|
-
}
|
|
945
|
-
this.logs = {};
|
|
946
|
-
if (this.mjpegStream) {
|
|
947
|
-
this.log.info('Closing MJPEG stream');
|
|
948
|
-
this.mjpegStream.stop();
|
|
949
|
-
}
|
|
950
|
-
this.resetIos();
|
|
951
|
-
await super.deleteSession(sessionId);
|
|
952
|
-
}
|
|
953
|
-
async stop() {
|
|
954
|
-
this.jwpProxyActive = false;
|
|
955
|
-
this.proxyReqRes = null;
|
|
956
|
-
if (this.wda?.fullyStarted) {
|
|
957
|
-
if (this.wda.jwproxy) {
|
|
968
|
+
}
|
|
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;
|
|
958
1006
|
try {
|
|
959
|
-
|
|
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');
|
|
960
1012
|
}
|
|
961
1013
|
catch (err) {
|
|
962
|
-
|
|
963
|
-
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);
|
|
964
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;
|
|
965
1045
|
}
|
|
966
|
-
|
|
967
|
-
// If the session skipped the xcodebuild (this.wda.canSkipXcodebuild), the this.wda instance
|
|
968
|
-
// should quit properly.
|
|
969
|
-
if ((!this.wda.webDriverAgentUrl && this.opts.useNewWDA) || this.wda.canSkipXcodebuild) {
|
|
970
|
-
await this.wda.quit();
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
device_connections_factory_1.DEVICE_CONNECTIONS_FACTORY.releaseConnection(this.opts.udid);
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
*
|
|
977
|
-
* @param {string} cmd
|
|
978
|
-
* @param {...any} args
|
|
979
|
-
* @returns {Promise<any>}
|
|
980
|
-
*/
|
|
981
|
-
async executeCommand(cmd, ...args) {
|
|
982
|
-
this.log.debug(`Executing command '${cmd}'`);
|
|
983
|
-
if (cmd === 'receiveAsyncResponse') {
|
|
984
|
-
return await this.receiveAsyncResponse(...args);
|
|
985
|
-
}
|
|
986
|
-
// TODO: once this fix gets into base driver remove from here
|
|
987
|
-
if (cmd === 'getStatus') {
|
|
988
|
-
return await this.getStatus();
|
|
989
|
-
}
|
|
990
|
-
return await super.executeCommand(cmd, ...args);
|
|
1046
|
+
});
|
|
991
1047
|
}
|
|
992
1048
|
async configureApp() {
|
|
993
1049
|
function appIsPackageOrBundle(app) {
|
|
@@ -1009,11 +1065,11 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1009
1065
|
switch (lodash_1.default.toLower(this.opts.app)) {
|
|
1010
1066
|
case 'settings':
|
|
1011
1067
|
this.opts.bundleId = 'com.apple.Preferences';
|
|
1012
|
-
this.opts.app =
|
|
1068
|
+
this.opts.app = undefined;
|
|
1013
1069
|
return;
|
|
1014
1070
|
case 'calendar':
|
|
1015
1071
|
this.opts.bundleId = 'com.apple.mobilecal';
|
|
1016
|
-
this.opts.app =
|
|
1072
|
+
this.opts.app = undefined;
|
|
1017
1073
|
return;
|
|
1018
1074
|
}
|
|
1019
1075
|
this.opts.app = await this.helpers.configureApp(this.opts.app, {
|
|
@@ -1025,8 +1081,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1025
1081
|
async determineDevice() {
|
|
1026
1082
|
// in the one case where we create a sim, we will set this state
|
|
1027
1083
|
this.lifecycleData.createSim = false;
|
|
1028
|
-
// if we get generic names, translate them
|
|
1029
|
-
this.opts.deviceName = (0, utils_1.translateDeviceName)(this.opts.platformVersion ?? '', this.opts.deviceName);
|
|
1030
1084
|
const setupVersionCaps = async () => {
|
|
1031
1085
|
this._iosSdkVersion = await (0, utils_1.getAndCheckIosSdkVersion)();
|
|
1032
1086
|
this.log.info(`iOS SDK Version set to '${this._iosSdkVersion}'`);
|
|
@@ -1060,7 +1114,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1060
1114
|
let isRealDeviceUdid = false;
|
|
1061
1115
|
const shouldCheckAvailableRealDevices = !this.opts.webDriverAgentUrl;
|
|
1062
1116
|
if (shouldCheckAvailableRealDevices) {
|
|
1063
|
-
const devices = await (0,
|
|
1117
|
+
const devices = await (0, real_device_management_1.getConnectedDevices)();
|
|
1064
1118
|
this.log.debug(`Available real devices: ${devices.join(', ')}`);
|
|
1065
1119
|
isRealDeviceUdid = devices.includes(this.opts.udid);
|
|
1066
1120
|
}
|
|
@@ -1070,6 +1124,8 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1070
1124
|
devicesSetPath: this.opts.simulatorDevicesSetPath,
|
|
1071
1125
|
// @ts-ignore This is ok
|
|
1072
1126
|
logger: this.log,
|
|
1127
|
+
limInstanceApiUrl: this.opts.limInstanceApiUrl,
|
|
1128
|
+
limInstanceToken: this.opts.limInstanceToken,
|
|
1073
1129
|
});
|
|
1074
1130
|
return { device, realDevice: false, udid: this.opts.udid };
|
|
1075
1131
|
}
|
|
@@ -1082,7 +1138,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1082
1138
|
}
|
|
1083
1139
|
}
|
|
1084
1140
|
this.log.debug(`Creating iDevice object with udid '${this.opts.udid}'`);
|
|
1085
|
-
const device = new
|
|
1141
|
+
const device = new real_device_management_1.RealDevice(this.opts.udid, this.log);
|
|
1086
1142
|
return { device, realDevice: true, udid: this.opts.udid };
|
|
1087
1143
|
}
|
|
1088
1144
|
this.log.info(`No real device udid has been provided in capabilities. ` +
|
|
@@ -1105,9 +1161,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1105
1161
|
return { device, realDevice: false, udid: device.udid };
|
|
1106
1162
|
}
|
|
1107
1163
|
async startSim() {
|
|
1108
|
-
/** @type {import('@limrun/appium-ios-simulator').DevicePreferences} */
|
|
1109
1164
|
const devicePreferences = {};
|
|
1110
|
-
/** @type {import('@limrun/appium-ios-simulator').RunOptions} */
|
|
1111
1165
|
const runOpts = {
|
|
1112
1166
|
scaleFactor: this.opts.scaleFactor,
|
|
1113
1167
|
connectHardwareKeyboard: !!this.opts.connectHardwareKeyboard,
|
|
@@ -1136,7 +1190,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1136
1190
|
devicePreferences.SimulatorWindowRotationAngle = 0;
|
|
1137
1191
|
break;
|
|
1138
1192
|
}
|
|
1139
|
-
await
|
|
1193
|
+
await this.device.run(runOpts);
|
|
1140
1194
|
}
|
|
1141
1195
|
async createSim() {
|
|
1142
1196
|
this.lifecycleData.createSim = true;
|
|
@@ -1175,7 +1229,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1175
1229
|
// https://developer.apple.com/forums/thread/86951?answerId=263395022#263395022
|
|
1176
1230
|
env.TZ = this.opts.appTimeZone;
|
|
1177
1231
|
}
|
|
1178
|
-
/** @type {import('appium-webdriveragent').WDACapabilities} */
|
|
1179
1232
|
const wdaCaps = {
|
|
1180
1233
|
bundleId: this.opts.autoLaunch === false ? undefined : bundleId,
|
|
1181
1234
|
arguments: args,
|
|
@@ -1217,155 +1270,9 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1217
1270
|
});
|
|
1218
1271
|
this.log.info(`WDA session startup took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
1219
1272
|
}
|
|
1220
|
-
// Override Proxy methods from BaseDriver
|
|
1221
|
-
proxyActive() {
|
|
1222
|
-
return Boolean(this.jwpProxyActive);
|
|
1223
|
-
}
|
|
1224
|
-
getProxyAvoidList() {
|
|
1225
|
-
if (this.isWebview()) {
|
|
1226
|
-
return NO_PROXY_WEB_LIST;
|
|
1227
|
-
}
|
|
1228
|
-
return NO_PROXY_NATIVE_LIST;
|
|
1229
|
-
}
|
|
1230
|
-
canProxy() {
|
|
1231
|
-
return true;
|
|
1232
|
-
}
|
|
1233
|
-
/**
|
|
1234
|
-
* @returns {boolean}
|
|
1235
|
-
*/
|
|
1236
|
-
isSafari() {
|
|
1237
|
-
return !!this.safari;
|
|
1238
|
-
}
|
|
1239
|
-
/**
|
|
1240
|
-
* @returns {boolean}
|
|
1241
|
-
*/
|
|
1242
|
-
isRealDevice() {
|
|
1243
|
-
return 'devicectl' in (this.device ?? {});
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* @returns {boolean}
|
|
1247
|
-
*/
|
|
1248
|
-
isSimulator() {
|
|
1249
|
-
return 'simctl' in (this.device ?? {});
|
|
1250
|
-
}
|
|
1251
|
-
/**
|
|
1252
|
-
* @param {string} strategy
|
|
1253
|
-
*/
|
|
1254
|
-
validateLocatorStrategy(strategy) {
|
|
1255
|
-
super.validateLocatorStrategy(strategy, this.isWebContext());
|
|
1256
|
-
}
|
|
1257
|
-
/**
|
|
1258
|
-
* @param {any} caps
|
|
1259
|
-
* @returns {caps is import('@appium/types').DriverCaps<XCUITestDriverConstraints>}
|
|
1260
|
-
*/
|
|
1261
|
-
validateDesiredCaps(caps) {
|
|
1262
|
-
if (!super.validateDesiredCaps(caps)) {
|
|
1263
|
-
return false;
|
|
1264
|
-
}
|
|
1265
|
-
// make sure that the capabilities have one of `app` or `bundleId`
|
|
1266
|
-
if (lodash_1.default.toLower(caps.browserName) !== 'safari' && !caps.app && !caps.bundleId) {
|
|
1267
|
-
this.log.info('The desired capabilities include neither an app nor a bundleId. ' +
|
|
1268
|
-
'WebDriverAgent will be started without the default app');
|
|
1269
|
-
}
|
|
1270
|
-
if (!support_1.util.coerceVersion(String(caps.platformVersion), false)) {
|
|
1271
|
-
this.log.warn(`'platformVersion' capability ('${caps.platformVersion}') is not a valid version number. ` +
|
|
1272
|
-
`Consider fixing it or be ready to experience an inconsistent driver behavior.`);
|
|
1273
|
-
}
|
|
1274
|
-
let verifyProcessArgument = (processArguments) => {
|
|
1275
|
-
const { args, env } = processArguments;
|
|
1276
|
-
if (!lodash_1.default.isNil(args) && !lodash_1.default.isArray(args)) {
|
|
1277
|
-
throw this.log.errorWithException('processArguments.args must be an array of strings');
|
|
1278
|
-
}
|
|
1279
|
-
if (!lodash_1.default.isNil(env) && !lodash_1.default.isPlainObject(env)) {
|
|
1280
|
-
throw this.log.errorWithException('processArguments.env must be an object <key,value> pair {a:b, c:d}');
|
|
1281
|
-
}
|
|
1282
|
-
};
|
|
1283
|
-
// `processArguments` should be JSON string or an object with arguments and/ environment details
|
|
1284
|
-
if (caps.processArguments) {
|
|
1285
|
-
if (lodash_1.default.isString(caps.processArguments)) {
|
|
1286
|
-
try {
|
|
1287
|
-
// try to parse the string as JSON
|
|
1288
|
-
caps.processArguments = JSON.parse(caps.processArguments);
|
|
1289
|
-
verifyProcessArgument(caps.processArguments);
|
|
1290
|
-
}
|
|
1291
|
-
catch (err) {
|
|
1292
|
-
throw this.log.errorWithException(`processArguments must be a JSON format or an object with format {args : [], env : {a:b, c:d}}. ` +
|
|
1293
|
-
`Both environment and argument can be null. Error: ${err}`);
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
else if (lodash_1.default.isPlainObject(caps.processArguments)) {
|
|
1297
|
-
verifyProcessArgument(caps.processArguments);
|
|
1298
|
-
}
|
|
1299
|
-
else {
|
|
1300
|
-
throw this.log.errorWithException(`'processArguments must be an object, or a string JSON object with format {args : [], env : {a:b, c:d}}. ` +
|
|
1301
|
-
`Both environment and argument can be null.`);
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
// there is no point in having `keychainPath` without `keychainPassword`
|
|
1305
|
-
if ((caps.keychainPath && !caps.keychainPassword) ||
|
|
1306
|
-
(!caps.keychainPath && caps.keychainPassword)) {
|
|
1307
|
-
throw this.log.errorWithException(`If 'keychainPath' is set, 'keychainPassword' must also be set (and vice versa).`);
|
|
1308
|
-
}
|
|
1309
|
-
// `resetOnSessionStartOnly` should be set to true by default
|
|
1310
|
-
this.opts.resetOnSessionStartOnly =
|
|
1311
|
-
!support_1.util.hasValue(this.opts.resetOnSessionStartOnly) || this.opts.resetOnSessionStartOnly;
|
|
1312
|
-
this.opts.useNewWDA = support_1.util.hasValue(this.opts.useNewWDA) ? this.opts.useNewWDA : false;
|
|
1313
|
-
if (caps.commandTimeouts) {
|
|
1314
|
-
caps.commandTimeouts = (0, utils_1.normalizeCommandTimeouts)(caps.commandTimeouts);
|
|
1315
|
-
}
|
|
1316
|
-
if (lodash_1.default.isString(caps.webDriverAgentUrl)) {
|
|
1317
|
-
const { protocol, host } = node_url_1.default.parse(caps.webDriverAgentUrl);
|
|
1318
|
-
if (lodash_1.default.isEmpty(protocol) || lodash_1.default.isEmpty(host)) {
|
|
1319
|
-
throw this.log.errorWithException(`'webDriverAgentUrl' capability is expected to contain a valid WebDriverAgent server URL. ` +
|
|
1320
|
-
`'${caps.webDriverAgentUrl}' is given instead`);
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
if (caps.browserName) {
|
|
1324
|
-
if (caps.bundleId) {
|
|
1325
|
-
throw this.log.errorWithException(`'browserName' cannot be set together with 'bundleId' capability`);
|
|
1326
|
-
}
|
|
1327
|
-
// warn if the capabilities have both `app` and `browser, although this
|
|
1328
|
-
// is common with selenium grid
|
|
1329
|
-
if (caps.app) {
|
|
1330
|
-
this.log.warn(`The capabilities should generally not include both an 'app' and a 'browserName'`);
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
if (caps.permissions) {
|
|
1334
|
-
try {
|
|
1335
|
-
for (const [bundleId, perms] of lodash_1.default.toPairs(JSON.parse(caps.permissions))) {
|
|
1336
|
-
if (!lodash_1.default.isString(bundleId)) {
|
|
1337
|
-
throw new Error(`'${JSON.stringify(bundleId)}' must be a string`);
|
|
1338
|
-
}
|
|
1339
|
-
if (!lodash_1.default.isPlainObject(perms)) {
|
|
1340
|
-
throw new Error(`'${JSON.stringify(perms)}' must be a JSON object`);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
catch (e) {
|
|
1345
|
-
throw this.log.errorWithException(`'${caps.permissions}' is expected to be a valid object with format ` +
|
|
1346
|
-
`{"<bundleId1>": {"<serviceName1>": "<serviceStatus1>", ...}, ...}. Original error: ${e.message}`);
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
if (caps.platformVersion && !support_1.util.coerceVersion(caps.platformVersion, false)) {
|
|
1350
|
-
throw this.log.errorWithException(`'platformVersion' must be a valid version number. ` +
|
|
1351
|
-
`'${caps.platformVersion}' is given instead.`);
|
|
1352
|
-
}
|
|
1353
|
-
// additionalWebviewBundleIds is an array, JSON array, or string
|
|
1354
|
-
if (caps.additionalWebviewBundleIds) {
|
|
1355
|
-
caps.additionalWebviewBundleIds = this.helpers.parseCapsArray(caps.additionalWebviewBundleIds);
|
|
1356
|
-
}
|
|
1357
|
-
// finally, return true since the superclass check passed, as did this
|
|
1358
|
-
return true;
|
|
1359
|
-
}
|
|
1360
|
-
/**
|
|
1361
|
-
* Check if the given app can be installed, or should uninstall before installing it.
|
|
1362
|
-
*
|
|
1363
|
-
* @param {AutInstallationStateOptions} [opts]
|
|
1364
|
-
* @returns {Promise<AutInstallationState>}
|
|
1365
|
-
*/
|
|
1366
1273
|
async checkAutInstallationState(opts) {
|
|
1367
1274
|
const { enforceAppInstall, fullReset, noReset, bundleId, app } = opts ?? this.opts;
|
|
1368
|
-
const wasAppInstalled = await this.device.isAppInstalled(bundleId);
|
|
1275
|
+
const wasAppInstalled = !!bundleId && await this.device.isAppInstalled(bundleId);
|
|
1369
1276
|
if (wasAppInstalled) {
|
|
1370
1277
|
this.log.info(`App '${bundleId}' is already installed`);
|
|
1371
1278
|
if (noReset) {
|
|
@@ -1386,7 +1293,7 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1386
1293
|
skipUninstall: !wasAppInstalled,
|
|
1387
1294
|
};
|
|
1388
1295
|
}
|
|
1389
|
-
const candidateBundleVersion = await this.appInfosCache.extractBundleVersion(app);
|
|
1296
|
+
const candidateBundleVersion = app ? await this.appInfosCache.extractBundleVersion(app) : undefined;
|
|
1390
1297
|
this.log.debug(`CFBundleVersion from Info.plist: ${candidateBundleVersion}`);
|
|
1391
1298
|
if (!candidateBundleVersion) {
|
|
1392
1299
|
return {
|
|
@@ -1395,8 +1302,8 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1395
1302
|
};
|
|
1396
1303
|
}
|
|
1397
1304
|
const appBundleVersion = this.isRealDevice()
|
|
1398
|
-
? (await
|
|
1399
|
-
: BUNDLE_VERSION_PATTERN.exec(await
|
|
1305
|
+
? (await this.device.fetchAppInfo(bundleId))?.CFBundleVersion
|
|
1306
|
+
: BUNDLE_VERSION_PATTERN.exec(await this.device.simctl.appInfo(bundleId))?.[1];
|
|
1400
1307
|
this.log.debug(`CFBundleVersion from installed app info: ${appBundleVersion}`);
|
|
1401
1308
|
if (!appBundleVersion) {
|
|
1402
1309
|
return {
|
|
@@ -1453,19 +1360,14 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1453
1360
|
}
|
|
1454
1361
|
if (support_1.util.hasValue(this.opts.iosInstallPause)) {
|
|
1455
1362
|
// https://github.com/appium/appium/issues/6889
|
|
1456
|
-
const pauseMs =
|
|
1363
|
+
const pauseMs = this.opts.iosInstallPause;
|
|
1457
1364
|
this.log.debug(`iosInstallPause set. Pausing ${pauseMs} ms before continuing`);
|
|
1458
1365
|
await bluebird_1.default.delay(pauseMs);
|
|
1459
1366
|
}
|
|
1460
1367
|
this.logEvent('appInstalled');
|
|
1461
1368
|
}
|
|
1462
1369
|
}
|
|
1463
|
-
/**
|
|
1464
|
-
* @param {string|string[]} otherApps
|
|
1465
|
-
* @returns {Promise<void>}
|
|
1466
|
-
*/
|
|
1467
1370
|
async installOtherApps(otherApps) {
|
|
1468
|
-
/** @type {string[]|undefined} */
|
|
1469
1371
|
let appsList;
|
|
1470
1372
|
try {
|
|
1471
1373
|
appsList = this.helpers.parseCapsArray(otherApps);
|
|
@@ -1477,13 +1379,11 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1477
1379
|
this.log.info(`Got zero apps from 'otherApps' capability value. Doing nothing`);
|
|
1478
1380
|
return;
|
|
1479
1381
|
}
|
|
1480
|
-
/** @type {string[]} */
|
|
1481
1382
|
const appPaths = await bluebird_1.default.all(appsList.map((app) => this.helpers.configureApp(app, {
|
|
1482
1383
|
onPostProcess: app_utils_1.onPostConfigureApp.bind(this),
|
|
1483
1384
|
onDownload: app_utils_1.onDownloadApp.bind(this),
|
|
1484
1385
|
supportedExtensions: app_utils_1.SUPPORTED_EXTENSIONS,
|
|
1485
1386
|
})));
|
|
1486
|
-
/** @type {string[]} */
|
|
1487
1387
|
const appIds = await bluebird_1.default.all(appPaths.map((appPath) => this.appInfosCache.extractBundleId(appPath)));
|
|
1488
1388
|
for (const [appId, appPath] of lodash_1.default.zip(appIds, appPaths)) {
|
|
1489
1389
|
if (this.isRealDevice()) {
|
|
@@ -1499,10 +1399,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1499
1399
|
}
|
|
1500
1400
|
}
|
|
1501
1401
|
}
|
|
1502
|
-
/**
|
|
1503
|
-
* @param {string} orientation
|
|
1504
|
-
* @returns {Promise<void>}
|
|
1505
|
-
*/
|
|
1506
1402
|
async setInitialOrientation(orientation) {
|
|
1507
1403
|
const dstOrientation = lodash_1.default.toUpper(orientation);
|
|
1508
1404
|
if (!SUPPORTED_ORIENATIONS.includes(dstOrientation)) {
|
|
@@ -1518,21 +1414,6 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1518
1414
|
this.log.warn(`Setting initial orientation failed with: ${err.message}`);
|
|
1519
1415
|
}
|
|
1520
1416
|
}
|
|
1521
|
-
/**
|
|
1522
|
-
* @param {string} [cmdName]
|
|
1523
|
-
* @returns {number|undefined}
|
|
1524
|
-
*/
|
|
1525
|
-
_getCommandTimeout(cmdName) {
|
|
1526
|
-
if (this.opts.commandTimeouts) {
|
|
1527
|
-
if (cmdName && lodash_1.default.has(this.opts.commandTimeouts, cmdName)) {
|
|
1528
|
-
return this.opts.commandTimeouts[cmdName];
|
|
1529
|
-
}
|
|
1530
|
-
return this.opts.commandTimeouts[utils_1.DEFAULT_TIMEOUT_KEY];
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
/**
|
|
1534
|
-
* Reset the current session (run the delete session and create session subroutines)
|
|
1535
|
-
*/
|
|
1536
1417
|
async reset() {
|
|
1537
1418
|
throw new Error(`The reset API has been deprecated and is not supported anymore. ` +
|
|
1538
1419
|
`Consider using corresponding 'mobile:' extensions to manage the state of the app under test.`);
|
|
@@ -1561,6 +1442,41 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1561
1442
|
await simulator_management_1.installToSimulator.bind(this)(this.opts.prebuiltWDAPath, candidateBundleId);
|
|
1562
1443
|
}
|
|
1563
1444
|
}
|
|
1445
|
+
resetIos() {
|
|
1446
|
+
this.opts = this.opts || {};
|
|
1447
|
+
this._wda = null;
|
|
1448
|
+
this.jwpProxyActive = false;
|
|
1449
|
+
this.proxyReqRes = null;
|
|
1450
|
+
this.safari = false;
|
|
1451
|
+
this.cachedWdaStatus = null;
|
|
1452
|
+
this.curWebFrames = [];
|
|
1453
|
+
this._currentUrl = null;
|
|
1454
|
+
this.curContext = null;
|
|
1455
|
+
this.xcodeVersion = undefined;
|
|
1456
|
+
this.contexts = [];
|
|
1457
|
+
this.implicitWaitMs = 0;
|
|
1458
|
+
this.pageLoadMs = 6000;
|
|
1459
|
+
this.landscapeWebCoordsOffset = 0;
|
|
1460
|
+
this.remote = null;
|
|
1461
|
+
this._conditionInducerService = null;
|
|
1462
|
+
this._remoteXPCConditionInducerConnection = null;
|
|
1463
|
+
this.webElementsCache = new lru_cache_1.LRUCache({
|
|
1464
|
+
max: WEB_ELEMENTS_CACHE_SIZE,
|
|
1465
|
+
});
|
|
1466
|
+
this._waitingAtoms = {
|
|
1467
|
+
count: 0,
|
|
1468
|
+
alertNotifier: new node_events_1.default(),
|
|
1469
|
+
alertMonitor: bluebird_1.default.resolve(),
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
_getCommandTimeout(cmdName) {
|
|
1473
|
+
if (this.opts.commandTimeouts) {
|
|
1474
|
+
if (cmdName && lodash_1.default.has(this.opts.commandTimeouts, cmdName)) {
|
|
1475
|
+
return this.opts.commandTimeouts[cmdName];
|
|
1476
|
+
}
|
|
1477
|
+
return this.opts.commandTimeouts[utils_1.DEFAULT_TIMEOUT_KEY];
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1564
1480
|
/*---------------+
|
|
1565
1481
|
| ACTIVEAPPINFO |
|
|
1566
1482
|
+---------------+*/
|
|
@@ -1936,32 +1852,4 @@ class XCUITestDriver extends driver_1.BaseDriver {
|
|
|
1936
1852
|
}
|
|
1937
1853
|
exports.XCUITestDriver = XCUITestDriver;
|
|
1938
1854
|
exports.default = XCUITestDriver;
|
|
1939
|
-
/**
|
|
1940
|
-
* @template {import('@appium/types').Constraints} C
|
|
1941
|
-
* @template [Ctx=string]
|
|
1942
|
-
* @typedef {import('@appium/types').ExternalDriver<C, Ctx>} ExternalDriver
|
|
1943
|
-
*/
|
|
1944
|
-
/**
|
|
1945
|
-
* @typedef {Pick<XCUITestDriverOpts, 'enforceAppInstall' | 'fullReset' | 'noReset' | 'bundleId' | 'app'>} AutInstallationStateOptions
|
|
1946
|
-
*/
|
|
1947
|
-
/**
|
|
1948
|
-
* @typedef {Object} AutInstallationState
|
|
1949
|
-
* @property {boolean} install - If the given app should install, or not need to install.
|
|
1950
|
-
* @property {boolean} skipUninstall - If the installed app should be uninstalled, or not.
|
|
1951
|
-
*/
|
|
1952
|
-
/**
|
|
1953
|
-
* @typedef {typeof desiredCapConstraints} XCUITestDriverConstraints
|
|
1954
|
-
* @typedef {import('@appium/types').DriverOpts<XCUITestDriverConstraints>} XCUITestDriverOpts
|
|
1955
|
-
* @typedef {import('./commands/types').FullContext} FullContext
|
|
1956
|
-
* @typedef {import('@limrun/appium-xcode').XcodeVersion} XcodeVersion
|
|
1957
|
-
* @typedef {import('@limrun/appium-ios-simulator').Simulator} Simulator
|
|
1958
|
-
*/
|
|
1959
|
-
/**
|
|
1960
|
-
* @typedef {Object} DriverLogs
|
|
1961
|
-
* @property {import('./device-log/ios-device-log').IOSDeviceLog|import('./device-log/ios-simulator-log').IOSSimulatorLog} [syslog]
|
|
1962
|
-
* @property {import('./device-log/ios-crash-log').IOSCrashLog} [crashlog]
|
|
1963
|
-
* @property {import('./device-log/safari-console-log').SafariConsoleLog} [safariConsole]
|
|
1964
|
-
* @property {import('./device-log/safari-network-log').SafariNetworkLog} [safariNetwork]
|
|
1965
|
-
* @property {import('./device-log/ios-performance-log').IOSPerformanceLog} [performance]
|
|
1966
|
-
*/
|
|
1967
1855
|
//# sourceMappingURL=driver.js.map
|