appium-xcuitest-driver 10.16.0 → 10.16.2

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.
@@ -119,26 +119,14 @@ export async function mobileInstallCertificate(
119
119
  );
120
120
  }
121
121
  } else {
122
- if (!this.opts.udid) {
123
- throw new Error('udid capability is required');
124
- }
125
-
126
- let client: CertificateClient | null = null;
127
122
  try {
128
- client = await CertificateClient.create(
129
- this.opts.udid,
130
- this.log,
131
- isIos18OrNewer(this.opts)
132
- );
133
- await client.installCertificate({payload: Buffer.from(content, 'base64')});
123
+ await withCertificateClient(this, async (client) => {
124
+ await client.installCertificate({payload: Buffer.from(content, 'base64')});
125
+ });
134
126
  return;
135
127
  } catch (err) {
136
128
  this.log.error(`Failed to install the certificate: ${err.message}`);
137
129
  this.log.info('Falling back to the (slow) UI-based installation');
138
- } finally {
139
- if (client) {
140
- await client.close();
141
- }
142
130
  }
143
131
  }
144
132
 
@@ -166,7 +154,7 @@ export async function mobileInstallCertificate(
166
154
  try {
167
155
  const host = os.hostname();
168
156
  const certUrl = `http://${host}:${tmpPort}/${configName}`;
169
- await tmpServer.listen(tmpPort);
157
+ tmpServer.listen(tmpPort);
170
158
  try {
171
159
  await waitForCondition(
172
160
  async () => {
@@ -238,7 +226,7 @@ export async function mobileInstallCertificate(
238
226
 
239
227
  return (await util.toInMemoryBase64(configPath)).toString();
240
228
  } finally {
241
- await tmpServer.close();
229
+ tmpServer.close();
242
230
  await fs.rimraf(tmpRoot);
243
231
  }
244
232
  }
@@ -258,23 +246,7 @@ export async function mobileInstallCertificate(
258
246
  */
259
247
  export async function mobileRemoveCertificate(this: XCUITestDriver, name: string): Promise<string> {
260
248
  requireRealDevice(this, 'Removing certificate');
261
- if (!this.opts.udid) {
262
- throw new Error('udid capability is required');
263
- }
264
-
265
- let client: CertificateClient | null = null;
266
- try {
267
- client = await CertificateClient.create(
268
- this.opts.udid,
269
- this.log,
270
- isIos18OrNewer(this.opts)
271
- );
272
- return await client.removeCertificate(name);
273
- } finally {
274
- if (client) {
275
- await client.close();
276
- }
277
- }
249
+ return await withCertificateClient(this, async (client) => client.removeCertificate(name));
278
250
  }
279
251
 
280
252
  /**
@@ -288,18 +260,31 @@ export async function mobileRemoveCertificate(this: XCUITestDriver, name: string
288
260
  */
289
261
  export async function mobileListCertificates(this: XCUITestDriver): Promise<CertificateList> {
290
262
  requireRealDevice(this, 'Listing certificates');
291
- if (!this.opts.udid) {
292
- throw new Error('udid capability is required');
293
- }
263
+ return await withCertificateClient(this, async (client) => client.listCertificates());
264
+ }
294
265
 
266
+ /**
267
+ * Helper function to create a CertificateClient, execute an operation, and ensure cleanup.
268
+ *
269
+ * @param driver - The XCUITestDriver instance
270
+ * @param operation - A callback function that receives the client and performs the operation
271
+ * @returns The result of the operation callback
272
+ */
273
+ async function withCertificateClient<T>(
274
+ driver: XCUITestDriver,
275
+ operation: (client: CertificateClient) => Promise<T>,
276
+ ): Promise<T> {
295
277
  let client: CertificateClient | null = null;
296
278
  try {
279
+ if (!driver.opts.udid) {
280
+ throw new Error('udid capability is required');
281
+ }
297
282
  client = await CertificateClient.create(
298
- this.opts.udid,
299
- this.log,
300
- isIos18OrNewer(this.opts)
283
+ driver.opts.udid,
284
+ driver.log,
285
+ isIos18OrNewer(driver.opts),
301
286
  );
302
- return await client.listCertificates();
287
+ return await operation(client);
303
288
  } finally {
304
289
  if (client) {
305
290
  await client.close();
@@ -264,6 +264,7 @@ export class RealDevice {
264
264
  readonly udid: string;
265
265
  private readonly _log: AppiumLogger;
266
266
  readonly devicectl: Devicectl;
267
+ private platformVersion: string | undefined;
267
268
 
268
269
  constructor(udid: string, logger?: AppiumLogger) {
269
270
  this.udid = udid;
@@ -293,18 +294,20 @@ export class RealDevice {
293
294
  timeoutMs = IO_TIMEOUT_MS,
294
295
  } = opts;
295
296
  const timer = new timing.Timer().start();
296
- const afcService = await services.startAfcService(this.udid);
297
+ const platformVersion = await this.getPlatformVersion();
298
+ const useRemoteXPC = !!platformVersion && util.compareVersions(platformVersion, '>=', '18.0');
299
+ const afcClient = await AfcClient.createForDevice(this.udid, useRemoteXPC);
297
300
  try {
298
301
  let bundlePathOnPhone: string;
299
302
  if ((await fs.stat(appPath)).isFile()) {
300
303
  // https://github.com/doronz88/pymobiledevice3/blob/6ff5001f5776e03b610363254e82d7fbcad4ef5f/pymobiledevice3/services/installation_proxy.py#L75
301
304
  bundlePathOnPhone = `/${path.basename(appPath)}`;
302
- await pushFile(afcService, appPath, bundlePathOnPhone, {
305
+ await pushFile(afcClient, appPath, bundlePathOnPhone, {
303
306
  timeoutMs,
304
307
  });
305
308
  } else {
306
309
  bundlePathOnPhone = `${INSTALLATION_STAGING_DIR}/${bundleId}`;
307
- await pushFolder(afcService, appPath, bundlePathOnPhone, {
310
+ await pushFolder(afcClient, appPath, bundlePathOnPhone, {
308
311
  enableParallelPush: true,
309
312
  timeoutMs,
310
313
  });
@@ -325,7 +328,7 @@ export class RealDevice {
325
328
  errMessage += `. Original error: ${(err as Error).message}`;
326
329
  throw new Error(errMessage);
327
330
  } finally {
328
- afcService.close();
331
+ await afcClient.close();
329
332
  }
330
333
  this.log.info(
331
334
  `The installation of '${bundleId}' succeeded after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`
@@ -513,7 +516,10 @@ export class RealDevice {
513
516
  }
514
517
 
515
518
  async getPlatformVersion(): Promise<string> {
516
- return await utilities.getOSVersion(this.udid);
519
+ if (!this.platformVersion) {
520
+ this.platformVersion = await utilities.getOSVersion(this.udid) as string;
521
+ }
522
+ return this.platformVersion;
517
523
  }
518
524
 
519
525
  async reset(opts: {bundleId?: string; fullReset?: boolean}): Promise<void> {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "10.16.0",
3
+ "version": "10.16.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appium-xcuitest-driver",
9
- "version": "10.16.0",
9
+ "version": "10.16.2",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@appium/strongbox": "^1.0.0-rc.1",
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "xcuitest",
9
9
  "xctest"
10
10
  ],
11
- "version": "10.16.0",
11
+ "version": "10.16.2",
12
12
  "author": "Appium Contributors",
13
13
  "license": "Apache-2.0",
14
14
  "repository": {