appium-xcuitest-driver 11.2.4 → 11.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [11.3.0](https://github.com/appium/appium-xcuitest-driver/compare/v11.2.4...v11.3.0) (2026-05-09)
2
+
3
+ ### Features
4
+
5
+ * add download-wda command ([#2835](https://github.com/appium/appium-xcuitest-driver/issues/2835)) ([1f568b4](https://github.com/appium/appium-xcuitest-driver/commit/1f568b4823a75ede182afdc7c82b73193f554765))
6
+
1
7
  ## [11.2.4](https://github.com/appium/appium-xcuitest-driver/compare/v11.2.3...v11.2.4) (2026-05-08)
2
8
 
3
9
  ### Bug Fixes
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "11.2.4",
3
+ "version": "11.3.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appium-xcuitest-driver",
9
- "version": "11.2.4",
9
+ "version": "11.3.0",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@appium/strongbox": "^1.0.0-rc.1",
@@ -240,6 +240,18 @@
240
240
  "sharp": "0.34.5"
241
241
  }
242
242
  },
243
+ "node_modules/@appium/support/node_modules/semver": {
244
+ "version": "7.7.4",
245
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
246
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
247
+ "license": "ISC",
248
+ "bin": {
249
+ "semver": "bin/semver.js"
250
+ },
251
+ "engines": {
252
+ "node": ">=10"
253
+ }
254
+ },
243
255
  "node_modules/@appium/tsconfig": {
244
256
  "version": "1.1.2",
245
257
  "resolved": "https://registry.npmjs.org/@appium/tsconfig/-/tsconfig-1.1.2.tgz",
@@ -551,9 +563,9 @@
551
563
  }
552
564
  },
553
565
  "node_modules/appium-ios-device": {
554
- "version": "3.1.12",
555
- "resolved": "https://registry.npmjs.org/appium-ios-device/-/appium-ios-device-3.1.12.tgz",
556
- "integrity": "sha512-2EEeGzWz2uDmUJftxuZ4b5DCptGqvQuND+FDMQ6p4qOpxbQX6E5HmAs0LyeepB/xAxkUP9wXZdBRl1OnrLKqvg==",
566
+ "version": "3.1.13",
567
+ "resolved": "https://registry.npmjs.org/appium-ios-device/-/appium-ios-device-3.1.13.tgz",
568
+ "integrity": "sha512-W10U63ISs2z/OwrkvRkSpGJeLc3qeBfIBhKd33jLaaDZE3VNR3yD7vLVLBfXxVaaM6UFOqx3yL5BtoeYltsmYQ==",
557
569
  "license": "Apache-2.0",
558
570
  "dependencies": {
559
571
  "@appium/support": "^7.2.2",
@@ -655,9 +667,9 @@
655
667
  }
656
668
  },
