appium-xcuitest-driver 10.41.0 → 10.42.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
+ ## [10.42.0](https://github.com/appium/appium-xcuitest-driver/compare/v10.41.0...v10.42.0) (2026-04-06)
2
+
3
+ ### Features
4
+
5
+ * Use remotexpc to delete stale native video recordings ([#2795](https://github.com/appium/appium-xcuitest-driver/issues/2795)) ([2efb765](https://github.com/appium/appium-xcuitest-driver/commit/2efb7656cce9fb5e625b2076ca834b021996d87a))
6
+
1
7
  ## [10.41.0](https://github.com/appium/appium-xcuitest-driver/compare/v10.40.2...v10.41.0) (2026-04-02)
2
8
 
3
9
  ### Features
@@ -4,10 +4,11 @@ import type { XcTestScreenRecordingInfo, XcTestScreenRecording } from './types';
4
4
  /**
5
5
  * Start a new screen recording via XCTest.
6
6
  *
7
- * Even though the feature is available for real devices
8
- * there is no possibility to delete stored video files yet,
9
- * which may lead to internal storage overload.
10
- * That is why it was put under a security feature flag.
7
+ * On **real devices**, if **iOS 18+** and a new enough **appium-ios-remotexpc** (with
8
+ * **XCTestAttachment**) are present, the attachment is removed after stop and the
9
+ * `xctest_screen_record` insecure feature is **not** required.
10
+ * If deletion cannot be performed (older iOS, package missing, or too old), you must enable
11
+ * the `xctest_screen_record` insecure feature to start recording.
11
12
  *
12
13
  * If the recording is already running this API is a noop.
13
14
  *
@@ -31,10 +32,13 @@ export declare function mobileGetXctestScreenRecordingInfo(this: XCUITestDriver)
31
32
  * The resulting movie is returned as base-64 string or is uploaded to
32
33
  * a remote location if corresponding options have been provided.
33
34
  *
34
- * The resulting movie is automatically deleted FOR SIMULATORS ONLY.
35
- * In order to clean it up from a real device it is necessary to properly
36
- * shut down XCTest by calling `GET /wda/shutdown` API to the WebDriverAgent server running
37
- * on the device directly or by doing factory reset.
35
+ * The resulting movie is automatically deleted from the host temp file FOR SIMULATORS ONLY.
36
+ * On **real devices**, after a successful pull the driver removes the XCTest attachment via
37
+ * **appium-ios-remotexpc** when the same conditions hold as for starting without
38
+ * `xctest_screen_record` (iOS 18+, package present, **XCTestAttachment** export). Otherwise
39
+ * device-side delete is skipped. That deletion runs even if Base64 encoding or remote upload
40
+ * fails afterward (the original encode/upload error is still thrown); if both fail, delete errors
41
+ * are logged as warnings so the encode/upload failure remains primary.
38
42
  *
39
43
  * @since Xcode 15/iOS 17
40
44
  * @param remotePath - The path to the remote location, where the resulting video should be
@@ -1 +1 @@
1
- {"version":3,"file":"xctest-record-screen.d.ts","sourceRoot":"","sources":["../../../lib/commands/xctest-record-screen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,WAAW,CAAC;AAG9C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAC,yBAAyB,EAAE,qBAAqB,EAAC,MAAM,SAAS,CAAC;AA8D9E;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gCAAgC,CACpD,IAAI,EAAE,cAAc,EACpB,GAAG,CAAC,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,yBAAyB,CAAC,CAsBpC;AAED;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAE3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,cAAc,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,WAAW,EACrB,aAAa,CAAC,EAAE,MAAM,EACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAClD,MAAM,GAAE,KAAK,GAAG,MAAM,GAAG,OAAe,GACvC,OAAO,CAAC,qBAAqB,CAAC,CA0BhC"}
1
+ {"version":3,"file":"xctest-record-screen.d.ts","sourceRoot":"","sources":["../../../lib/commands/xctest-record-screen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,WAAW,CAAC;AAG9C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAC,yBAAyB,EAAE,qBAAqB,EAAC,MAAM,SAAS,CAAC;AAgE9E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gCAAgC,CACpD,IAAI,EAAE,cAAc,EACpB,GAAG,CAAC,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,yBAAyB,CAAC,CA2BpC;AAED;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAE3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,cAAc,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,WAAW,EACrB,aAAa,CAAC,EAAE,MAAM,EACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAClD,MAAM,GAAE,KAAK,GAAG,MAAM,GAAG,OAAe,GACvC,OAAO,CAAC,qBAAqB,CAAC,CAqEhC"}
@@ -10,8 +10,10 @@ const lodash_1 = __importDefault(require("lodash"));
10
10
  const support_1 = require("appium/support");
11
11
  const utils_1 = require("../utils");
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
+ const xctest_attachment_deletion_client_1 = require("../device/xctest-attachment-deletion-client");
13
14
  const MOV_EXT = '.mov';
14
- const FEATURE_NAME = 'xctest_screen_record';
15
+ /** Insecure feature when real-device XCTest recording is used without RemoteXPC attachment deletion. */
16
+ const XCTEST_SCREEN_RECORD_FEATURE = 'xctest_screen_record';
15
17
  const DOMAIN_IDENTIFIER = 'com.apple.testmanagerd';
16
18
  const DOMAIN_TYPE = 'appDataContainer';
17
19
  const USERNAME = 'mobile';
@@ -64,10 +66,11 @@ async function retrieveXcTestScreenRecording(uuid) {
64
66
  /**
65
67
  * Start a new screen recording via XCTest.
66
68
  *
67
- * Even though the feature is available for real devices
68
- * there is no possibility to delete stored video files yet,
69
- * which may lead to internal storage overload.
70
- * That is why it was put under a security feature flag.
69
+ * On **real devices**, if **iOS 18+** and a new enough **appium-ios-remotexpc** (with
70
+ * **XCTestAttachment**) are present, the attachment is removed after stop and the
71
+ * `xctest_screen_record` insecure feature is **not** required.
72
+ * If deletion cannot be performed (older iOS, package missing, or too old), you must enable
73
+ * the `xctest_screen_record` insecure feature to start recording.
71
74
  *
72
75
  * If the recording is already running this API is a noop.
73
76
  *
@@ -79,10 +82,10 @@ async function retrieveXcTestScreenRecording(uuid) {
79
82
  */
80
83
  async function mobileStartXctestScreenRecording(fps, codec) {
81
84
  if (this.isRealDevice()) {
82
- // This feature might be used to abuse real devices as there is no
83
- // reliable way (yet) to cleanup video recordings stored there
84
- // by the testmanagerd daemon
85
- this.assertFeatureEnabled(FEATURE_NAME);
85
+ const canDeleteAfterStop = await xctest_attachment_deletion_client_1.XctestAttachmentDeletionClient.isDeletionAvailable(this.opts.udid ?? '', this.opts.platformVersion ?? '', undefined, this.log);
86
+ if (!canDeleteAfterStop) {
87
+ this.assertFeatureEnabled(XCTEST_SCREEN_RECORD_FEATURE);
88
+ }
86
89
  }
87
90
  const opts = {};
88
91
  if (lodash_1.default.isInteger(codec)) {
@@ -110,10 +113,13 @@ async function mobileGetXctestScreenRecordingInfo() {
110
113
  * The resulting movie is returned as base-64 string or is uploaded to
111
114
  * a remote location if corresponding options have been provided.
112
115
  *
113
- * The resulting movie is automatically deleted FOR SIMULATORS ONLY.
114
- * In order to clean it up from a real device it is necessary to properly
115
- * shut down XCTest by calling `GET /wda/shutdown` API to the WebDriverAgent server running
116
- * on the device directly or by doing factory reset.
116
+ * The resulting movie is automatically deleted from the host temp file FOR SIMULATORS ONLY.
117
+ * On **real devices**, after a successful pull the driver removes the XCTest attachment via
118
+ * **appium-ios-remotexpc** when the same conditions hold as for starting without
119
+ * `xctest_screen_record` (iOS 18+, package present, **XCTestAttachment** export). Otherwise
120
+ * device-side delete is skipped. That deletion runs even if Base64 encoding or remote upload
121
+ * fails afterward (the original encode/upload error is still thrown); if both fail, delete errors
122
+ * are logged as warnings so the encode/upload failure remains primary.
117
123
  *
118
124
  * @since Xcode 15/iOS 17
119
125
  * @param remotePath - The path to the remote location, where the resulting video should be
@@ -149,6 +155,8 @@ async function mobileStopXctestScreenRecording(remotePath, user, pass, headers,
149
155
  ...screenRecordingInfo,
150
156
  payload: '', // Will be set below
151
157
  };
158
+ let encodeOrUploadError;
159
+ let attachmentDeleteError;
152
160
  try {
153
161
  result.payload = await (0, utils_1.encodeBase64OrUpload)(videoPath, remotePath, {
154
162
  user,
@@ -159,8 +167,37 @@ async function mobileStopXctestScreenRecording(remotePath, user, pass, headers,
159
167
  method,
160
168
  });
161
169
  }
170
+ catch (err) {
171
+ encodeOrUploadError = err;
172
+ }
162
173
  finally {
163
174
  await support_1.fs.rimraf(videoPath);
175
+ if (this.isRealDevice() && this.opts.udid) {
176
+ try {
177
+ const canDelete = await xctest_attachment_deletion_client_1.XctestAttachmentDeletionClient.isDeletionAvailable(this.opts.udid, this.opts.platformVersion ?? '', undefined, this.log);
178
+ if (canDelete) {
179
+ const deletionClient = await xctest_attachment_deletion_client_1.XctestAttachmentDeletionClient.create(this.opts.udid, this.opts.platformVersion ?? '');
180
+ await deletionClient.deleteAttachmentsByUuid([screenRecordingInfo.uuid]);
181
+ }
182
+ else {
183
+ this.log.debug('Skipping XCTest attachment deletion on device (RemoteXPC deletion not available for this session)');
184
+ }
185
+ }
186
+ catch (deleteErr) {
187
+ if (encodeOrUploadError === undefined) {
188
+ attachmentDeleteError = deleteErr;
189
+ }
190
+ else {
191
+ this.log.warn(`Could not delete XCTest attachment on device after stop (encode/upload had already failed): ${deleteErr?.message ?? deleteErr}`);
192
+ }
193
+ }
194
+ }
195
+ }
196
+ if (encodeOrUploadError !== undefined) {
197
+ throw encodeOrUploadError;
198
+ }
199
+ if (attachmentDeleteError !== undefined) {
200
+ throw attachmentDeleteError;
164
201
  }
165
202
  return result;
166
203
  }
@@ -1 +1 @@
1
- {"version":3,"file":"xctest-record-screen.js","sourceRoot":"","sources":["../../../lib/commands/xctest-record-screen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"xctest-record-screen.js","sourceRoot":"","sources":["../../../lib/commands/xctest-record-screen.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Services, XCTestRunner } from 'appium-ios-remotexpc';
2
+ export type RemoteXPCEsmModule = typeof import('appium-ios-remotexpc');
2
3
  /**
3
4
  * Get the RemoteXPC Services module dynamically
4
5
  *
@@ -10,6 +11,31 @@ import type { Services, XCTestRunner } from 'appium-ios-remotexpc';
10
11
  * @throws {Error} If the module cannot be imported
11
12
  */
12
13
  export declare function getRemoteXPCServices(): Promise<typeof Services>;
14
+ /**
15
+ * Try to load appium-ios-remotexpc without throwing (e.g. for optional features).
16
+ * Successful loads share the same cache as {@link getRemoteXPCServices}.
17
+ *
18
+ * If the package is **not installed** (resolution error for **appium-ios-remotexpc**), subsequent
19
+ * calls return `null` without re-importing. Other import failures are recorded via
20
+ * {@link getLastRemoteXPCOptionalImportError} and **do not** permanently disable retries.
21
+ */
22
+ export declare function tryGetRemoteXPCServices(): Promise<typeof Services | null>;
23
+ /**
24
+ * Whether {@link tryGetRemoteXPCServices} has determined that **appium-ios-remotexpc** is not
25
+ * installed (same process will not retry optional import).
26
+ */
27
+ export declare function isRemoteXPCOptionalDependencyMissing(): boolean;
28
+ /**
29
+ * Last error from an optional RemoteXPC `import()`, including transient failures. Cleared when a
30
+ * load succeeds. When {@link isRemoteXPCOptionalDependencyMissing} is `true`, this matches the
31
+ * stored missing-package error.
32
+ */
33
+ export declare function getLastRemoteXPCOptionalImportError(): Error | null;
34
+ /**
35
+ * Full **appium-ios-remotexpc** module after a successful optional load (same `import()` as
36
+ * {@link tryGetRemoteXPCServices}). Returns `null` if the package is missing or failed to load.
37
+ */
38
+ export declare function tryGetRemoteXPCModule(): Promise<RemoteXPCEsmModule | null>;
13
39
  /**
14
40
  * Get the XCTestRunner class dynamically from appium-ios-remotexpc
15
41
  *
@@ -1 +1 @@
1
- {"version":3,"file":"remotexpc-utils.d.ts","sourceRoot":"","sources":["../../../lib/device/remotexpc-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,QAAQ,EAAE,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAiBjE;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,QAAQ,CAAC,CAiCrE;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,YAAY,CAAC,CAuBzE"}
1
+ {"version":3,"file":"remotexpc-utils.d.ts","sourceRoot":"","sources":["../../../lib/device/remotexpc-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,QAAQ,EAAE,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,cAAc,sBAAsB,CAAC,CAAC;AAyEvE;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,QAAQ,CAAC,CAyBrE;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,QAAQ,GAAG,IAAI,CAAC,CAkC/E;AAED;;;GAGG;AACH,wBAAgB,oCAAoC,IAAI,OAAO,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,IAAI,KAAK,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAGhF;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,YAAY,CAAC,CA6BzE"}
@@ -4,14 +4,35 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getRemoteXPCServices = getRemoteXPCServices;
7
+ exports.tryGetRemoteXPCServices = tryGetRemoteXPCServices;
8
+ exports.isRemoteXPCOptionalDependencyMissing = isRemoteXPCOptionalDependencyMissing;
9
+ exports.getLastRemoteXPCOptionalImportError = getLastRemoteXPCOptionalImportError;
10
+ exports.tryGetRemoteXPCModule = tryGetRemoteXPCModule;
7
11
  exports.getXCTestRunnerClass = getXCTestRunnerClass;
8
12
  const support_1 = require("appium/support");
9
13
  const node_path_1 = __importDefault(require("node:path"));
10
14
  const node_fs_1 = require("node:fs");
15
+ /**
16
+ * Full ESM namespace after a successful `import('appium-ios-remotexpc')` (e.g. **XCTestAttachment**).
17
+ * Set together with {@link cachedRemoteXPCServices}.
18
+ */
19
+ let cachedRemoteXPCFullModule = null;
11
20
  /**
12
21
  * Cached RemoteXPC Services module
13
22
  */
14
23
  let cachedRemoteXPCServices = null;
24
+ /**
25
+ * Set when **appium-ios-remotexpc** resolution failed in a way that is unlikely to succeed on
26
+ * retry in the same process (package not installed). Transient import errors do not set this.
27
+ */
28
+ let remoteXpcModuleUnavailable = false;
29
+ /** Stored only when {@link remoteXpcModuleUnavailable} is set (missing-package case). */
30
+ let lastRemoteXpcImportError = null;
31
+ /**
32
+ * Most recent failed optional `import('appium-ios-remotexpc')` from {@link tryGetRemoteXPCServices}
33
+ * (including full-module backfill). Cleared when an optional load succeeds.
34
+ */
35
+ let lastTryGetRemoteXPCImportError = null;
15
36
  /**
16
37
  * Cached XCTestRunner class
17
38
  */
@@ -20,6 +41,31 @@ let cachedXCTestRunnerClass = null;
20
41
  * Module root and version cached at initialization
21
42
  */
22
43
  const { moduleRoot, remoteXpcVersion } = fetchInstallInfo();
44
+ /**
45
+ * Whether `err` indicates the **appium-ios-remotexpc** package is not installed / not resolvable,
46
+ * as opposed to a transient or corrupt-install failure that may succeed on a later attempt.
47
+ */
48
+ function isAppiumIosRemotexpcPackageMissingError(err) {
49
+ const msg = err.message;
50
+ return ((msg.includes('Cannot find module') && msg.includes('appium-ios-remotexpc')) ||
51
+ (msg.includes('Cannot find package') && msg.includes('appium-ios-remotexpc')));
52
+ }
53
+ function throwRemoteXPCImportError(err) {
54
+ if (err.message.includes('Cannot find module')) {
55
+ let errorMessage = 'Failed to import appium-ios-remotexpc module. ' +
56
+ 'This module is required for iOS 18 and above device operations.';
57
+ if (moduleRoot && remoteXpcVersion) {
58
+ errorMessage +=
59
+ ' Please install it by running: ' +
60
+ `cd "${moduleRoot}" && npm install "appium-ios-remotexpc@${remoteXpcVersion}".`;
61
+ }
62
+ errorMessage += ` Original error: ${err.message}`;
63
+ throw new Error(errorMessage);
64
+ }
65
+ throw new Error('Failed to import appium-ios-remotexpc module. ' +
66
+ 'This module is required for iOS 18 and above device operations. ' +
67
+ `Original error: ${err.message}`);
68
+ }
23
69
  /**
24
70
  * Get the RemoteXPC Services module dynamically
25
71
  *
@@ -32,30 +78,98 @@ const { moduleRoot, remoteXpcVersion } = fetchInstallInfo();
32
78
  */
33
79
  async function getRemoteXPCServices() {
34
80
  if (cachedRemoteXPCServices) {
81
+ if (!cachedRemoteXPCFullModule) {
82
+ try {
83
+ cachedRemoteXPCFullModule = (await import('appium-ios-remotexpc'));
84
+ }
85
+ catch (err) {
86
+ throwRemoteXPCImportError(err);
87
+ }
88
+ }
89
+ lastTryGetRemoteXPCImportError = null;
35
90
  return cachedRemoteXPCServices;
36
91
  }
92
+ if (remoteXpcModuleUnavailable && lastRemoteXpcImportError) {
93
+ throwRemoteXPCImportError(lastRemoteXpcImportError);
94
+ }
37
95
  try {
38
- const remotexpcModule = await import('appium-ios-remotexpc');
96
+ const remotexpcModule = (await import('appium-ios-remotexpc'));
97
+ cachedRemoteXPCFullModule = remotexpcModule;
39
98
  cachedRemoteXPCServices = remotexpcModule.Services;
99
+ lastTryGetRemoteXPCImportError = null;
40
100
  return cachedRemoteXPCServices;
41
101
  }
42
102
  catch (err) {
43
- const error = err;
44
- if (error.message.includes('Cannot find module')) {
45
- let errorMessage = 'Failed to import appium-ios-remotexpc module. ' +
46
- 'This module is required for iOS 18 and above device operations.';
47
- if (moduleRoot && remoteXpcVersion) {
48
- errorMessage +=
49
- ' Please install it by running: ' +
50
- `cd "${moduleRoot}" && npm install "appium-ios-remotexpc@${remoteXpcVersion}".`;
103
+ throwRemoteXPCImportError(err);
104
+ }
105
+ }
106
+ /**
107
+ * Try to load appium-ios-remotexpc without throwing (e.g. for optional features).
108
+ * Successful loads share the same cache as {@link getRemoteXPCServices}.
109
+ *
110
+ * If the package is **not installed** (resolution error for **appium-ios-remotexpc**), subsequent
111
+ * calls return `null` without re-importing. Other import failures are recorded via
112
+ * {@link getLastRemoteXPCOptionalImportError} and **do not** permanently disable retries.
113
+ */
114
+ async function tryGetRemoteXPCServices() {
115
+ if (cachedRemoteXPCServices) {
116
+ if (!cachedRemoteXPCFullModule) {
117
+ try {
118
+ cachedRemoteXPCFullModule = (await import('appium-ios-remotexpc'));
119
+ lastTryGetRemoteXPCImportError = null;
120
+ }
121
+ catch (err) {
122
+ lastTryGetRemoteXPCImportError = err;
123
+ /* ignore: tryGetRemoteXPCModule may still return null for XCTestAttachment callers */
51
124
  }
52
- errorMessage += ` Original error: ${error.message}`;
53
- throw new Error(errorMessage);
54
125
  }
55
- throw new Error('Failed to import appium-ios-remotexpc module. ' +
56
- 'This module is required for iOS 18 and above device operations. ' +
57
- `Original error: ${error.message}`);
126
+ else {
127
+ lastTryGetRemoteXPCImportError = null;
128
+ }
129
+ return cachedRemoteXPCServices;
130
+ }
131
+ if (remoteXpcModuleUnavailable) {
132
+ return null;
133
+ }
134
+ try {
135
+ const remotexpcModule = (await import('appium-ios-remotexpc'));
136
+ cachedRemoteXPCFullModule = remotexpcModule;
137
+ cachedRemoteXPCServices = remotexpcModule.Services;
138
+ lastTryGetRemoteXPCImportError = null;
139
+ return cachedRemoteXPCServices;
58
140
  }
141
+ catch (err) {
142
+ const error = err;
143
+ lastTryGetRemoteXPCImportError = error;
144
+ if (isAppiumIosRemotexpcPackageMissingError(error)) {
145
+ lastRemoteXpcImportError = error;
146
+ remoteXpcModuleUnavailable = true;
147
+ }
148
+ return null;
149
+ }
150
+ }
151
+ /**
152
+ * Whether {@link tryGetRemoteXPCServices} has determined that **appium-ios-remotexpc** is not
153
+ * installed (same process will not retry optional import).
154
+ */
155
+ function isRemoteXPCOptionalDependencyMissing() {
156
+ return remoteXpcModuleUnavailable;
157
+ }
158
+ /**
159
+ * Last error from an optional RemoteXPC `import()`, including transient failures. Cleared when a
160
+ * load succeeds. When {@link isRemoteXPCOptionalDependencyMissing} is `true`, this matches the
161
+ * stored missing-package error.
162
+ */
163
+ function getLastRemoteXPCOptionalImportError() {
164
+ return lastTryGetRemoteXPCImportError;
165
+ }
166
+ /**
167
+ * Full **appium-ios-remotexpc** module after a successful optional load (same `import()` as
168
+ * {@link tryGetRemoteXPCServices}). Returns `null` if the package is missing or failed to load.
169
+ */
170
+ async function tryGetRemoteXPCModule() {
171
+ await tryGetRemoteXPCServices();
172
+ return cachedRemoteXPCFullModule;
59
173
  }
60
174
  /**
61
175
  * Get the XCTestRunner class dynamically from appium-ios-remotexpc
@@ -67,8 +181,12 @@ async function getXCTestRunnerClass() {
67
181
  if (cachedXCTestRunnerClass) {
68
182
  return cachedXCTestRunnerClass;
69
183
  }
184
+ await getRemoteXPCServices();
185
+ const remotexpcModule = cachedRemoteXPCFullModule;
186
+ if (!remotexpcModule) {
187
+ throw new Error('appium-ios-remotexpc loaded Services but full module cache is missing; cannot load XCTestRunner.');
188
+ }
70
189
  try {
71
- const remotexpcModule = await import('appium-ios-remotexpc');
72
190
  const XCTestRunnerClass = remotexpcModule.XCTestRunner;
73
191
  if (typeof XCTestRunnerClass !== 'function') {
74
192
  throw new Error('XCTestRunner is not exported from appium-ios-remotexpc. ' +
@@ -1 +1 @@
1
- {"version":3,"file":"remotexpc-utils.js","sourceRoot":"","sources":["../../../lib/device/remotexpc-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remotexpc-utils.js","sourceRoot":"","sources":["../../../lib/device/remotexpc-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { AppiumLogger } from '@appium/types';
2
+ type XCTestAttachmentCtor = new (udid: string) => {
3
+ delete(uuids: string[]): Promise<unknown>;
4
+ };
5
+ /** Subset of appium-ios-remotexpc exports used here (types may lag the runtime package). */
6
+ export type RemotexpcAttachmentModule = {
7
+ XCTestAttachment?: XCTestAttachmentCtor;
8
+ };
9
+ export interface IXctestAttachmentDeletionClient {
10
+ deleteAttachmentsByUuid(uuids: string[]): Promise<void>;
11
+ }
12
+ /**
13
+ * Deletes XCTest screen-recording attachments on a real device via appium-ios-remotexpc
14
+ * (testmanagerd). Use {@link isDeletionAvailable} before start; {@link create} returns a client
15
+ * ready to delete (or throws if deletion cannot run).
16
+ */
17
+ export declare class XctestAttachmentDeletionClient implements IXctestAttachmentDeletionClient {
18
+ private readonly udid;
19
+ private readonly XCTestAttachment;
20
+ private constructor();
21
+ /**
22
+ * Whether attachment deletion can run: **iOS 18+**, **appium-ios-remotexpc** loadable, and
23
+ * **XCTestAttachment** exported (new enough package).
24
+ *
25
+ * @param remotexpcModule - optional pre-loaded module (for unit tests)
26
+ * @param log - if set, warns when the package is present but too old (no **XCTestAttachment** export)
27
+ */
28
+ static isDeletionAvailable(udid: string, platformVersion: string, remotexpcModule?: RemotexpcAttachmentModule | null, log?: AppiumLogger): Promise<boolean>;
29
+ /**
30
+ * @param remotexpcModule - optional pre-loaded module (for unit tests)
31
+ * @throws {Error} If real-device XCTest attachment deletion is not supported
32
+ */
33
+ static create(udid: string, platformVersion: string, remotexpcModule?: RemotexpcAttachmentModule | null): Promise<XctestAttachmentDeletionClient>;
34
+ deleteAttachmentsByUuid(uuids: string[]): Promise<void>;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=xctest-attachment-deletion-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xctest-attachment-deletion-client.d.ts","sourceRoot":"","sources":["../../../lib/device/xctest-attachment-deletion-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAQhD,KAAK,oBAAoB,GAAG,KAAK,IAAI,EAAE,MAAM,KAAK;IAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC;AAE9F,4FAA4F;AAC5F,MAAM,MAAM,yBAAyB,GAAG;IACtC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;CACzC,CAAC;AAEF,MAAM,WAAW,+BAA+B;IAC9C,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED;;;;GAIG;AACH,qBAAa,8BAA+B,YAAW,+BAA+B;IAElF,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAFnC,OAAO;IAKP;;;;;;OAMG;WACU,mBAAmB,CAC9B,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAClD,GAAG,CAAC,EAAE,YAAY,GACjB,OAAO,CAAC,OAAO,CAAC;IAoBnB;;;OAGG;WACU,MAAM,CACjB,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,yBAAyB,GAAG,IAAI,GACjD,OAAO,CAAC,8BAA8B,CAAC;IAsCpC,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAO9D"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XctestAttachmentDeletionClient = void 0;
4
+ const remotexpc_utils_1 = require("./remotexpc-utils");
5
+ const utils_1 = require("../utils");
6
+ const REMOTEXPC_UPGRADE_HINT = 'Upgrade appium-ios-remotexpc to a version that exports XCTestAttachment ' +
7
+ '(XCTest screen recording attachment deletion on real devices).';
8
+ /**
9
+ * Deletes XCTest screen-recording attachments on a real device via appium-ios-remotexpc
10
+ * (testmanagerd). Use {@link isDeletionAvailable} before start; {@link create} returns a client
11
+ * ready to delete (or throws if deletion cannot run).
12
+ */
13
+ class XctestAttachmentDeletionClient {
14
+ udid;
15
+ XCTestAttachment;
16
+ constructor(udid, XCTestAttachment) {
17
+ this.udid = udid;
18
+ this.XCTestAttachment = XCTestAttachment;
19
+ }
20
+ /**
21
+ * Whether attachment deletion can run: **iOS 18+**, **appium-ios-remotexpc** loadable, and
22
+ * **XCTestAttachment** exported (new enough package).
23
+ *
24
+ * @param remotexpcModule - optional pre-loaded module (for unit tests)
25
+ * @param log - if set, warns when the package is present but too old (no **XCTestAttachment** export)
26
+ */
27
+ static async isDeletionAvailable(udid, platformVersion, remotexpcModule, log) {
28
+ if (!udid?.trim() || !(0, utils_1.isIos18OrNewerPlatform)(platformVersion)) {
29
+ return false;
30
+ }
31
+ let mod = remotexpcModule;
32
+ if (mod === undefined) {
33
+ mod = (await (0, remotexpc_utils_1.tryGetRemoteXPCModule)());
34
+ if (!mod) {
35
+ return false;
36
+ }
37
+ }
38
+ if (typeof mod?.XCTestAttachment === 'function') {
39
+ return true;
40
+ }
41
+ if (mod && log) {
42
+ log.warn(REMOTEXPC_UPGRADE_HINT);
43
+ }
44
+ return false;
45
+ }
46
+ /**
47
+ * @param remotexpcModule - optional pre-loaded module (for unit tests)
48
+ * @throws {Error} If real-device XCTest attachment deletion is not supported
49
+ */
50
+ static async create(udid, platformVersion, remotexpcModule) {
51
+ if (!udid?.trim()) {
52
+ throw new Error('A device UDID is required for XCTest screen recording on a real device so attachments can be removed after stop.');
53
+ }
54
+ if (!(0, utils_1.isIos18OrNewerPlatform)(platformVersion)) {
55
+ throw new Error('XCTest screen recording on a real device requires iOS 18 or newer. ' +
56
+ 'The driver removes recordings from the device after stop using appium-ios-remotexpc, which is only supported on iOS 18+.');
57
+ }
58
+ let mod = remotexpcModule;
59
+ if (mod === undefined) {
60
+ mod = (await (0, remotexpc_utils_1.tryGetRemoteXPCModule)());
61
+ if (!mod) {
62
+ throw new Error('appium-ios-remotexpc must be installed to use XCTest screen recording on a real device. ' +
63
+ 'It is used to delete screen-recording attachments after stop.');
64
+ }
65
+ }
66
+ const XCTestAttachment = mod?.XCTestAttachment;
67
+ if (!mod || typeof XCTestAttachment !== 'function') {
68
+ throw new Error('The installed appium-ios-remotexpc package must export XCTestAttachment for real-device XCTest screen recording. ' +
69
+ REMOTEXPC_UPGRADE_HINT);
70
+ }
71
+ return new XctestAttachmentDeletionClient(udid.trim(), XCTestAttachment);
72
+ }
73
+ async deleteAttachmentsByUuid(uuids) {
74
+ if (!uuids.length) {
75
+ return;
76
+ }
77
+ const attachment = new this.XCTestAttachment(this.udid);
78
+ await attachment.delete(uuids);
79
+ }
80
+ }
81
+ exports.XctestAttachmentDeletionClient = XctestAttachmentDeletionClient;
82
+ //# sourceMappingURL=xctest-attachment-deletion-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xctest-attachment-deletion-client.js","sourceRoot":"","sources":["../../../lib/device/xctest-attachment-deletion-client.ts"],"names":[],"mappings":";;;AACA,uDAAwD;AACxD,oCAAgD;AAEhD,MAAM,sBAAsB,GAC1B,0EAA0E;IAC1E,gEAAgE,CAAC;AAanE;;;;GAIG;AACH,MAAa,8BAA8B;IAEtB;IACA;IAFnB,YACmB,IAAY,EACZ,gBAAsC;QADtC,SAAI,GAAJ,IAAI,CAAQ;QACZ,qBAAgB,GAAhB,gBAAgB,CAAsB;IACtD,CAAC;IAEJ;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAC9B,IAAY,EACZ,eAAuB,EACvB,eAAkD,EAClD,GAAkB;QAElB,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAA,8BAAsB,EAAC,eAAe,CAAC,EAAE,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,GAAG,GAAiD,eAAe,CAAC;QACxE,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,GAAG,GAAG,CAAC,MAAM,IAAA,uCAAqB,GAAE,CAAqC,CAAC;YAC1E,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,IAAI,OAAO,GAAG,EAAE,gBAAgB,KAAK,UAAU,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,IAAY,EACZ,eAAuB,EACvB,eAAkD;QAElD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,kHAAkH,CACnH,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAA,8BAAsB,EAAC,eAAe,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CACb,qEAAqE;gBACnE,0HAA0H,CAC7H,CAAC;QACJ,CAAC;QAED,IAAI,GAAG,GAAiD,eAAe,CAAC;QACxE,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,GAAG,GAAG,CAAC,MAAM,IAAA,uCAAqB,GAAE,CAAqC,CAAC;YAC1E,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CACb,0FAA0F;oBACxF,+DAA+D,CAClE,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,gBAAgB,GAAG,GAAG,EAAE,gBAAgB,CAAC;QAC/C,IAAI,CAAC,GAAG,IAAI,OAAO,gBAAgB,KAAK,UAAU,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CACb,mHAAmH;gBACjH,sBAAsB,CACzB,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,8BAA8B,CACvC,IAAI,CAAC,IAAI,EAAE,EACX,gBAAwC,CACzC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,KAAe;QAC3C,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,MAAM,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;CACF;AA3FD,wEA2FC"}
@@ -7,9 +7,11 @@ import type {Simulator} from 'appium-ios-simulator';
7
7
  import type {RealDevice} from '../device/real-device-management';
8
8
  import type {HTTPHeaders} from '@appium/types';
9
9
  import type {XcTestScreenRecordingInfo, XcTestScreenRecording} from './types';
10
+ import {XctestAttachmentDeletionClient} from '../device/xctest-attachment-deletion-client';
10
11
 
11
12
  const MOV_EXT = '.mov';
12
- const FEATURE_NAME = 'xctest_screen_record';
13
+ /** Insecure feature when real-device XCTest recording is used without RemoteXPC attachment deletion. */
14
+ const XCTEST_SCREEN_RECORD_FEATURE = 'xctest_screen_record';
13
15
  const DOMAIN_IDENTIFIER = 'com.apple.testmanagerd';
14
16
  const DOMAIN_TYPE = 'appDataContainer';
15
17
  const USERNAME = 'mobile';
@@ -71,10 +73,11 @@ async function retrieveXcTestScreenRecording(this: XCUITestDriver, uuid: string)
71
73
  /**
72
74
  * Start a new screen recording via XCTest.
73
75
  *
74
- * Even though the feature is available for real devices
75
- * there is no possibility to delete stored video files yet,
76
- * which may lead to internal storage overload.
77
- * That is why it was put under a security feature flag.
76
+ * On **real devices**, if **iOS 18+** and a new enough **appium-ios-remotexpc** (with
77
+ * **XCTestAttachment**) are present, the attachment is removed after stop and the
78
+ * `xctest_screen_record` insecure feature is **not** required.
79
+ * If deletion cannot be performed (older iOS, package missing, or too old), you must enable
80
+ * the `xctest_screen_record` insecure feature to start recording.
78
81
  *
79
82
  * If the recording is already running this API is a noop.
80
83
  *
@@ -90,10 +93,15 @@ export async function mobileStartXctestScreenRecording(
90
93
  codec?: number,
91
94
  ): Promise<XcTestScreenRecordingInfo> {
92
95
  if (this.isRealDevice()) {
93
- // This feature might be used to abuse real devices as there is no
94
- // reliable way (yet) to cleanup video recordings stored there
95
- // by the testmanagerd daemon
96
- this.assertFeatureEnabled(FEATURE_NAME);
96
+ const canDeleteAfterStop = await XctestAttachmentDeletionClient.isDeletionAvailable(
97
+ this.opts.udid ?? '',
98
+ this.opts.platformVersion ?? '',
99
+ undefined,
100
+ this.log,
101
+ );
102
+ if (!canDeleteAfterStop) {
103
+ this.assertFeatureEnabled(XCTEST_SCREEN_RECORD_FEATURE);
104
+ }
97
105
  }
98
106
 
99
107
  const opts: {codec?: number; fps?: number} = {};
@@ -130,10 +138,13 @@ export async function mobileGetXctestScreenRecordingInfo(
130
138
  * The resulting movie is returned as base-64 string or is uploaded to
131
139
  * a remote location if corresponding options have been provided.
132
140
  *
133
- * The resulting movie is automatically deleted FOR SIMULATORS ONLY.
134
- * In order to clean it up from a real device it is necessary to properly
135
- * shut down XCTest by calling `GET /wda/shutdown` API to the WebDriverAgent server running
136
- * on the device directly or by doing factory reset.
141
+ * The resulting movie is automatically deleted from the host temp file FOR SIMULATORS ONLY.
142
+ * On **real devices**, after a successful pull the driver removes the XCTest attachment via
143
+ * **appium-ios-remotexpc** when the same conditions hold as for starting without
144
+ * `xctest_screen_record` (iOS 18+, package present, **XCTestAttachment** export). Otherwise
145
+ * device-side delete is skipped. That deletion runs even if Base64 encoding or remote upload
146
+ * fails afterward (the original encode/upload error is still thrown); if both fail, delete errors
147
+ * are logged as warnings so the encode/upload failure remains primary.
137
148
  *
138
149
  * @since Xcode 15/iOS 17
139
150
  * @param remotePath - The path to the remote location, where the resulting video should be
@@ -179,6 +190,8 @@ export async function mobileStopXctestScreenRecording(
179
190
  ...screenRecordingInfo,
180
191
  payload: '', // Will be set below
181
192
  };
193
+ let encodeOrUploadError: unknown;
194
+ let attachmentDeleteError: unknown;
182
195
  try {
183
196
  result.payload = await encodeBase64OrUpload(videoPath, remotePath, {
184
197
  user,
@@ -188,8 +201,49 @@ export async function mobileStopXctestScreenRecording(
188
201
  formFields,
189
202
  method,
190
203
  });
204
+ } catch (err) {
205
+ encodeOrUploadError = err;
191
206
  } finally {
192
207
  await fs.rimraf(videoPath);
208
+ if (this.isRealDevice() && this.opts.udid) {
209
+ try {
210
+ const canDelete = await XctestAttachmentDeletionClient.isDeletionAvailable(
211
+ this.opts.udid,
212
+ this.opts.platformVersion ?? '',
213
+ undefined,
214
+ this.log,
215
+ );
216
+ if (canDelete) {
217
+ const deletionClient = await XctestAttachmentDeletionClient.create(
218
+ this.opts.udid,
219
+ this.opts.platformVersion ?? '',
220
+ );
221
+ await deletionClient.deleteAttachmentsByUuid([screenRecordingInfo.uuid]);
222
+ } else {
223
+ this.log.debug(
224
+ 'Skipping XCTest attachment deletion on device (RemoteXPC deletion not available for this session)',
225
+ );
226
+ }
227
+ } catch (deleteErr: any) {
228
+ if (encodeOrUploadError === undefined) {
229
+ attachmentDeleteError = deleteErr;
230
+ } else {
231
+ this.log.warn(
232
+ `Could not delete XCTest attachment on device after stop (encode/upload had already failed): ${
233
+ deleteErr?.message ?? deleteErr
234
+ }`,
235
+ );
236
+ }
237
+ }
238
+ }
239
+ }
240
+
241
+ if (encodeOrUploadError !== undefined) {
242
+ throw encodeOrUploadError;
193
243
  }
244
+ if (attachmentDeleteError !== undefined) {
245
+ throw attachmentDeleteError;
246
+ }
247
+
194
248
  return result;
195
249
  }
@@ -3,11 +3,34 @@ import path from 'node:path';
3
3
  import {readFileSync} from 'node:fs';
4
4
  import type {Services, XCTestRunner} from 'appium-ios-remotexpc';
5
5
 
6
+ export type RemoteXPCEsmModule = typeof import('appium-ios-remotexpc');
7
+
8
+ /**
9
+ * Full ESM namespace after a successful `import('appium-ios-remotexpc')` (e.g. **XCTestAttachment**).
10
+ * Set together with {@link cachedRemoteXPCServices}.
11
+ */
12
+ let cachedRemoteXPCFullModule: RemoteXPCEsmModule | null = null;
13
+
6
14
  /**
7
15
  * Cached RemoteXPC Services module
8
16
  */
9
17
  let cachedRemoteXPCServices: typeof Services | null = null;
10
18
 
19
+ /**
20
+ * Set when **appium-ios-remotexpc** resolution failed in a way that is unlikely to succeed on
21
+ * retry in the same process (package not installed). Transient import errors do not set this.
22
+ */
23
+ let remoteXpcModuleUnavailable = false;
24
+
25
+ /** Stored only when {@link remoteXpcModuleUnavailable} is set (missing-package case). */
26
+ let lastRemoteXpcImportError: Error | null = null;
27
+
28
+ /**
29
+ * Most recent failed optional `import('appium-ios-remotexpc')` from {@link tryGetRemoteXPCServices}
30
+ * (including full-module backfill). Cleared when an optional load succeeds.
31
+ */
32
+ let lastTryGetRemoteXPCImportError: Error | null = null;
33
+
11
34
  /**
12
35
  * Cached XCTestRunner class
13
36
  */
@@ -18,6 +41,41 @@ let cachedXCTestRunnerClass: typeof XCTestRunner | null = null;
18
41
  */
19
42
  const {moduleRoot, remoteXpcVersion} = fetchInstallInfo();
20
43
 
44
+ /**
45
+ * Whether `err` indicates the **appium-ios-remotexpc** package is not installed / not resolvable,
46
+ * as opposed to a transient or corrupt-install failure that may succeed on a later attempt.
47
+ */
48
+ function isAppiumIosRemotexpcPackageMissingError(err: Error): boolean {
49
+ const msg = err.message;
50
+ return (
51
+ (msg.includes('Cannot find module') && msg.includes('appium-ios-remotexpc')) ||
52
+ (msg.includes('Cannot find package') && msg.includes('appium-ios-remotexpc'))
53
+ );
54
+ }
55
+
56
+ function throwRemoteXPCImportError(err: Error): never {
57
+ if (err.message.includes('Cannot find module')) {
58
+ let errorMessage =
59
+ 'Failed to import appium-ios-remotexpc module. ' +
60
+ 'This module is required for iOS 18 and above device operations.';
61
+
62
+ if (moduleRoot && remoteXpcVersion) {
63
+ errorMessage +=
64
+ ' Please install it by running: ' +
65
+ `cd "${moduleRoot}" && npm install "appium-ios-remotexpc@${remoteXpcVersion}".`;
66
+ }
67
+
68
+ errorMessage += ` Original error: ${err.message}`;
69
+ throw new Error(errorMessage);
70
+ }
71
+
72
+ throw new Error(
73
+ 'Failed to import appium-ios-remotexpc module. ' +
74
+ 'This module is required for iOS 18 and above device operations. ' +
75
+ `Original error: ${err.message}`,
76
+ );
77
+ }
78
+
21
79
  /**
22
80
  * Get the RemoteXPC Services module dynamically
23
81
  *
@@ -30,39 +88,101 @@ const {moduleRoot, remoteXpcVersion} = fetchInstallInfo();
30
88
  */
31
89
  export async function getRemoteXPCServices(): Promise<typeof Services> {
32
90
  if (cachedRemoteXPCServices) {
91
+ if (!cachedRemoteXPCFullModule) {
92
+ try {
93
+ cachedRemoteXPCFullModule = (await import('appium-ios-remotexpc')) as RemoteXPCEsmModule;
94
+ } catch (err) {
95
+ throwRemoteXPCImportError(err as Error);
96
+ }
97
+ }
98
+ lastTryGetRemoteXPCImportError = null;
33
99
  return cachedRemoteXPCServices;
34
100
  }
101
+ if (remoteXpcModuleUnavailable && lastRemoteXpcImportError) {
102
+ throwRemoteXPCImportError(lastRemoteXpcImportError);
103
+ }
35
104
 
36
105
  try {
37
- const remotexpcModule = await import('appium-ios-remotexpc');
106
+ const remotexpcModule = (await import('appium-ios-remotexpc')) as RemoteXPCEsmModule;
107
+ cachedRemoteXPCFullModule = remotexpcModule;
38
108
  cachedRemoteXPCServices = remotexpcModule.Services;
109
+ lastTryGetRemoteXPCImportError = null;
39
110
  return cachedRemoteXPCServices;
40
111
  } catch (err) {
41
- const error = err as Error;
42
-
43
- if (error.message.includes('Cannot find module')) {
44
- let errorMessage =
45
- 'Failed to import appium-ios-remotexpc module. ' +
46
- 'This module is required for iOS 18 and above device operations.';
112
+ throwRemoteXPCImportError(err as Error);
113
+ }
114
+ }
47
115
 
48
- if (moduleRoot && remoteXpcVersion) {
49
- errorMessage +=
50
- ' Please install it by running: ' +
51
- `cd "${moduleRoot}" && npm install "appium-ios-remotexpc@${remoteXpcVersion}".`;
116
+ /**
117
+ * Try to load appium-ios-remotexpc without throwing (e.g. for optional features).
118
+ * Successful loads share the same cache as {@link getRemoteXPCServices}.
119
+ *
120
+ * If the package is **not installed** (resolution error for **appium-ios-remotexpc**), subsequent
121
+ * calls return `null` without re-importing. Other import failures are recorded via
122
+ * {@link getLastRemoteXPCOptionalImportError} and **do not** permanently disable retries.
123
+ */
124
+ export async function tryGetRemoteXPCServices(): Promise<typeof Services | null> {
125
+ if (cachedRemoteXPCServices) {
126
+ if (!cachedRemoteXPCFullModule) {
127
+ try {
128
+ cachedRemoteXPCFullModule = (await import('appium-ios-remotexpc')) as RemoteXPCEsmModule;
129
+ lastTryGetRemoteXPCImportError = null;
130
+ } catch (err) {
131
+ lastTryGetRemoteXPCImportError = err as Error;
132
+ /* ignore: tryGetRemoteXPCModule may still return null for XCTestAttachment callers */
52
133
  }
53
-
54
- errorMessage += ` Original error: ${error.message}`;
55
- throw new Error(errorMessage);
134
+ } else {
135
+ lastTryGetRemoteXPCImportError = null;
56
136
  }
137
+ return cachedRemoteXPCServices;
138
+ }
139
+ if (remoteXpcModuleUnavailable) {
140
+ return null;
141
+ }
57
142
 
58
- throw new Error(
59
- 'Failed to import appium-ios-remotexpc module. ' +
60
- 'This module is required for iOS 18 and above device operations. ' +
61
- `Original error: ${error.message}`,
62
- );
143
+ try {
144
+ const remotexpcModule = (await import('appium-ios-remotexpc')) as RemoteXPCEsmModule;
145
+ cachedRemoteXPCFullModule = remotexpcModule;
146
+ cachedRemoteXPCServices = remotexpcModule.Services;
147
+ lastTryGetRemoteXPCImportError = null;
148
+ return cachedRemoteXPCServices;
149
+ } catch (err) {
150
+ const error = err as Error;
151
+ lastTryGetRemoteXPCImportError = error;
152
+ if (isAppiumIosRemotexpcPackageMissingError(error)) {
153
+ lastRemoteXpcImportError = error;
154
+ remoteXpcModuleUnavailable = true;
155
+ }
156
+ return null;
63
157
  }
64
158
  }
65
159
 
160
+ /**
161
+ * Whether {@link tryGetRemoteXPCServices} has determined that **appium-ios-remotexpc** is not
162
+ * installed (same process will not retry optional import).
163
+ */
164
+ export function isRemoteXPCOptionalDependencyMissing(): boolean {
165
+ return remoteXpcModuleUnavailable;
166
+ }
167
+
168
+ /**
169
+ * Last error from an optional RemoteXPC `import()`, including transient failures. Cleared when a
170
+ * load succeeds. When {@link isRemoteXPCOptionalDependencyMissing} is `true`, this matches the
171
+ * stored missing-package error.
172
+ */
173
+ export function getLastRemoteXPCOptionalImportError(): Error | null {
174
+ return lastTryGetRemoteXPCImportError;
175
+ }
176
+
177
+ /**
178
+ * Full **appium-ios-remotexpc** module after a successful optional load (same `import()` as
179
+ * {@link tryGetRemoteXPCServices}). Returns `null` if the package is missing or failed to load.
180
+ */
181
+ export async function tryGetRemoteXPCModule(): Promise<RemoteXPCEsmModule | null> {
182
+ await tryGetRemoteXPCServices();
183
+ return cachedRemoteXPCFullModule;
184
+ }
185
+
66
186
  /**
67
187
  * Get the XCTestRunner class dynamically from appium-ios-remotexpc
68
188
  *
@@ -74,8 +194,14 @@ export async function getXCTestRunnerClass(): Promise<typeof XCTestRunner> {
74
194
  return cachedXCTestRunnerClass;
75
195
  }
76
196
 
197
+ await getRemoteXPCServices();
198
+ const remotexpcModule = cachedRemoteXPCFullModule;
199
+ if (!remotexpcModule) {
200
+ throw new Error(
201
+ 'appium-ios-remotexpc loaded Services but full module cache is missing; cannot load XCTestRunner.',
202
+ );
203
+ }
77
204
  try {
78
- const remotexpcModule = await import('appium-ios-remotexpc');
79
205
  const XCTestRunnerClass = remotexpcModule.XCTestRunner;
80
206
  if (typeof XCTestRunnerClass !== 'function') {
81
207
  throw new Error(
@@ -0,0 +1,116 @@
1
+ import type {AppiumLogger} from '@appium/types';
2
+ import {tryGetRemoteXPCModule} from './remotexpc-utils';
3
+ import {isIos18OrNewerPlatform} from '../utils';
4
+
5
+ const REMOTEXPC_UPGRADE_HINT =
6
+ 'Upgrade appium-ios-remotexpc to a version that exports XCTestAttachment ' +
7
+ '(XCTest screen recording attachment deletion on real devices).';
8
+
9
+ type XCTestAttachmentCtor = new (udid: string) => {delete(uuids: string[]): Promise<unknown>};
10
+
11
+ /** Subset of appium-ios-remotexpc exports used here (types may lag the runtime package). */
12
+ export type RemotexpcAttachmentModule = {
13
+ XCTestAttachment?: XCTestAttachmentCtor;
14
+ };
15
+
16
+ export interface IXctestAttachmentDeletionClient {
17
+ deleteAttachmentsByUuid(uuids: string[]): Promise<void>;
18
+ }
19
+
20
+ /**
21
+ * Deletes XCTest screen-recording attachments on a real device via appium-ios-remotexpc
22
+ * (testmanagerd). Use {@link isDeletionAvailable} before start; {@link create} returns a client
23
+ * ready to delete (or throws if deletion cannot run).
24
+ */
25
+ export class XctestAttachmentDeletionClient implements IXctestAttachmentDeletionClient {
26
+ private constructor(
27
+ private readonly udid: string,
28
+ private readonly XCTestAttachment: XCTestAttachmentCtor,
29
+ ) {}
30
+
31
+ /**
32
+ * Whether attachment deletion can run: **iOS 18+**, **appium-ios-remotexpc** loadable, and
33
+ * **XCTestAttachment** exported (new enough package).
34
+ *
35
+ * @param remotexpcModule - optional pre-loaded module (for unit tests)
36
+ * @param log - if set, warns when the package is present but too old (no **XCTestAttachment** export)
37
+ */
38
+ static async isDeletionAvailable(
39
+ udid: string,
40
+ platformVersion: string,
41
+ remotexpcModule?: RemotexpcAttachmentModule | null,
42
+ log?: AppiumLogger,
43
+ ): Promise<boolean> {
44
+ if (!udid?.trim() || !isIos18OrNewerPlatform(platformVersion)) {
45
+ return false;
46
+ }
47
+ let mod: RemotexpcAttachmentModule | null | undefined = remotexpcModule;
48
+ if (mod === undefined) {
49
+ mod = (await tryGetRemoteXPCModule()) as RemotexpcAttachmentModule | null;
50
+ if (!mod) {
51
+ return false;
52
+ }
53
+ }
54
+ if (typeof mod?.XCTestAttachment === 'function') {
55
+ return true;
56
+ }
57
+ if (mod && log) {
58
+ log.warn(REMOTEXPC_UPGRADE_HINT);
59
+ }
60
+ return false;
61
+ }
62
+
63
+ /**
64
+ * @param remotexpcModule - optional pre-loaded module (for unit tests)
65
+ * @throws {Error} If real-device XCTest attachment deletion is not supported
66
+ */
67
+ static async create(
68
+ udid: string,
69
+ platformVersion: string,
70
+ remotexpcModule?: RemotexpcAttachmentModule | null,
71
+ ): Promise<XctestAttachmentDeletionClient> {
72
+ if (!udid?.trim()) {
73
+ throw new Error(
74
+ 'A device UDID is required for XCTest screen recording on a real device so attachments can be removed after stop.',
75
+ );
76
+ }
77
+ if (!isIos18OrNewerPlatform(platformVersion)) {
78
+ throw new Error(
79
+ 'XCTest screen recording on a real device requires iOS 18 or newer. ' +
80
+ 'The driver removes recordings from the device after stop using appium-ios-remotexpc, which is only supported on iOS 18+.',
81
+ );
82
+ }
83
+
84
+ let mod: RemotexpcAttachmentModule | null | undefined = remotexpcModule;
85
+ if (mod === undefined) {
86
+ mod = (await tryGetRemoteXPCModule()) as RemotexpcAttachmentModule | null;
87
+ if (!mod) {
88
+ throw new Error(
89
+ 'appium-ios-remotexpc must be installed to use XCTest screen recording on a real device. ' +
90
+ 'It is used to delete screen-recording attachments after stop.',
91
+ );
92
+ }
93
+ }
94
+
95
+ const XCTestAttachment = mod?.XCTestAttachment;
96
+ if (!mod || typeof XCTestAttachment !== 'function') {
97
+ throw new Error(
98
+ 'The installed appium-ios-remotexpc package must export XCTestAttachment for real-device XCTest screen recording. ' +
99
+ REMOTEXPC_UPGRADE_HINT,
100
+ );
101
+ }
102
+
103
+ return new XctestAttachmentDeletionClient(
104
+ udid.trim(),
105
+ XCTestAttachment as XCTestAttachmentCtor,
106
+ );
107
+ }
108
+
109
+ async deleteAttachmentsByUuid(uuids: string[]): Promise<void> {
110
+ if (!uuids.length) {
111
+ return;
112
+ }
113
+ const attachment = new this.XCTestAttachment(this.udid);
114
+ await attachment.delete(uuids);
115
+ }
116
+ }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "10.41.0",
3
+ "version": "10.42.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appium-xcuitest-driver",
9
- "version": "10.41.0",
9
+ "version": "10.42.0",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@appium/strongbox": "^1.0.0-rc.1",
@@ -583,9 +583,9 @@
583
583
  "license": "MIT"
584
584
  },
585
585
  "node_modules/@types/node": {
586
- "version": "25.5.0",
587
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz",
588
- "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
586
+ "version": "25.5.2",
587
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz",
588
+ "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==",
589
589
  "devOptional": true,
590
590
  "license": "MIT",
591
591
  "dependencies": {
@@ -703,9 +703,9 @@
703
703
  }
704
704
  },
705
705
  "node_modules/appium-ios-remotexpc": {
706
- "version": "0.43.2",
707
- "resolved": "https://registry.npmjs.org/appium-ios-remotexpc/-/appium-ios-remotexpc-0.43.2.tgz",
708
- "integrity": "sha512-ZIP8WSjj0Ayy7+rgJzcalHyTFnNtW0yTb1z90NPQ+S6M75FW50zej+MOVkrxHX4a9xpsavOFBdrZSdR+QXKGhQ==",
706
+ "version": "0.44.0",
707
+ "resolved": "https://registry.npmjs.org/appium-ios-remotexpc/-/appium-ios-remotexpc-0.44.0.tgz",
708
+ "integrity": "sha512-e7DbfRJuobWpsOHTpdtzWPlb2R3HvLEjzist9D5Lzk5bzpEDasYiV+hlr+mvq6VM7gjB7ZHN8lZ3CC5kF3HQAw==",
709
709
  "license": "Apache-2.0",
710
710
  "optional": true,
711
711
  "dependencies": {
@@ -2661,9 +2661,9 @@
2661
2661
  }
2662
2662
  },
2663
2663
  "node_modules/lru-cache": {
2664
- "version": "11.2.7",
2665
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz",
2666
- "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==",
2664
+ "version": "11.3.0",
2665
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.0.tgz",
2666
+ "integrity": "sha512-sr8xPKE25m6vJVcrdn6NxtC0fVfuPowbscLypegRgOm0yXSqr5JNHCAY3hnusdJ7HRBW04j6Ip4khvHU778DuQ==",
2667
2667
  "license": "BlueOak-1.0.0",
2668
2668
  "engines": {
2669
2669
  "node": "20 || >=22"
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "xcuitest",
9
9
  "xctest"
10
10
  ],
11
- "version": "10.41.0",
11
+ "version": "10.42.0",
12
12
  "author": "Appium Contributors",
13
13
  "license": "Apache-2.0",
14
14
  "repository": {