appium-webdriveragent 10.5.3 → 11.0.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 +23 -0
- package/Scripts/{build-webdriveragent.js → build-webdriveragent.mjs} +13 -7
- package/Scripts/{fetch-prebuilt-wda.js → fetch-prebuilt-wda.mjs} +17 -9
- package/Scripts/update-wda-version.mjs +42 -0
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +6503 -6229
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +4107 -3883
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -2
- package/build/index.js.map +1 -1
- package/build/lib/check-dependencies.d.ts +2 -7
- package/build/lib/check-dependencies.d.ts.map +1 -1
- package/build/lib/check-dependencies.js +0 -11
- package/build/lib/check-dependencies.js.map +1 -1
- package/build/lib/constants.d.ts +12 -12
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +14 -26
- package/build/lib/constants.js.map +1 -1
- package/build/lib/logger.d.ts +1 -2
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js +2 -2
- package/build/lib/logger.js.map +1 -1
- package/build/lib/no-session-proxy.d.ts +5 -5
- package/build/lib/no-session-proxy.d.ts.map +1 -1
- package/build/lib/no-session-proxy.js +0 -1
- package/build/lib/no-session-proxy.js.map +1 -1
- package/build/lib/utils.d.ts +53 -96
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +124 -110
- package/build/lib/utils.js.map +1 -1
- package/build/lib/webdriveragent.d.ts +123 -170
- package/build/lib/webdriveragent.d.ts.map +1 -1
- package/build/lib/webdriveragent.js +319 -349
- package/build/lib/webdriveragent.js.map +1 -1
- package/build/lib/xcodebuild.d.ts +66 -77
- package/build/lib/xcodebuild.d.ts.map +1 -1
- package/build/lib/xcodebuild.js +123 -92
- package/build/lib/xcodebuild.js.map +1 -1
- package/build/test/functional/desired.d.ts +3 -0
- package/build/test/functional/desired.d.ts.map +1 -0
- package/build/test/functional/desired.js +9 -0
- package/build/test/functional/desired.js.map +1 -0
- package/build/test/functional/helpers/simulator.d.ts +5 -0
- package/build/test/functional/helpers/simulator.d.ts.map +1 -0
- package/build/test/functional/helpers/simulator.js +39 -0
- package/build/test/functional/helpers/simulator.js.map +1 -0
- package/build/test/functional/webdriveragent-e2e-specs.d.ts +2 -0
- package/build/test/functional/webdriveragent-e2e-specs.d.ts.map +1 -0
- package/build/test/functional/webdriveragent-e2e-specs.js +133 -0
- package/build/test/functional/webdriveragent-e2e-specs.js.map +1 -0
- package/build/test/unit/utils-specs.d.ts +2 -0
- package/build/test/unit/utils-specs.d.ts.map +1 -0
- package/build/test/unit/utils-specs.js +161 -0
- package/build/test/unit/utils-specs.js.map +1 -0
- package/build/test/unit/webdriveragent-specs.d.ts +2 -0
- package/build/test/unit/webdriveragent-specs.d.ts.map +1 -0
- package/build/test/unit/webdriveragent-specs.js +424 -0
- package/build/test/unit/webdriveragent-specs.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/index.ts +1 -1
- package/lib/{check-dependencies.js → check-dependencies.ts} +4 -13
- package/lib/constants.ts +18 -0
- package/lib/logger.ts +3 -0
- package/lib/{no-session-proxy.js → no-session-proxy.ts} +4 -5
- package/lib/{utils.js → utils.ts} +101 -111
- package/lib/{webdriveragent.js → webdriveragent.ts} +353 -390
- package/lib/{xcodebuild.js → xcodebuild.ts} +145 -114
- package/package.json +7 -9
- package/lib/constants.js +0 -24
- package/lib/logger.js +0 -5
|
@@ -6,12 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.WebDriverAgent = void 0;
|
|
7
7
|
const asyncbox_1 = require("asyncbox");
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
-
const
|
|
10
|
-
const
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_url_1 = __importDefault(require("node:url"));
|
|
11
11
|
const bluebird_1 = __importDefault(require("bluebird"));
|
|
12
12
|
const base_driver_1 = require("@appium/base-driver");
|
|
13
13
|
const support_1 = require("@appium/support");
|
|
14
|
-
const logger_1 =
|
|
14
|
+
const logger_1 = require("./logger");
|
|
15
15
|
const no_session_proxy_1 = require("./no-session-proxy");
|
|
16
16
|
const utils_1 = require("./utils");
|
|
17
17
|
const xcodebuild_1 = require("./xcodebuild");
|
|
@@ -27,29 +27,53 @@ const WDA_CF_BUNDLE_NAME = 'WebDriverAgentRunner-Runner';
|
|
|
27
27
|
const SHARED_RESOURCES_GUARD = new async_lock_1.default();
|
|
28
28
|
const RECENT_MODULE_VERSION_ITEM_NAME = 'recentWdaModuleVersion';
|
|
29
29
|
class WebDriverAgent {
|
|
30
|
-
/** @type {string} */
|
|
31
30
|
bootstrapPath;
|
|
32
|
-
/** @type {string} */
|
|
33
31
|
agentPath;
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
args;
|
|
33
|
+
log;
|
|
34
|
+
device;
|
|
35
|
+
platformVersion;
|
|
36
|
+
platformName;
|
|
37
|
+
iosSdkVersion;
|
|
38
|
+
host;
|
|
39
|
+
isRealDevice;
|
|
40
|
+
wdaBundlePath;
|
|
41
|
+
wdaLocalPort;
|
|
42
|
+
wdaRemotePort;
|
|
43
|
+
wdaBaseUrl;
|
|
44
|
+
wdaBindingIP;
|
|
45
|
+
prebuildWDA;
|
|
46
|
+
webDriverAgentUrl;
|
|
47
|
+
started;
|
|
48
|
+
wdaConnectionTimeout;
|
|
49
|
+
useXctestrunFile;
|
|
50
|
+
usePrebuiltWDA;
|
|
51
|
+
derivedDataPath;
|
|
52
|
+
mjpegServerPort;
|
|
53
|
+
updatedWDABundleId;
|
|
54
|
+
wdaLaunchTimeout;
|
|
55
|
+
usePreinstalledWDA;
|
|
56
|
+
xctestApiClient;
|
|
57
|
+
updatedWDABundleIdSuffix;
|
|
58
|
+
_xcodebuild;
|
|
59
|
+
noSessionProxy;
|
|
60
|
+
jwproxy;
|
|
61
|
+
proxyReqRes;
|
|
62
|
+
_url;
|
|
36
63
|
/**
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
39
|
-
* @param
|
|
64
|
+
* Creates a new WebDriverAgent instance.
|
|
65
|
+
* @param args - Configuration arguments for WebDriverAgent
|
|
66
|
+
* @param log - Optional logger instance
|
|
40
67
|
*/
|
|
41
|
-
constructor(
|
|
42
|
-
this.xcodeVersion = xcodeVersion;
|
|
68
|
+
constructor(args, log = null) {
|
|
43
69
|
this.args = lodash_1.default.clone(args);
|
|
44
|
-
this.log = log ?? logger_1.
|
|
70
|
+
this.log = log ?? logger_1.log;
|
|
45
71
|
this.device = args.device;
|
|
46
72
|
this.platformVersion = args.platformVersion;
|
|
47
73
|
this.platformName = args.platformName;
|
|
48
74
|
this.iosSdkVersion = args.iosSdkVersion;
|
|
49
75
|
this.host = args.host;
|
|
50
76
|
this.isRealDevice = !!args.realDevice;
|
|
51
|
-
/** @deprecated We'll stop supporting idb */
|
|
52
|
-
this.idb = args.device.idb;
|
|
53
77
|
this.wdaBundlePath = args.wdaBundlePath;
|
|
54
78
|
this.setWDAPaths(args.bootstrapPath, args.agentPath);
|
|
55
79
|
this.wdaLocalPort = args.wdaLocalPort;
|
|
@@ -73,9 +97,9 @@ class WebDriverAgent {
|
|
|
73
97
|
this.usePreinstalledWDA = args.usePreinstalledWDA;
|
|
74
98
|
this.xctestApiClient = null;
|
|
75
99
|
this.updatedWDABundleIdSuffix = args.updatedWDABundleIdSuffix ?? constants_1.DEFAULT_TEST_BUNDLE_SUFFIX;
|
|
76
|
-
this.
|
|
100
|
+
this._xcodebuild = this.canSkipXcodebuild
|
|
77
101
|
? null
|
|
78
|
-
: new xcodebuild_1.XcodeBuild(this.
|
|
102
|
+
: new xcodebuild_1.XcodeBuild(this.device, {
|
|
79
103
|
platformVersion: this.platformVersion,
|
|
80
104
|
platformName: this.platformName,
|
|
81
105
|
iosSdkVersion: this.iosSdkVersion,
|
|
@@ -104,42 +128,41 @@ class WebDriverAgent {
|
|
|
104
128
|
}
|
|
105
129
|
/**
|
|
106
130
|
* Return true if the session does not need xcodebuild.
|
|
107
|
-
* @returns
|
|
131
|
+
* @returns Whether the session needs/has xcodebuild.
|
|
108
132
|
*/
|
|
109
133
|
get canSkipXcodebuild() {
|
|
110
134
|
// Use this.args.webDriverAgentUrl to guarantee
|
|
111
135
|
// the capabilities set gave the `appium:webDriverAgentUrl`.
|
|
112
136
|
return this.usePreinstalledWDA || !!this.args.webDriverAgentUrl;
|
|
113
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Get the xcodebuild instance. Throws if not initialized.
|
|
140
|
+
* @returns The XcodeBuild instance
|
|
141
|
+
* @throws Error if xcodebuild is not available
|
|
142
|
+
*/
|
|
143
|
+
get xcodebuild() {
|
|
144
|
+
if (!this._xcodebuild) {
|
|
145
|
+
throw new Error('xcodebuild is not available');
|
|
146
|
+
}
|
|
147
|
+
return this._xcodebuild;
|
|
148
|
+
}
|
|
114
149
|
/**
|
|
115
150
|
* Return bundle id for WebDriverAgent to launch the WDA.
|
|
116
151
|
* The primary usage is with 'this.usePreinstalledWDA'.
|
|
117
152
|
* It adds `.xctrunner` as suffix by default but 'this.updatedWDABundleIdSuffix'
|
|
118
153
|
* lets skip it.
|
|
119
154
|
*
|
|
120
|
-
* @returns
|
|
155
|
+
* @returns Bundle ID for Xctest.
|
|
121
156
|
*/
|
|
122
157
|
get bundleIdForXctest() {
|
|
123
158
|
return `${this.updatedWDABundleId ? this.updatedWDABundleId : constants_1.WDA_RUNNER_BUNDLE_ID}${this.updatedWDABundleIdSuffix}`;
|
|
124
159
|
}
|
|
125
160
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*/
|
|
129
|
-
setWDAPaths(bootstrapPath, agentPath) {
|
|
130
|
-
// allow the user to specify a place for WDA. This is undocumented and
|
|
131
|
-
// only here for the purposes of testing development of WDA
|
|
132
|
-
this.bootstrapPath = bootstrapPath || utils_1.BOOTSTRAP_PATH;
|
|
133
|
-
this.log.info(`Using WDA path: '${this.bootstrapPath}'`);
|
|
134
|
-
// for backward compatibility we need to be able to specify agentPath too
|
|
135
|
-
this.agentPath = agentPath || path_1.default.resolve(this.bootstrapPath, 'WebDriverAgent.xcodeproj');
|
|
136
|
-
this.log.info(`Using WDA agent: '${this.agentPath}'`);
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* @returns {Promise<void>}
|
|
161
|
+
* Cleans up obsolete cached processes from previous WDA sessions
|
|
162
|
+
* that are listening on the same port but belong to different devices.
|
|
140
163
|
*/
|
|
141
164
|
async cleanupObsoleteProcesses() {
|
|
142
|
-
const obsoletePids = await (0, utils_1.getPIDsListeningOnPort)(
|
|
165
|
+
const obsoletePids = await (0, utils_1.getPIDsListeningOnPort)(this.url.port, (cmdLine) => cmdLine.includes('/WebDriverAgentRunner') &&
|
|
143
166
|
!cmdLine.toLowerCase().includes(this.device.udid.toLowerCase()));
|
|
144
167
|
if (lodash_1.default.isEmpty(obsoletePids)) {
|
|
145
168
|
this.log.debug(`No obsolete cached processes from previous WDA sessions ` +
|
|
@@ -157,15 +180,8 @@ class WebDriverAgent {
|
|
|
157
180
|
}
|
|
158
181
|
}
|
|
159
182
|
/**
|
|
160
|
-
*
|
|
161
|
-
* @
|
|
162
|
-
* @throws {Error} If there was invalid response code or body
|
|
163
|
-
*/
|
|
164
|
-
async isRunning() {
|
|
165
|
-
return !!(await this.getStatus());
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* @returns {string}
|
|
183
|
+
* Gets the base path for the WebDriverAgent URL.
|
|
184
|
+
* @returns The base path (empty string if root path)
|
|
169
185
|
*/
|
|
170
186
|
get basePath() {
|
|
171
187
|
if (this.url.path === '/') {
|
|
@@ -173,230 +189,6 @@ class WebDriverAgent {
|
|
|
173
189
|
}
|
|
174
190
|
return this.url.path || '';
|
|
175
191
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Return current running WDA's status like below
|
|
178
|
-
* {
|
|
179
|
-
* "state": "success",
|
|
180
|
-
* "os": {
|
|
181
|
-
* "name": "iOS",
|
|
182
|
-
* "version": "11.4",
|
|
183
|
-
* "sdkVersion": "11.3"
|
|
184
|
-
* },
|
|
185
|
-
* "ios": {
|
|
186
|
-
* "simulatorVersion": "11.4",
|
|
187
|
-
* "ip": "172.254.99.34"
|
|
188
|
-
* },
|
|
189
|
-
* "build": {
|
|
190
|
-
* "time": "Jun 24 2018 17:08:21",
|
|
191
|
-
* "productBundleIdentifier": "com.facebook.WebDriverAgentRunner"
|
|
192
|
-
* }
|
|
193
|
-
* }
|
|
194
|
-
*
|
|
195
|
-
* @param {number} [timeoutMs=0] If the given timeoutMs is zero or negative number,
|
|
196
|
-
* this function will return the response of `/status` immediately. If the given timeoutMs,
|
|
197
|
-
* this function will try to get the response of `/status` up to the timeoutMs.
|
|
198
|
-
* @return {Promise<import('@appium/types').StringRecord|null>} State Object
|
|
199
|
-
* @throws {Error} If there was an error within timeoutMs timeout.
|
|
200
|
-
* No error is raised if zero or negative number for the timeoutMs.
|
|
201
|
-
*/
|
|
202
|
-
async getStatus(timeoutMs = 0) {
|
|
203
|
-
const noSessionProxy = new no_session_proxy_1.NoSessionProxy({
|
|
204
|
-
server: this.url.hostname,
|
|
205
|
-
port: this.url.port,
|
|
206
|
-
base: this.basePath,
|
|
207
|
-
timeout: 3000,
|
|
208
|
-
});
|
|
209
|
-
const sendGetStatus = async () => await /** @type import('@appium/types').StringRecord */ (noSessionProxy.command('/status', 'GET'));
|
|
210
|
-
if (lodash_1.default.isNil(timeoutMs) || timeoutMs <= 0) {
|
|
211
|
-
try {
|
|
212
|
-
return await sendGetStatus();
|
|
213
|
-
}
|
|
214
|
-
catch (err) {
|
|
215
|
-
this.log.debug(`WDA is not listening at '${this.url.href}'. Original error:: ${err.message}`);
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
let lastError = null;
|
|
220
|
-
let status = null;
|
|
221
|
-
try {
|
|
222
|
-
await (0, asyncbox_1.waitForCondition)(async () => {
|
|
223
|
-
try {
|
|
224
|
-
status = await sendGetStatus();
|
|
225
|
-
return true;
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
lastError = err;
|
|
229
|
-
}
|
|
230
|
-
return false;
|
|
231
|
-
}, {
|
|
232
|
-
waitMs: timeoutMs,
|
|
233
|
-
intervalMs: 300,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
catch (err) {
|
|
237
|
-
this.log.debug(`Failed to get the status endpoint in ${timeoutMs} ms. ` +
|
|
238
|
-
`The last error while accessing ${this.url.href}: ${lastError}. Original error:: ${err.message}.`);
|
|
239
|
-
throw new Error(`WDA was not ready in ${timeoutMs} ms.`);
|
|
240
|
-
}
|
|
241
|
-
return status;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Uninstall WDAs from the test device.
|
|
245
|
-
* Over Xcode 11, multiple WDA can be in the device since Xcode 11 generates different WDA.
|
|
246
|
-
* Appium does not expect multiple WDAs are running on a device.
|
|
247
|
-
*
|
|
248
|
-
* @returns {Promise<void>}
|
|
249
|
-
*/
|
|
250
|
-
async uninstall() {
|
|
251
|
-
try {
|
|
252
|
-
const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME);
|
|
253
|
-
if (lodash_1.default.isEmpty(bundleIds)) {
|
|
254
|
-
this.log.debug('No WDAs on the device.');
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
this.log.debug(`Uninstalling WDAs: '${bundleIds}'`);
|
|
258
|
-
for (const bundleId of bundleIds) {
|
|
259
|
-
await this.device.removeApp(bundleId);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
catch (e) {
|
|
263
|
-
this.log.debug(e);
|
|
264
|
-
this.log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` +
|
|
265
|
-
`Original error: ${e.message}`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
async _cleanupProjectIfFresh() {
|
|
269
|
-
if (this.canSkipXcodebuild) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
const packageInfo = JSON.parse(await support_1.fs.readFile(path_1.default.join(utils_1.BOOTSTRAP_PATH, 'package.json'), 'utf8'));
|
|
273
|
-
const box = (0, strongbox_1.strongbox)(packageInfo.name);
|
|
274
|
-
let boxItem = box.getItem(RECENT_MODULE_VERSION_ITEM_NAME);
|
|
275
|
-
if (!boxItem) {
|
|
276
|
-
const timestampPath = path_1.default.resolve(process.env.HOME ?? '', constants_1.WDA_UPGRADE_TIMESTAMP_PATH);
|
|
277
|
-
if (await support_1.fs.exists(timestampPath)) {
|
|
278
|
-
// TODO: It is probably a bit ugly to hardcode the recent version string,
|
|
279
|
-
// TODO: hovewer it should do the job as a temporary transition trick
|
|
280
|
-
// TODO: to switch from a hardcoded file path to the strongbox usage.
|
|
281
|
-
try {
|
|
282
|
-
boxItem = await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, '5.0.0');
|
|
283
|
-
}
|
|
284
|
-
catch (e) {
|
|
285
|
-
this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
this.log.info('There is no need to perform the project cleanup. A fresh install has been detected');
|
|
291
|
-
try {
|
|
292
|
-
await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, packageInfo.version);
|
|
293
|
-
}
|
|
294
|
-
catch (e) {
|
|
295
|
-
this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
|
|
296
|
-
}
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
let recentModuleVersion = await boxItem.read();
|
|
301
|
-
try {
|
|
302
|
-
recentModuleVersion = support_1.util.coerceVersion(recentModuleVersion, true);
|
|
303
|
-
}
|
|
304
|
-
catch (e) {
|
|
305
|
-
this.log.warn(`The persisted module version string has been damaged: ${e.message}`);
|
|
306
|
-
this.log.info(`Updating it to '${packageInfo.version}' assuming the project clenup is not needed`);
|
|
307
|
-
await boxItem.write(packageInfo.version);
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (support_1.util.compareVersions(recentModuleVersion, '>=', packageInfo.version)) {
|
|
311
|
-
this.log.info(`WebDriverAgent does not need a cleanup. The project sources are up to date ` +
|
|
312
|
-
`(${recentModuleVersion} >= ${packageInfo.version})`);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
this.log.info(`Cleaning up the WebDriverAgent project after the module upgrade has happened ` +
|
|
316
|
-
`(${recentModuleVersion} < ${packageInfo.version})`);
|
|
317
|
-
try {
|
|
318
|
-
// @ts-ignore xcodebuild should be set
|
|
319
|
-
await this.xcodebuild.cleanProject();
|
|
320
|
-
await boxItem.write(packageInfo.version);
|
|
321
|
-
}
|
|
322
|
-
catch (e) {
|
|
323
|
-
this.log.warn(`Cannot perform WebDriverAgent project cleanup. Original error: ${e.message}`);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* @typedef {Object} LaunchWdaViaDeviceCtlOptions
|
|
328
|
-
* @property {Record<string, string|number>} [env] environment variables for the launching WDA process
|
|
329
|
-
*/
|
|
330
|
-
/**
|
|
331
|
-
* Launch WDA with preinstalled package with 'xcrun devicectl device process launch'.
|
|
332
|
-
* The WDA package must be prepared properly like published via
|
|
333
|
-
* https://github.com/appium/WebDriverAgent/releases
|
|
334
|
-
* with proper sign for this case.
|
|
335
|
-
*
|
|
336
|
-
* When we implement launching XCTest service via appium-ios-device,
|
|
337
|
-
* this implementation can be replaced with it.
|
|
338
|
-
*
|
|
339
|
-
* @param {LaunchWdaViaDeviceCtlOptions} [opts={}] launching WDA with devicectl command options.
|
|
340
|
-
* @return {Promise<void>}
|
|
341
|
-
*/
|
|
342
|
-
async _launchViaDevicectl(opts = {}) {
|
|
343
|
-
const { env } = opts;
|
|
344
|
-
await this.device.devicectl.launchApp(this.bundleIdForXctest, { env, terminateExisting: true });
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Launch WDA with preinstalled package without xcodebuild.
|
|
348
|
-
* @param {string} sessionId Launch WDA and establish the session with this sessionId
|
|
349
|
-
* @return {Promise<import('@appium/types').StringRecord|null>} State Object
|
|
350
|
-
* @throws {Error} If there was an error within timeoutMs timeout.
|
|
351
|
-
* No error is raised if zero or negative number for the timeoutMs.
|
|
352
|
-
*/
|
|
353
|
-
async launchWithPreinstalledWDA(sessionId) {
|
|
354
|
-
const xctestEnv = {
|
|
355
|
-
USE_PORT: this.wdaLocalPort || WDA_AGENT_PORT,
|
|
356
|
-
WDA_PRODUCT_BUNDLE_IDENTIFIER: this.bundleIdForXctest
|
|
357
|
-
};
|
|
358
|
-
if (this.mjpegServerPort) {
|
|
359
|
-
xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort;
|
|
360
|
-
}
|
|
361
|
-
if (this.wdaBindingIP) {
|
|
362
|
-
xctestEnv.USE_IP = this.wdaBindingIP;
|
|
363
|
-
}
|
|
364
|
-
this.log.info('Launching WebDriverAgent on the device without xcodebuild');
|
|
365
|
-
if (this.isRealDevice) {
|
|
366
|
-
// Current method to launch WDA process can be done via 'xcrun devicectl',
|
|
367
|
-
// but it has limitation about the WDA preinstalled package.
|
|
368
|
-
// https://github.com/appium/appium/issues/19206#issuecomment-2014182674
|
|
369
|
-
if (this.platformVersion && support_1.util.compareVersions(this.platformVersion, '>=', '17.0')) {
|
|
370
|
-
await this._launchViaDevicectl({ env: xctestEnv });
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
this.xctestApiClient = new appium_ios_device_1.Xctest(this.device.udid, this.bundleIdForXctest, null, { env: xctestEnv });
|
|
374
|
-
await this.xctestApiClient.start();
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
await this.device.simctl.exec('launch', {
|
|
379
|
-
args: [
|
|
380
|
-
'--terminate-running-process',
|
|
381
|
-
this.device.udid,
|
|
382
|
-
this.bundleIdForXctest,
|
|
383
|
-
],
|
|
384
|
-
env: xctestEnv,
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
this.setupProxies(sessionId);
|
|
388
|
-
let status;
|
|
389
|
-
try {
|
|
390
|
-
status = await this.getStatus(this.wdaLaunchTimeout);
|
|
391
|
-
}
|
|
392
|
-
catch {
|
|
393
|
-
throw new Error(`Failed to start the preinstalled WebDriverAgent in ${this.wdaLaunchTimeout} ms. ` +
|
|
394
|
-
`The WebDriverAgent might not be properly built or the device might be locked. ` +
|
|
395
|
-
`The 'appium:wdaLaunchTimeout' capability modifies the timeout.`);
|
|
396
|
-
}
|
|
397
|
-
this.started = true;
|
|
398
|
-
return status;
|
|
399
|
-
}
|
|
400
192
|
/**
|
|
401
193
|
* Return current running WDA's status like below after launching WDA
|
|
402
194
|
* {
|
|
@@ -416,9 +208,7 @@ class WebDriverAgent {
|
|
|
416
208
|
* }
|
|
417
209
|
* }
|
|
418
210
|
*
|
|
419
|
-
* @param
|
|
420
|
-
* @return {Promise<any?>} State Object
|
|
421
|
-
* @throws {Error} If there was invalid response code or body
|
|
211
|
+
* @param sessionId Launch WDA and establish the session with this sessionId
|
|
422
212
|
*/
|
|
423
213
|
async launch(sessionId) {
|
|
424
214
|
if (this.webDriverAgentUrl) {
|
|
@@ -438,79 +228,48 @@ class WebDriverAgent {
|
|
|
438
228
|
}
|
|
439
229
|
// useXctestrunFile and usePrebuiltWDA use existing dependencies
|
|
440
230
|
// It depends on user side
|
|
441
|
-
if (this.
|
|
231
|
+
if (this.useXctestrunFile || this.usePrebuiltWDA) {
|
|
442
232
|
this.log.info('Skipped WDA project cleanup according to the provided capabilities');
|
|
443
233
|
}
|
|
444
234
|
else {
|
|
445
|
-
const synchronizationKey =
|
|
235
|
+
const synchronizationKey = node_path_1.default.normalize(this.bootstrapPath);
|
|
446
236
|
await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => await this._cleanupProjectIfFresh());
|
|
447
237
|
}
|
|
448
238
|
// We need to provide WDA local port, because it might be occupied
|
|
449
239
|
await (0, utils_1.resetTestProcesses)(this.device.udid, !this.isRealDevice);
|
|
450
|
-
if (this.
|
|
451
|
-
|
|
240
|
+
if (!this.noSessionProxy) {
|
|
241
|
+
throw new Error('noSessionProxy is not available');
|
|
452
242
|
}
|
|
453
|
-
// @ts-ignore xcodebuild should be set
|
|
454
243
|
await this.xcodebuild.init(this.noSessionProxy);
|
|
455
244
|
// Start the xcodebuild process
|
|
456
245
|
if (this.prebuildWDA) {
|
|
457
|
-
// @ts-ignore xcodebuild should be set
|
|
458
246
|
await this.xcodebuild.prebuild();
|
|
459
247
|
}
|
|
460
|
-
// @ts-ignore xcodebuild should be set
|
|
461
248
|
return await this.xcodebuild.start();
|
|
462
249
|
}
|
|
463
250
|
/**
|
|
464
|
-
*
|
|
465
|
-
*
|
|
251
|
+
* Checks if the WebDriverAgent source is fresh by verifying
|
|
252
|
+
* that required resource files exist.
|
|
253
|
+
* @returns `true` if source is fresh (all required files exist), `false` otherwise
|
|
466
254
|
*/
|
|
467
|
-
async
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
};
|
|
474
|
-
if (this.mjpegServerPort) {
|
|
475
|
-
env.MJPEG_SERVER_PORT = this.mjpegServerPort;
|
|
476
|
-
}
|
|
477
|
-
if (this.wdaBindingIP) {
|
|
478
|
-
env.USE_IP = this.wdaBindingIP;
|
|
479
|
-
}
|
|
480
|
-
return await this.idb.runXCUITest(wdaBundleId, wdaBundleId, testBundleId, { env });
|
|
255
|
+
async isSourceFresh() {
|
|
256
|
+
const existsPromises = [
|
|
257
|
+
'Resources',
|
|
258
|
+
`Resources${node_path_1.default.sep}WebDriverAgent.bundle`,
|
|
259
|
+
].map((subPath) => support_1.fs.exists(node_path_1.default.resolve(this.bootstrapPath, subPath)));
|
|
260
|
+
return (await bluebird_1.default.all(existsPromises)).some((v) => v === false);
|
|
481
261
|
}
|
|
482
|
-
/**
|
|
483
|
-
*
|
|
484
|
-
* @param {string} wdaBundlePath
|
|
485
|
-
* @returns {Promise<string>}
|
|
486
|
-
*/
|
|
487
262
|
async parseBundleId(wdaBundlePath) {
|
|
488
|
-
const infoPlistPath =
|
|
263
|
+
const infoPlistPath = node_path_1.default.join(wdaBundlePath, 'Info.plist');
|
|
489
264
|
const infoPlist = await support_1.plist.parsePlist(await support_1.fs.readFile(infoPlistPath));
|
|
490
265
|
if (!infoPlist.CFBundleIdentifier) {
|
|
491
266
|
throw new Error(`Could not find bundle id in '${infoPlistPath}'`);
|
|
492
267
|
}
|
|
493
268
|
return infoPlist.CFBundleIdentifier;
|
|
494
269
|
}
|
|
495
|
-
/**
|
|
496
|
-
* @deprecated We'll stop using idb
|
|
497
|
-
* @returns {Promise<{wdaBundleId: string, testBundleId: string, wdaBundlePath: string}>}
|
|
498
|
-
*/
|
|
499
|
-
async prepareWDA() {
|
|
500
|
-
const wdaBundlePath = this.wdaBundlePath || await this.fetchWDABundle();
|
|
501
|
-
const wdaBundleId = await this.parseBundleId(wdaBundlePath);
|
|
502
|
-
if (!await this.device.isAppInstalled(wdaBundleId)) {
|
|
503
|
-
await this.device.installApp(wdaBundlePath);
|
|
504
|
-
}
|
|
505
|
-
const testBundleId = await this.idb.installXCTestBundle(path_1.default.join(wdaBundlePath, 'PlugIns', 'WebDriverAgentRunner.xctest'));
|
|
506
|
-
return { wdaBundleId, testBundleId, wdaBundlePath };
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* @returns {Promise<string>}
|
|
510
|
-
*/
|
|
511
270
|
async fetchWDABundle() {
|
|
512
271
|
if (!this.derivedDataPath) {
|
|
513
|
-
return await (0, check_dependencies_1.bundleWDASim)(
|
|
272
|
+
return await (0, check_dependencies_1.bundleWDASim)(this.xcodebuild);
|
|
514
273
|
}
|
|
515
274
|
const wdaBundlePaths = await support_1.fs.glob(`${this.derivedDataPath}/**/*${constants_1.WDA_RUNNER_APP}/`, {
|
|
516
275
|
absolute: true,
|
|
@@ -520,20 +279,6 @@ class WebDriverAgent {
|
|
|
520
279
|
}
|
|
521
280
|
return wdaBundlePaths[0];
|
|
522
281
|
}
|
|
523
|
-
/**
|
|
524
|
-
* @returns {Promise<boolean>}
|
|
525
|
-
*/
|
|
526
|
-
async isSourceFresh() {
|
|
527
|
-
const existsPromises = [
|
|
528
|
-
'Resources',
|
|
529
|
-
`Resources${path_1.default.sep}WebDriverAgent.bundle`,
|
|
530
|
-
].map((subPath) => support_1.fs.exists(path_1.default.resolve(/** @type {String} */ (this.bootstrapPath), subPath)));
|
|
531
|
-
return (await bluebird_1.default.all(existsPromises)).some((v) => v === false);
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* @param {string} sessionId
|
|
535
|
-
* @returns {void}
|
|
536
|
-
*/
|
|
537
282
|
setupProxies(sessionId) {
|
|
538
283
|
const proxyOpts = {
|
|
539
284
|
log: this.log,
|
|
@@ -553,7 +298,8 @@ class WebDriverAgent {
|
|
|
553
298
|
this.noSessionProxy = new no_session_proxy_1.NoSessionProxy(proxyOpts);
|
|
554
299
|
}
|
|
555
300
|
/**
|
|
556
|
-
*
|
|
301
|
+
* Stops the WebDriverAgent session and cleans up resources.
|
|
302
|
+
* Handles both preinstalled WDA and xcodebuild-based sessions.
|
|
557
303
|
*/
|
|
558
304
|
async quit() {
|
|
559
305
|
if (this.usePreinstalledWDA) {
|
|
@@ -573,8 +319,10 @@ class WebDriverAgent {
|
|
|
573
319
|
}
|
|
574
320
|
else if (!this.args.webDriverAgentUrl) {
|
|
575
321
|
this.log.info('Shutting down sub-processes');
|
|
576
|
-
|
|
577
|
-
|
|
322
|
+
if (this._xcodebuild) {
|
|
323
|
+
await this.xcodebuild.quit();
|
|
324
|
+
await this.xcodebuild.reset();
|
|
325
|
+
}
|
|
578
326
|
}
|
|
579
327
|
else {
|
|
580
328
|
this.log.debug('Do not stop xcodebuild nor XCTest session ' +
|
|
@@ -591,58 +339,62 @@ class WebDriverAgent {
|
|
|
591
339
|
}
|
|
592
340
|
}
|
|
593
341
|
/**
|
|
594
|
-
*
|
|
342
|
+
* Gets the WebDriverAgent URL.
|
|
343
|
+
* Constructs the URL from webDriverAgentUrl if provided, otherwise
|
|
344
|
+
* builds it from wdaBaseUrl, wdaBindingIP, and wdaLocalPort.
|
|
345
|
+
* @returns The parsed URL object
|
|
595
346
|
*/
|
|
596
347
|
get url() {
|
|
597
348
|
if (!this._url) {
|
|
598
349
|
if (this.webDriverAgentUrl) {
|
|
599
|
-
this._url =
|
|
350
|
+
this._url = node_url_1.default.parse(this.webDriverAgentUrl);
|
|
600
351
|
}
|
|
601
352
|
else {
|
|
602
353
|
const port = this.wdaLocalPort || WDA_AGENT_PORT;
|
|
603
|
-
const { protocol, hostname } =
|
|
604
|
-
this._url =
|
|
354
|
+
const { protocol, hostname } = node_url_1.default.parse(this.wdaBaseUrl || constants_1.WDA_BASE_URL);
|
|
355
|
+
this._url = node_url_1.default.parse(`${protocol}//${this.wdaBindingIP || hostname}:${port}`);
|
|
605
356
|
}
|
|
606
357
|
}
|
|
607
358
|
return this._url;
|
|
608
359
|
}
|
|
609
360
|
/**
|
|
610
|
-
*
|
|
611
|
-
* @
|
|
361
|
+
* Sets the WebDriverAgent URL.
|
|
362
|
+
* @param _url - The URL string to parse and set
|
|
612
363
|
*/
|
|
613
364
|
set url(_url) {
|
|
614
|
-
this._url =
|
|
365
|
+
this._url = node_url_1.default.parse(_url);
|
|
615
366
|
}
|
|
616
367
|
/**
|
|
617
|
-
*
|
|
368
|
+
* Gets whether WebDriverAgent has fully started.
|
|
369
|
+
* @returns `true` if WDA has started, `false` otherwise
|
|
618
370
|
*/
|
|
619
371
|
get fullyStarted() {
|
|
620
372
|
return this.started;
|
|
621
373
|
}
|
|
622
374
|
/**
|
|
623
|
-
*
|
|
624
|
-
* @
|
|
375
|
+
* Sets whether WebDriverAgent has fully started.
|
|
376
|
+
* @param started - `true` if WDA has started, `false` otherwise
|
|
625
377
|
*/
|
|
626
378
|
set fullyStarted(started) {
|
|
627
379
|
this.started = started ?? false;
|
|
628
380
|
}
|
|
629
381
|
/**
|
|
630
|
-
*
|
|
382
|
+
* Retrieves the Xcode derived data path for WebDriverAgent.
|
|
383
|
+
* @returns The derived data path, or `undefined` if xcodebuild is skipped
|
|
631
384
|
*/
|
|
632
385
|
async retrieveDerivedDataPath() {
|
|
633
386
|
if (this.canSkipXcodebuild) {
|
|
634
387
|
return;
|
|
635
388
|
}
|
|
636
|
-
return await
|
|
389
|
+
return await this.xcodebuild.retrieveDerivedDataPath();
|
|
637
390
|
}
|
|
638
391
|
/**
|
|
639
392
|
* Reuse running WDA if it has the same bundle id with updatedWDABundleId.
|
|
640
393
|
* Or reuse it if it has the default id without updatedWDABundleId.
|
|
641
394
|
* Uninstall it if the method faces an exception for the above situation.
|
|
642
|
-
* @returns {Promise<void>}
|
|
643
395
|
*/
|
|
644
396
|
async setupCaching() {
|
|
645
|
-
const status = await this.getStatus();
|
|
397
|
+
const status = await this.getStatus(0);
|
|
646
398
|
if (!status || !status.build) {
|
|
647
399
|
this.log.debug('WDA is currently not running. There is nothing to cache');
|
|
648
400
|
return;
|
|
@@ -674,13 +426,231 @@ class WebDriverAgent {
|
|
|
674
426
|
}
|
|
675
427
|
/**
|
|
676
428
|
* Quit and uninstall running WDA.
|
|
677
|
-
* @returns {Promise<void>}
|
|
678
429
|
*/
|
|
679
430
|
async quitAndUninstall() {
|
|
680
431
|
await this.quit();
|
|
681
432
|
await this.uninstall();
|
|
682
433
|
}
|
|
434
|
+
setWDAPaths(bootstrapPath, agentPath) {
|
|
435
|
+
// allow the user to specify a place for WDA. This is undocumented and
|
|
436
|
+
// only here for the purposes of testing development of WDA
|
|
437
|
+
this.bootstrapPath = bootstrapPath || utils_1.BOOTSTRAP_PATH;
|
|
438
|
+
this.log.info(`Using WDA path: '${this.bootstrapPath}'`);
|
|
439
|
+
// for backward compatibility we need to be able to specify agentPath too
|
|
440
|
+
this.agentPath = agentPath || node_path_1.default.resolve(this.bootstrapPath, 'WebDriverAgent.xcodeproj');
|
|
441
|
+
this.log.info(`Using WDA agent: '${this.agentPath}'`);
|
|
442
|
+
}
|
|
443
|
+
async isRunning() {
|
|
444
|
+
return !!(await this.getStatus());
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Return current running WDA's status like below
|
|
448
|
+
* {
|
|
449
|
+
* "state": "success",
|
|
450
|
+
* "os": {
|
|
451
|
+
* "name": "iOS",
|
|
452
|
+
* "version": "11.4",
|
|
453
|
+
* "sdkVersion": "11.3"
|
|
454
|
+
* },
|
|
455
|
+
* "ios": {
|
|
456
|
+
* "simulatorVersion": "11.4",
|
|
457
|
+
* "ip": "172.254.99.34"
|
|
458
|
+
* },
|
|
459
|
+
* "build": {
|
|
460
|
+
* "time": "Jun 24 2018 17:08:21",
|
|
461
|
+
* "productBundleIdentifier": "com.facebook.WebDriverAgentRunner"
|
|
462
|
+
* }
|
|
463
|
+
* }
|
|
464
|
+
*
|
|
465
|
+
* @param timeoutMs If zero or negative, returns immediately. Otherwise, waits up to timeoutMs.
|
|
466
|
+
*/
|
|
467
|
+
async getStatus(timeoutMs = 0) {
|
|
468
|
+
const noSessionProxy = new no_session_proxy_1.NoSessionProxy({
|
|
469
|
+
server: this.url.hostname ?? undefined,
|
|
470
|
+
port: parseInt(this.url.port ?? '', 10) || undefined,
|
|
471
|
+
base: this.basePath,
|
|
472
|
+
timeout: 3000,
|
|
473
|
+
});
|
|
474
|
+
const sendGetStatus = async () => await noSessionProxy.command('/status', 'GET');
|
|
475
|
+
if (lodash_1.default.isNil(timeoutMs) || timeoutMs <= 0) {
|
|
476
|
+
try {
|
|
477
|
+
return await sendGetStatus();
|
|
478
|
+
}
|
|
479
|
+
catch (err) {
|
|
480
|
+
this.log.debug(`WDA is not listening at '${this.url.href}'. Original error:: ${err.message}`);
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
let lastError = null;
|
|
485
|
+
let status = null;
|
|
486
|
+
try {
|
|
487
|
+
await (0, asyncbox_1.waitForCondition)(async () => {
|
|
488
|
+
try {
|
|
489
|
+
status = await sendGetStatus();
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
catch (err) {
|
|
493
|
+
lastError = err;
|
|
494
|
+
}
|
|
495
|
+
return false;
|
|
496
|
+
}, {
|
|
497
|
+
waitMs: timeoutMs,
|
|
498
|
+
intervalMs: 300,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
this.log.debug(`Failed to get the status endpoint in ${timeoutMs} ms. ` +
|
|
503
|
+
`The last error while accessing ${this.url.href}: ${lastError}. Original error:: ${err.message}.`);
|
|
504
|
+
throw new Error(`WDA was not ready in ${timeoutMs} ms.`);
|
|
505
|
+
}
|
|
506
|
+
return status;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Uninstall WDAs from the test device.
|
|
510
|
+
* Over Xcode 11, multiple WDA can be in the device since Xcode 11 generates different WDA.
|
|
511
|
+
* Appium does not expect multiple WDAs are running on a device.
|
|
512
|
+
*/
|
|
513
|
+
async uninstall() {
|
|
514
|
+
try {
|
|
515
|
+
const bundleIds = await this.device.getUserInstalledBundleIdsByBundleName(WDA_CF_BUNDLE_NAME);
|
|
516
|
+
if (lodash_1.default.isEmpty(bundleIds)) {
|
|
517
|
+
this.log.debug('No WDAs on the device.');
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
this.log.debug(`Uninstalling WDAs: '${bundleIds}'`);
|
|
521
|
+
for (const bundleId of bundleIds) {
|
|
522
|
+
await this.device.removeApp(bundleId);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
catch (e) {
|
|
526
|
+
this.log.debug(e);
|
|
527
|
+
this.log.warn(`WebDriverAgent uninstall failed. Perhaps, it is already uninstalled? ` +
|
|
528
|
+
`Original error: ${e.message}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
async _cleanupProjectIfFresh() {
|
|
532
|
+
if (this.canSkipXcodebuild) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const packageInfo = JSON.parse(await support_1.fs.readFile(node_path_1.default.join(utils_1.BOOTSTRAP_PATH, 'package.json'), 'utf8'));
|
|
536
|
+
const box = (0, strongbox_1.strongbox)(packageInfo.name);
|
|
537
|
+
let boxItem = box.getItem(RECENT_MODULE_VERSION_ITEM_NAME);
|
|
538
|
+
if (!boxItem) {
|
|
539
|
+
const timestampPath = node_path_1.default.resolve(process.env.HOME ?? '', constants_1.WDA_UPGRADE_TIMESTAMP_PATH);
|
|
540
|
+
if (await support_1.fs.exists(timestampPath)) {
|
|
541
|
+
// TODO: It is probably a bit ugly to hardcode the recent version string,
|
|
542
|
+
// TODO: hovewer it should do the job as a temporary transition trick
|
|
543
|
+
// TODO: to switch from a hardcoded file path to the strongbox usage.
|
|
544
|
+
try {
|
|
545
|
+
boxItem = await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, '5.0.0');
|
|
546
|
+
}
|
|
547
|
+
catch (e) {
|
|
548
|
+
this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
this.log.info('There is no need to perform the project cleanup. A fresh install has been detected');
|
|
554
|
+
try {
|
|
555
|
+
await box.createItemWithValue(RECENT_MODULE_VERSION_ITEM_NAME, packageInfo.version);
|
|
556
|
+
}
|
|
557
|
+
catch (e) {
|
|
558
|
+
this.log.warn(`The actual module version cannot be persisted: ${e.message}`);
|
|
559
|
+
}
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
let recentModuleVersion = await boxItem.read();
|
|
564
|
+
try {
|
|
565
|
+
recentModuleVersion = support_1.util.coerceVersion(recentModuleVersion, true);
|
|
566
|
+
}
|
|
567
|
+
catch (e) {
|
|
568
|
+
this.log.warn(`The persisted module version string has been damaged: ${e.message}`);
|
|
569
|
+
this.log.info(`Updating it to '${packageInfo.version}' assuming the project clenup is not needed`);
|
|
570
|
+
await boxItem.write(packageInfo.version);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (support_1.util.compareVersions(recentModuleVersion, '>=', packageInfo.version)) {
|
|
574
|
+
this.log.info(`WebDriverAgent does not need a cleanup. The project sources are up to date ` +
|
|
575
|
+
`(${recentModuleVersion} >= ${packageInfo.version})`);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
this.log.info(`Cleaning up the WebDriverAgent project after the module upgrade has happened ` +
|
|
579
|
+
`(${recentModuleVersion} < ${packageInfo.version})`);
|
|
580
|
+
try {
|
|
581
|
+
await this.xcodebuild.cleanProject();
|
|
582
|
+
await boxItem.write(packageInfo.version);
|
|
583
|
+
}
|
|
584
|
+
catch (e) {
|
|
585
|
+
this.log.warn(`Cannot perform WebDriverAgent project cleanup. Original error: ${e.message}`);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Launch WDA with preinstalled package with 'xcrun devicectl device process launch'.
|
|
590
|
+
* The WDA package must be prepared properly like published via
|
|
591
|
+
* https://github.com/appium/WebDriverAgent/releases
|
|
592
|
+
* with proper sign for this case.
|
|
593
|
+
*
|
|
594
|
+
* When we implement launching XCTest service via appium-ios-device,
|
|
595
|
+
* this implementation can be replaced with it.
|
|
596
|
+
*
|
|
597
|
+
* @param opts launching WDA with devicectl command options.
|
|
598
|
+
*/
|
|
599
|
+
async _launchViaDevicectl(opts = {}) {
|
|
600
|
+
const { env } = opts;
|
|
601
|
+
await this.device.devicectl.launchApp(this.bundleIdForXctest, { env, terminateExisting: true });
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Launch WDA with preinstalled package without xcodebuild.
|
|
605
|
+
* @param sessionId Launch WDA and establish the session with this sessionId
|
|
606
|
+
*/
|
|
607
|
+
async launchWithPreinstalledWDA(sessionId) {
|
|
608
|
+
const xctestEnv = {
|
|
609
|
+
USE_PORT: this.wdaLocalPort || WDA_AGENT_PORT,
|
|
610
|
+
WDA_PRODUCT_BUNDLE_IDENTIFIER: this.bundleIdForXctest
|
|
611
|
+
};
|
|
612
|
+
if (this.mjpegServerPort) {
|
|
613
|
+
xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort;
|
|
614
|
+
}
|
|
615
|
+
if (this.wdaBindingIP) {
|
|
616
|
+
xctestEnv.USE_IP = this.wdaBindingIP;
|
|
617
|
+
}
|
|
618
|
+
this.log.info('Launching WebDriverAgent on the device without xcodebuild');
|
|
619
|
+
if (this.isRealDevice) {
|
|
620
|
+
// Current method to launch WDA process can be done via 'xcrun devicectl',
|
|
621
|
+
// but it has limitation about the WDA preinstalled package.
|
|
622
|
+
// https://github.com/appium/appium/issues/19206#issuecomment-2014182674
|
|
623
|
+
if (this.platformVersion && support_1.util.compareVersions(this.platformVersion, '>=', '17.0')) {
|
|
624
|
+
await this._launchViaDevicectl({ env: xctestEnv });
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
this.xctestApiClient = new appium_ios_device_1.Xctest(this.device.udid, this.bundleIdForXctest, null, { env: xctestEnv });
|
|
628
|
+
await this.xctestApiClient.start();
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
await this.device.simctl.exec('launch', {
|
|
633
|
+
args: [
|
|
634
|
+
'--terminate-running-process',
|
|
635
|
+
this.device.udid,
|
|
636
|
+
this.bundleIdForXctest,
|
|
637
|
+
],
|
|
638
|
+
env: xctestEnv,
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
this.setupProxies(sessionId);
|
|
642
|
+
let status;
|
|
643
|
+
try {
|
|
644
|
+
status = await this.getStatus(this.wdaLaunchTimeout);
|
|
645
|
+
}
|
|
646
|
+
catch {
|
|
647
|
+
throw new Error(`Failed to start the preinstalled WebDriverAgent in ${this.wdaLaunchTimeout} ms. ` +
|
|
648
|
+
`The WebDriverAgent might not be properly built or the device might be locked. ` +
|
|
649
|
+
`The 'appium:wdaLaunchTimeout' capability modifies the timeout.`);
|
|
650
|
+
}
|
|
651
|
+
this.started = true;
|
|
652
|
+
return status;
|
|
653
|
+
}
|
|
683
654
|
}
|
|
684
655
|
exports.WebDriverAgent = WebDriverAgent;
|
|
685
|
-
exports.default = WebDriverAgent;
|
|
686
656
|
//# sourceMappingURL=webdriveragent.js.map
|