657
669
  "node_modules/appium-webdriveragent": {
658
- "version": "12.2.1",
659
- "resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-12.2.1.tgz",
660
- "integrity": "sha512-iSY3s4EUiNqY7SZg36ufI3Jt84dBDcFxIUxmusAUJzjxkHPYy+VNTOyIdtuP5RkhFNoSh4VHg8JjusGKqdKWwg==",
670
+ "version": "12.2.2",
671
+ "resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-12.2.2.tgz",
672
+ "integrity": "sha512-/GbzAjEHaaNgBUK8eVnmtf8s2fudjyCi55IBoEzv0sFg/188Bo+wsJfQhECjrk9CdhkpiwjsHAlJGLUy+iEpIQ==",
661
673
  "license": "Apache-2.0",
662
674
  "dependencies": {
663
675
  "@appium/base-driver": "^10.3.0",
@@ -667,7 +679,7 @@
667
679
  "appium-ios-simulator": "^8.0.0",
668
680
  "async-lock": "^1.0.0",
669
681
  "asyncbox": "^6.1.0",
670
- "axios": "^1.4.0",
682
+ "axios": "^1.16.0",
671
683
  "teen_process": "^4.0.7"
672
684
  },
673
685
  "engines": {
@@ -3450,9 +3462,9 @@
3450
3462
  "optional": true
3451
3463
  },
3452
3464
  "node_modules/semver": {
3453
- "version": "7.7.4",
3454
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
3455
- "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
3465
+ "version": "7.8.0",
3466
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
3467
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
3456
3468
  "license": "ISC",
3457
3469
  "bin": {
3458
3470
  "semver": "bin/semver.js"
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "xcuitest",
9
9
  "xctest"
10
10
  ],
11
- "version": "11.2.4",
11
+ "version": "11.3.0",
12
12
  "author": "Appium Contributors",
13
13
  "license": "Apache-2.0",
14
14
  "repository": {
@@ -34,6 +34,7 @@
34
34
  "build-wda": "./scripts/build-wda.mjs",
35
35
  "open-wda": "./scripts/open-wda.mjs",
36
36
  "tunnel-creation": "./scripts/tunnel-creation.mjs",
37
+ "download-wda": "./scripts/download-wda.mjs",
37
38
  "download-wda-sim": "./scripts/download-wda-sim.mjs",
38
39
  "image-mounter": "./scripts/image-mounter.mjs",
39
40
  "list-real-devices": "./scripts/list-real-devices.mjs",
@@ -1,80 +1,25 @@
1
- import {fs, logger, zip, net, node} from 'appium/support.js';
2
- import _ from 'lodash';
3
- import os from 'node:os';
4
- import path from 'node:path';
1
+ import {getWDAPrebuiltPackage} from './download-wda.mjs';
5
2
  import {Command} from 'commander';
3
+ import { deprecate } from 'node:util';
6
4
 
7
- const log = logger.getLogger('download-wda-sim');
8
- const wdaUrl = (/** @type {string} */ version, /** @type {string} */ zipFileName) =>
9
- `https://github.com/appium/WebDriverAgent/releases/download/v${version}/${zipFileName}`;
10
- const destZip = (/** @type {string} */ platform) => {
11
- const scheme = `WebDriverAgentRunner${_.toLower(platform) === 'tvos' ? '_tvOS' : ''}`;
12
- return `${scheme}-Build-Sim-${os.arch() === 'arm64' ? 'arm64' : 'x86_64'}.zip`;
13
- };
14
-
15
- /**
16
- * Return installed appium-webdriveragent package version
17
- * @returns {Promise<string>}
18
- */
19
- async function webdriveragentPkgVersion() {
20
- const moduleRoot = node.getModuleRootSync('appium-xcuitest-driver', import.meta.url);
21
- if (!moduleRoot) {
22
- throw new Error('Cannot resolve module root for appium-xcuitest-driver');
23
- }
24
- const pkgPath = path.join(
25
- moduleRoot,
26
- 'node_modules',
27
- 'appium-webdriveragent',
28
- 'package.json'
29
- );
30
- const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
31
- return String(pkg.version);
32
- };
33
-
34
- /**
35
- * Prepare the working root directory.
36
- * @param {string} outdir
37
- * @returns {Promise<string>} Root directory to download and unzip.
38
- */
39
- async function prepareRootDir(outdir) {
40
- const destDir = path.resolve(process.cwd(), outdir);
41
- if (await fs.exists(destDir)) {
42
- throw new Error(`${destDir} already exists`);
43
- }
44
- await fs.mkdir(destDir, {recursive: true});
45
- return destDir;
46
- }
47
-
48
- /**
49
- * @param {DownloadOptions} options
50
- */
51
- async function getWDAPrebuiltPackage(options) {
52
- const destDir = await prepareRootDir(options.outdir);
53
- const zipFileName = destZip(options.platform);
54
- const wdaVersion = await webdriveragentPkgVersion();
55
- const urlToDownload = wdaUrl(wdaVersion, zipFileName);
56
- const downloadedZipFile = path.join(destDir, zipFileName);
57
- try {
58
- log.info(`Downloading ${urlToDownload}`);
59
- await net.downloadFile(urlToDownload, downloadedZipFile);
60
-
61
- log.info(`Unpacking ${downloadedZipFile} into ${destDir}`);
62
- await zip.extractAllTo(downloadedZipFile, destDir);
63
-
64
- log.info(`Deleting ${downloadedZipFile}`);
65
- } finally {
66
- if (await fs.exists(downloadedZipFile)) {
67
- await fs.unlink(downloadedZipFile);
68
- }
69
- }
70
- }
5
+ const DEPRECATION_MESSAGE =
6
+ "[DEPRECATED] 'download-wda-sim' is deprecated. " +
7
+ "Use 'appium driver run xcuitest download-wda -- --kind=sim --platform=<platform> --outdir=<outdir>' instead.";
71
8
 
72
9
  async function main() {
73
10
  const program = new Command();
74
11
 
12
+ const oldHandler = deprecate(
13
+ async (options) => {
14
+ await getWDAPrebuiltPackage({...options, kind: 'sim'});
15
+ },
16
+ DEPRECATION_MESSAGE
17
+ );
18
+
75
19
  program
76
20
  .name('appium driver run xcuitest download-wda-sim')
77
21
  .description('Download a prebuilt WebDriverAgentRunner for iOS/tvOS simulator')
22
+ .addHelpText('beforeAll', `${DEPRECATION_MESSAGE}\n\n`)
78
23
  .requiredOption('--outdir <path>', 'Destination directory to download and unpack into')
79
24
  .requiredOption(
80
25
  '--platform <platform>',
@@ -86,14 +31,12 @@ async function main() {
86
31
  `
87
32
  EXAMPLES:
88
33
  # Download WDA for iOS simulator
89
- appium driver run xcuitest download-wda-sim --outdir ./wda-sim --platform iOS
34
+ appium driver run xcuitest download-wda-sim -- --outdir ./wda-sim --platform iOS
90
35
 
91
36
  # Download WDA for tvOS simulator
92
- appium driver run xcuitest download-wda-sim --outdir ./wda-sim-tvos --platform tvOS`,
37
+ appium driver run xcuitest download-wda-sim -- --outdir ./wda-sim-tvos --platform tvOS`,
93
38
  )
94
- .action(async (options) => {
95
- await getWDAPrebuiltPackage(options);
96
- });
39
+ .action(oldHandler);
97
40
 
98
41
  await program.parseAsync(process.argv);
99
42
  }
@@ -0,0 +1,167 @@
1
+ import {fs, logger, zip, net, node} from 'appium/support.js';
2
+ import {constants as fsConstants, promises as fsPromises} from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import {pathToFileURL} from 'node:url';
6
+ import {Command} from 'commander';
7
+
8
+ const log = logger.getLogger('download-wda');
9
+ const WDA_KIND_REAL = 'real';
10
+ const WDA_KIND_SIM = 'sim';
11
+
12
+ const wdaUrl = (/** @type {string} */ version, /** @type {string} */ zipFileName) =>
13
+ `https://github.com/appium/WebDriverAgent/releases/download/v${version}/${zipFileName}`;
14
+
15
+ /**
16
+ * Download and unpack a prebuilt WDA package for the given platform and kind.
17
+ * @param {DownloadOptions} options
18
+ * @returns {Promise<void>}
19
+ */
20
+ export async function getWDAPrebuiltPackage(options) {
21
+ const kind = normalizeKind(options.kind);
22
+ const destDir = await prepareRootDir(options.outdir);
23
+ const zipFileName = destZip(options.platform, kind);
24
+ const wdaVersion = await getWebdriveragentPkgVersion();
25
+ const urlToDownload = wdaUrl(wdaVersion, zipFileName);
26
+ const downloadedZipFile = path.join(destDir, zipFileName);
27
+ try {
28
+ log.info(`Downloading ${urlToDownload}`);
29
+ await net.downloadFile(urlToDownload, downloadedZipFile);
30
+
31
+ log.info(`Unpacking ${downloadedZipFile} into ${destDir}`);
32
+ await zip.extractAllTo(downloadedZipFile, destDir);
33
+
34
+ log.info(`Deleting ${downloadedZipFile}`);
35
+ } finally {
36
+ if (await fs.exists(downloadedZipFile)) {
37
+ await fs.unlink(downloadedZipFile);
38
+ }
39
+ }
40
+ }
41
+
42
+ const destZip = (/** @type {string} */ platform, /** @type {WDAKind} */ kind) => {
43
+ const scheme = `WebDriverAgentRunner${String(platform).toLowerCase() === 'tvos' ? '_tvOS' : ''}`;
44
+ if (kind === WDA_KIND_SIM) {
45
+ return `${scheme}-Build-Sim-${os.arch() === 'arm64' ? 'arm64' : 'x86_64'}.zip`;
46
+ }
47
+ return `${scheme}-Runner.zip`;
48
+ };
49
+
50
+ /**
51
+ * Normalize the kind value, ensuring it is either 'real' or 'sim'. Default to 'real' if undefined.
52
+ * @param {string | undefined} kind
53
+ * @returns {WDAKind}
54
+ */
55
+ function normalizeKind(kind) {
56
+ const normalized = String(kind || WDA_KIND_REAL).toLowerCase();
57
+ if (![WDA_KIND_REAL, WDA_KIND_SIM].includes(normalized)) {
58
+ throw new Error(`Unsupported kind '${kind}'. Supported values are '${WDA_KIND_REAL}' and '${WDA_KIND_SIM}'`);
59
+ }
60
+ return /** @type {WDAKind} */ (normalized);
61
+ }
62
+
63
+ /**
64
+ * Return installed appium-webdriveragent package version
65
+ * @returns {Promise<string>}
66
+ */
67
+ async function getWebdriveragentPkgVersion() {
68
+ const moduleRoot = node.getModuleRootSync('appium-xcuitest-driver', import.meta.url);
69
+ if (!moduleRoot) {
70
+ throw new Error('Cannot resolve module root for appium-xcuitest-driver');
71
+ }
72
+ const pkgPath = path.join(
73
+ moduleRoot,
74
+ 'node_modules',
75
+ 'appium-webdriveragent',
76
+ 'package.json'
77
+ );
78
+ const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
79
+ if (!pkg.version || typeof pkg.version !== 'string') {
80
+ throw new Error(`Cannot find version in ${pkgPath}`);
81
+ }
82
+ return pkg.version;
83
+ };
84
+
85
+ /**
86
+ * Prepare the working root directory.
87
+ * @param {string} outdir
88
+ * @returns {Promise<string>} Root directory to download and unzip.
89
+ */
90
+ async function prepareRootDir(outdir) {
91
+ const destDir = path.resolve(process.cwd(), outdir);
92
+ if (await fs.exists(destDir)) {
93
+ throw new Error(`${destDir} already exists`);
94
+ }
95
+
96
+ const parentDir = path.dirname(destDir);
97
+ try {
98
+ await fsPromises.access(parentDir, fsConstants.W_OK);
99
+ } catch (err) {
100
+ throw new Error(`Parent directory '${parentDir}' is not writable`, {
101
+ cause: err,
102
+ });
103
+ }
104
+
105
+ try {
106
+ await fs.mkdir(destDir, {recursive: true});
107
+ } catch (err) {
108
+ const message = err instanceof Error ? err.message : String(err);
109
+ throw new Error(`Cannot create directory '${destDir}': ${message}`, {
110
+ cause: err,
111
+ });
112
+ }
113
+ return destDir;
114
+ }
115
+
116
+ async function main() {
117
+ const program = new Command();
118
+
119
+ program
120
+ .name('appium driver run xcuitest download-wda')
121
+ .description('Download a prebuilt WebDriverAgentRunner for iOS/tvOS real devices or simulators')
122
+ .requiredOption('--outdir <path>', 'Destination directory to download and unpack into')
123
+ .requiredOption(
124
+ '--platform <platform>',
125
+ 'Target platform (e.g. iOS or tvOS)',
126
+ (value) => value,
127
+ )
128
+ .option(
129
+ '--kind <kind>',
130
+ `Target package type: ${WDA_KIND_REAL} (real devices) or ${WDA_KIND_SIM} (simulators). Default: ${WDA_KIND_REAL}`,
131
+ )
132
+ .addHelpText(
133
+ 'after',
134
+ `
135
+ EXAMPLES:
136
+ # Download WDA for iOS real device (default)
137
+ appium driver run xcuitest download-wda -- --outdir ./wda-real --platform iOS
138
+
139
+ # Download WDA for tvOS simulator
140
+ appium driver run xcuitest download-wda -- --outdir ./wda-sim-tvos --platform tvOS --kind sim`,
141
+ )
142
+ .action(async (options) => {
143
+ await getWDAPrebuiltPackage({
144
+ ...options,
145
+ kind: options.kind ?? WDA_KIND_REAL,
146
+ });
147
+ });
148
+
149
+ await program.parseAsync(process.argv);
150
+ }
151
+
152
+ const isMainModule =
153
+ Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
154
+ if (isMainModule) {
155
+ await main();
156
+ }
157
+
158
+ /**
159
+ * @typedef {'real' | 'sim'} WDAKind
160
+ */
161
+
162
+ /**
163
+ * @typedef {Object} DownloadOptions
164
+ * @property {string} outdir
165
+ * @property {string} platform
166
+ * @property {WDAKind | undefined} [kind]
167
+ */