appium-ios-device 3.1.9 → 3.1.11

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.
Files changed (152) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/afc/index.d.ts +1 -1
  3. package/build/lib/afc/index.d.ts.map +1 -1
  4. package/build/lib/afc/index.js +9 -9
  5. package/build/lib/afc/index.js.map +1 -1
  6. package/build/lib/afc/protocol.d.ts.map +1 -1
  7. package/build/lib/afc/protocol.js +16 -16
  8. package/build/lib/afc/protocol.js.map +1 -1
  9. package/build/lib/afc/streams.d.ts.map +1 -1
  10. package/build/lib/afc/streams.js.map +1 -1
  11. package/build/lib/afc/transformer/afcdecoder.d.ts.map +1 -1
  12. package/build/lib/afc/transformer/afcdecoder.js.map +1 -1
  13. package/build/lib/afc/transformer/afcencoder.d.ts.map +1 -1
  14. package/build/lib/afc/transformer/afcencoder.js.map +1 -1
  15. package/build/lib/base-service.d.ts.map +1 -1
  16. package/build/lib/base-service.js.map +1 -1
  17. package/build/lib/house-arrest/index.d.ts.map +1 -1
  18. package/build/lib/house-arrest/index.js.map +1 -1
  19. package/build/lib/imagemounter/index.d.ts.map +1 -1
  20. package/build/lib/imagemounter/index.js +4 -4
  21. package/build/lib/imagemounter/index.js.map +1 -1
  22. package/build/lib/imagemounter/utils/list_developer_image.d.ts.map +1 -1
  23. package/build/lib/imagemounter/utils/list_developer_image.js +3 -3
  24. package/build/lib/imagemounter/utils/list_developer_image.js.map +1 -1
  25. package/build/lib/installation-proxy/index.d.ts +11 -11
  26. package/build/lib/installation-proxy/index.d.ts.map +1 -1
  27. package/build/lib/installation-proxy/index.js +19 -17
  28. package/build/lib/installation-proxy/index.js.map +1 -1
  29. package/build/lib/instrument/headers.d.ts.map +1 -1
  30. package/build/lib/instrument/headers.js +7 -7
  31. package/build/lib/instrument/headers.js.map +1 -1
  32. package/build/lib/instrument/index.d.ts +1 -1
  33. package/build/lib/instrument/index.d.ts.map +1 -1
  34. package/build/lib/instrument/index.js +13 -7
  35. package/build/lib/instrument/index.js.map +1 -1
  36. package/build/lib/instrument/transformer/dtx-decode.d.ts.map +1 -1
  37. package/build/lib/instrument/transformer/dtx-decode.js +9 -3
  38. package/build/lib/instrument/transformer/dtx-decode.js.map +1 -1
  39. package/build/lib/instrument/transformer/dtx-encode.d.ts.map +1 -1
  40. package/build/lib/instrument/transformer/dtx-encode.js +1 -1
  41. package/build/lib/instrument/transformer/dtx-encode.js.map +1 -1
  42. package/build/lib/instrument/transformer/nskeyed.d.ts.map +1 -1
  43. package/build/lib/instrument/transformer/nskeyed.js +16 -9
  44. package/build/lib/instrument/transformer/nskeyed.js.map +1 -1
  45. package/build/lib/lockdown/index.d.ts +5 -5
  46. package/build/lib/lockdown/index.d.ts.map +1 -1
  47. package/build/lib/lockdown/index.js +9 -10
  48. package/build/lib/lockdown/index.js.map +1 -1
  49. package/build/lib/logger.js.map +1 -1
  50. package/build/lib/mcinstall/index.d.ts.map +1 -1
  51. package/build/lib/mcinstall/index.js +14 -6
  52. package/build/lib/mcinstall/index.js.map +1 -1
  53. package/build/lib/notification-proxy/index.d.ts.map +1 -1
  54. package/build/lib/notification-proxy/index.js +2 -2
  55. package/build/lib/notification-proxy/index.js.map +1 -1
  56. package/build/lib/plist-service/index.d.ts.map +1 -1
  57. package/build/lib/plist-service/index.js.map +1 -1
  58. package/build/lib/plist-service/transformer/plist-service-decoder.d.ts.map +1 -1
  59. package/build/lib/plist-service/transformer/plist-service-decoder.js.map +1 -1
  60. package/build/lib/plist-service/transformer/plist-service-encoder.d.ts.map +1 -1
  61. package/build/lib/plist-service/transformer/plist-service-encoder.js.map +1 -1
  62. package/build/lib/services.d.ts.map +1 -1
  63. package/build/lib/services.js +3 -3
  64. package/build/lib/services.js.map +1 -1
  65. package/build/lib/simulatelocation/index.d.ts.map +1 -1
  66. package/build/lib/simulatelocation/index.js.map +1 -1
  67. package/build/lib/ssl-helper.js +3 -3
  68. package/build/lib/ssl-helper.js.map +1 -1
  69. package/build/lib/syslog/index.d.ts +1 -1
  70. package/build/lib/syslog/index.d.ts.map +1 -1
  71. package/build/lib/syslog/index.js +1 -1
  72. package/build/lib/syslog/index.js.map +1 -1
  73. package/build/lib/syslog/transformer/syslog-decoder.d.ts.map +1 -1
  74. package/build/lib/syslog/transformer/syslog-decoder.js +4 -2
  75. package/build/lib/syslog/transformer/syslog-decoder.js.map +1 -1
  76. package/build/lib/testmanagerd/index.d.ts.map +1 -1
  77. package/build/lib/testmanagerd/index.js.map +1 -1
  78. package/build/lib/usbmux/index.d.ts.map +1 -1
  79. package/build/lib/usbmux/index.js +16 -13
  80. package/build/lib/usbmux/index.js.map +1 -1
  81. package/build/lib/usbmux/transformer/usbmux-decoder.d.ts.map +1 -1
  82. package/build/lib/usbmux/transformer/usbmux-decoder.js +1 -1
  83. package/build/lib/usbmux/transformer/usbmux-decoder.js.map +1 -1
  84. package/build/lib/usbmux/transformer/usbmux-encoder.d.ts.map +1 -1
  85. package/build/lib/usbmux/transformer/usbmux-encoder.js +1 -1
  86. package/build/lib/usbmux/transformer/usbmux-encoder.js.map +1 -1
  87. package/build/lib/util/transformer/length-based-splitter.d.ts.map +1 -1
  88. package/build/lib/util/transformer/length-based-splitter.js +9 -4
  89. package/build/lib/util/transformer/length-based-splitter.js.map +1 -1
  90. package/build/lib/util/transformer/stream-logger.d.ts.map +1 -1
  91. package/build/lib/util/transformer/stream-logger.js +4 -3
  92. package/build/lib/util/transformer/stream-logger.js.map +1 -1
  93. package/build/lib/util/uuid/parse.js.map +1 -1
  94. package/build/lib/util/uuid/stringify.js.map +1 -1
  95. package/build/lib/util/uuid/validate.d.ts.map +1 -1
  96. package/build/lib/util/uuid/validate.js.map +1 -1
  97. package/build/lib/utilities.d.ts.map +1 -1
  98. package/build/lib/utilities.js +12 -12
  99. package/build/lib/utilities.js.map +1 -1
  100. package/build/lib/webinspector/index.d.ts.map +1 -1
  101. package/build/lib/webinspector/index.js +11 -9
  102. package/build/lib/webinspector/index.js.map +1 -1
  103. package/build/lib/webinspector/transformer/webinspector-decoder.d.ts.map +1 -1
  104. package/build/lib/webinspector/transformer/webinspector-decoder.js.map +1 -1
  105. package/build/lib/webinspector/transformer/webinspector-encoder.d.ts.map +1 -1
  106. package/build/lib/webinspector/transformer/webinspector-encoder.js.map +1 -1
  107. package/build/lib/xctest.d.ts.map +1 -1
  108. package/build/lib/xctest.js +3 -6
  109. package/build/lib/xctest.js.map +1 -1
  110. package/lib/afc/index.js +49 -43
  111. package/lib/afc/protocol.js +53 -50
  112. package/lib/afc/streams.js +7 -9
  113. package/lib/afc/transformer/afcdecoder.js +8 -10
  114. package/lib/afc/transformer/afcencoder.js +7 -10
  115. package/lib/base-service.js +2 -4
  116. package/lib/constants.js +1 -1
  117. package/lib/house-arrest/index.js +16 -14
  118. package/lib/imagemounter/index.js +107 -104
  119. package/lib/imagemounter/utils/list_developer_image.js +115 -100
  120. package/lib/installation-proxy/index.js +31 -27
  121. package/lib/instrument/headers.js +51 -40
  122. package/lib/instrument/index.js +32 -21
  123. package/lib/instrument/transformer/dtx-decode.js +30 -16
  124. package/lib/instrument/transformer/dtx-encode.js +6 -8
  125. package/lib/instrument/transformer/nskeyed.js +40 -21
  126. package/lib/lockdown/index.js +44 -35
  127. package/lib/logger.js +1 -1
  128. package/lib/mcinstall/index.js +20 -13
  129. package/lib/notification-proxy/index.js +18 -17
  130. package/lib/plist-service/index.js +13 -14
  131. package/lib/plist-service/transformer/plist-service-decoder.js +6 -7
  132. package/lib/plist-service/transformer/plist-service-encoder.js +6 -7
  133. package/lib/services.js +45 -29
  134. package/lib/simulatelocation/index.js +4 -5
  135. package/lib/ssl-helper.js +6 -7
  136. package/lib/syslog/index.js +7 -8
  137. package/lib/syslog/transformer/syslog-decoder.js +11 -10
  138. package/lib/testmanagerd/index.js +10 -7
  139. package/lib/usbmux/index.js +52 -41
  140. package/lib/usbmux/transformer/usbmux-decoder.js +8 -10
  141. package/lib/usbmux/transformer/usbmux-encoder.js +10 -8
  142. package/lib/util/transformer/length-based-splitter.js +62 -24
  143. package/lib/util/transformer/stream-logger.js +14 -11
  144. package/lib/util/uuid/parse.ts +2 -2
  145. package/lib/util/uuid/stringify.ts +1 -1
  146. package/lib/util/uuid/validate.ts +2 -1
  147. package/lib/utilities.js +39 -28
  148. package/lib/webinspector/index.js +59 -46
  149. package/lib/webinspector/transformer/webinspector-decoder.js +22 -11
  150. package/lib/webinspector/transformer/webinspector-encoder.js +6 -8
  151. package/lib/xctest.js +284 -245
  152. package/package.json +4 -2
package/lib/xctest.js CHANGED
@@ -1,14 +1,19 @@
1
- import { startHouseArrestService, startTestmanagerdService, startInstallationProxyService, startInstrumentService } from './services';
2
- import { INSTRUMENT_CHANNEL } from './instrument';
3
- import { DTXMessageAuxBuffer } from './instrument/headers';
4
- import { NSUUID, XCTestConfiguration } from './instrument/transformer/nskeyed';
5
- import { TESTMANAGERD_CHANNEL } from './testmanagerd';
6
- import { util } from '@appium/support';
7
- import { getOSVersion } from './utilities';
8
- import { log } from './logger';
1
+ import {
2
+ startHouseArrestService,
3
+ startTestmanagerdService,
4
+ startInstallationProxyService,
5
+ startInstrumentService,
6
+ } from './services';
7
+ import {INSTRUMENT_CHANNEL} from './instrument';
8
+ import {DTXMessageAuxBuffer} from './instrument/headers';
9
+ import {NSUUID, XCTestConfiguration} from './instrument/transformer/nskeyed';
10
+ import {TESTMANAGERD_CHANNEL} from './testmanagerd';
11
+ import {util} from '@appium/support';
12
+ import {getOSVersion} from './utilities';
13
+ import {log} from './logger';
9
14
  import B from 'bluebird';
10
15
 
11
- const { DAEMON_CONNECTION_INTERFACE } = TESTMANAGERD_CHANNEL;
16
+ const {DAEMON_CONNECTION_INTERFACE} = TESTMANAGERD_CHANNEL;
12
17
  const XCTEST_CONFIGURATION_EXTENSION = '.xctestconfiguration';
13
18
  const TMP_FOLDER_PREFIX = '/tmp';
14
19
  const XCTEST_EXECUTABLE_SUFFIX = '-Runner';
@@ -18,7 +23,7 @@ const MAJOR_IOS_VERSION_12 = 12;
18
23
  //This is not related with which xcode user installed but only a marker to use inside device
19
24
  const XCODE_BUILD_PATH = '/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild';
20
25
  const XCODE_VERSION = 29;
21
- const MAGIC_CHANNEL = 0xFFFFFFFF;
26
+ const MAGIC_CHANNEL = 0xffffffff;
22
27
  /**
23
28
  * @typedef {Object} XCTestConfigurationProperties
24
29
  * @property {string?} productModuleName
@@ -38,259 +43,293 @@ const MAGIC_CHANNEL = 0xFFFFFFFF;
38
43
  * This class simulates the procedure which xcode uses to invoke xctests.
39
44
  */
40
45
  class Xctest {
41
- /** @type {import('./testmanagerd').TestmanagerdService|undefined} */
42
- _initialControlSession;
46
+ /** @type {import('./testmanagerd').TestmanagerdService|undefined} */
47
+ _initialControlSession;
43
48
 
44
- /** @type {import('./testmanagerd').TestmanagerdService|undefined} */
45
- _execTestPlanSession;
49
+ /** @type {import('./testmanagerd').TestmanagerdService|undefined} */
50
+ _execTestPlanSession;
46
51
 
47
- /**
48
- * @param {string} udid Device udid.
49
- * @param {string} xctestBundleId Bundle Id of xctest app on device. The app must be installed on device.
50
- * @param {string?} targetBundleId test target bundle id.
51
- * @param {Partial<XctestOption>} opts addition options to specific XCTestConfiguration and app launch env
52
- */
53
- constructor(udid, xctestBundleId, targetBundleId = null, opts = {}) {
54
- this.udid = udid;
55
- this.running = false;
56
- this._executing = false;
57
- this.xctestBundleId = xctestBundleId;
58
- this.targetBundleId = targetBundleId;
59
- this._conf = opts?.conf || {};
60
- this._env = opts?.env || {};
61
- }
52
+ /**
53
+ * @param {string} udid Device udid.
54
+ * @param {string} xctestBundleId Bundle Id of xctest app on device. The app must be installed on device.
55
+ * @param {string?} targetBundleId test target bundle id.
56
+ * @param {Partial<XctestOption>} opts addition options to specific XCTestConfiguration and app launch env
57
+ */
58
+ constructor(udid, xctestBundleId, targetBundleId = null, opts = {}) {
59
+ this.udid = udid;
60
+ this.running = false;
61
+ this._executing = false;
62
+ this.xctestBundleId = xctestBundleId;
63
+ this.targetBundleId = targetBundleId;
64
+ this._conf = opts?.conf || {};
65
+ this._env = opts?.env || {};
66
+ }
62
67
 
63
- /**
64
- * @param {number} majorVersion first part of iOS version 9/10/11/12/13/14/15/16
65
- * @param {string} sessionIdentifier uuid with format: 00000000-0000-0000-0000-000000000000
66
- */
67
- async _launchAppRunner(majorVersion, sessionIdentifier) {
68
- const { PROCESS_CONTROL } = INSTRUMENT_CHANNEL;
69
- const installation = await startInstallationProxyService(this.udid);
70
- let lookupResult;
71
- try {
72
- lookupResult = await installation.lookupApplications({ bundleIds: [this.xctestBundleId] });
73
- } finally {
74
- installation.close();
75
- }
76
- const appInfo = lookupResult[this.xctestBundleId];
77
- if (!appInfo) {
78
- throw new Error(`${this.xctestBundleId} not found on device ${this.udid}`);
79
- }
80
- const signerIdentifier = appInfo.SignerIdentity;
81
- log.info(`SignerIdentifier: ${signerIdentifier}`);
82
- const appContainer = appInfo.Container;
83
- const execName = appInfo.CFBundleExecutable;
84
- if (!execName.endsWith(XCTEST_EXECUTABLE_SUFFIX)) {
85
- throw new Error(`Invalid CFBundleExecutable ${execName} from ${this.xctestBundleId}, is this bundle a valid xctest app?`);
86
- }
87
- const targetName = execName.substr(0, execName.indexOf(XCTEST_EXECUTABLE_SUFFIX));
88
- const xctestPath = `${TMP_FOLDER_PREFIX}/${targetName}-${sessionIdentifier.toUpperCase()}${XCTEST_CONFIGURATION_EXTENSION}`;
89
- // @ts-ignore This works
90
- const xctestConfiguration = new XCTestConfiguration({
91
- ...this._conf,
92
- // properties below should not be override
93
- testBundleURL: `file://${appInfo.Path}/PlugIns/${targetName}.xctest`,
94
- sessionIdentifier,
95
- targetApplicationBundleID: this.targetBundleId,
96
- });
97
- await this._writeConfigurationToDevice(xctestConfiguration, xctestPath);
98
- this._instrumentService = await startInstrumentService(this.udid);
99
- this._instrumentService.registerLifecycleCallback('close', this.stop.bind(this));
100
- await this._instrumentService.callChannel(PROCESS_CONTROL, 'processIdentifierForBundleIdentifier:', this.xctestBundleId);
101
- const appPath = appInfo.Path;
102
- const xctestConfigurationPath = appContainer + xctestPath;
103
- const appEnv = {
104
- CA_ASSERT_MAIN_THREAD_TRANSACTIONS: '0',
105
- CA_DEBUG_TRANSACTIONS: '0',
106
- DYLD_FRAMEWORK_PATH: `${appPath}/Frameworks:`,
107
- DYLD_LIBRARY_PATH: `${appPath}/Frameworks`,
108
- NSUnbufferedIO: 'YES',
109
- SQLITE_ENABLE_THREAD_ASSERTIONS: '1',
110
- WDA_PRODUCT_BUNDLE_IDENTIFIER: '',
111
- XCTestConfigurationFilePath: xctestConfigurationPath,
112
- XCODE_DBG_XPC_EXCLUSIONS: 'com.apple.dt.xctestSymbolicator',
113
- MJPEG_SERVER_PORT: '',
114
- USE_PORT: '',
115
- // %p means pid
116
- LLVM_PROFILE_FILE: `${appContainer}/tmp/%p.profraw`,
117
- ...this._env
118
- };
119
- if (majorVersion >= MAJOR_IOS_VERSION_11) {
120
- appEnv.DYLD_INSERT_LIBRARIES = '/Developer/usr/lib/libMainThreadChecker.dylib';
121
- appEnv.OS_ACTIVITY_DT_MODE = 'YES';
122
- }
123
- const appArgs = [
124
- '-NSTreatUnknownArgumentsAsOpen', 'NO',
125
- '-ApplePersistenceIgnoreState', 'YES'
126
- ];
127
- const appOptions = { StartSuspendedKey: false };
128
- if (majorVersion >= MAJOR_IOS_VERSION_12) {
129
- appOptions.ActivateSuspended = true;
130
- appOptions.__ActivateSuspended = true;
131
- }
132
- const launchResult = await this._instrumentService.callChannel(PROCESS_CONTROL,
133
- 'launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:',
134
- appPath, this.xctestBundleId, appEnv, appArgs, appOptions);
135
- const pid = launchResult.selector;
136
- if (typeof pid !== 'number') {
137
- throw new Error(`Failed on launching ${this.xctestBundleId}: ${launchResult}`);
138
- }
139
- log.info(`Pid of launched ${this.xctestBundleId}: ${pid}`);
140
- const msg = new DTXMessageAuxBuffer();
141
- msg.appendObject(pid);
142
- await this._instrumentService.callChannel(PROCESS_CONTROL, 'startObservingPid:', msg);
143
- return pid;
68
+ /**
69
+ * @param {number} majorVersion first part of iOS version 9/10/11/12/13/14/15/16
70
+ * @param {string} sessionIdentifier uuid with format: 00000000-0000-0000-0000-000000000000
71
+ */
72
+ async _launchAppRunner(majorVersion, sessionIdentifier) {
73
+ const {PROCESS_CONTROL} = INSTRUMENT_CHANNEL;
74
+ const installation = await startInstallationProxyService(this.udid);
75
+ let lookupResult;
76
+ try {
77
+ lookupResult = await installation.lookupApplications({bundleIds: [this.xctestBundleId]});
78
+ } finally {
79
+ installation.close();
144
80
  }
145
-
146
- /**
147
- * @param {XCTestConfiguration} xctestConfiguration plist contains
148
- * @param {string} xctestPath where xctestConfiguration should be place in app sandbox.
149
- */
150
- async _writeConfigurationToDevice(xctestConfiguration, xctestPath) {
151
- const xctestContent = xctestConfiguration.getBytes();
152
- const houseArrestService = await startHouseArrestService(this.udid);
153
- let vendContainer;
154
- let stream;
155
- try {
156
- vendContainer = await houseArrestService.vendContainer(this.xctestBundleId);
157
- const list = await vendContainer.listDirectory(TMP_FOLDER_PREFIX);
158
- for (const file of list) {
159
- if (file.endsWith(XCTEST_CONFIGURATION_EXTENSION)) {
160
- const fullPath = `${TMP_FOLDER_PREFIX}/${file}`;
161
- log.debug(`removing ${fullPath}`);
162
- await vendContainer.deleteDirectory(fullPath);
163
- }
164
- }
165
- stream = await vendContainer.createWriteStream(xctestPath, {});
166
- await new B((resolve, reject) => {
167
- stream.write(xctestContent, resolve);
168
- stream.on('error', reject);
169
- });
170
- } finally {
171
- stream?.end();
172
- vendContainer?.close();
173
- houseArrestService.close();
174
- }
81
+ const appInfo = lookupResult[this.xctestBundleId];
82
+ if (!appInfo) {
83
+ throw new Error(`${this.xctestBundleId} not found on device ${this.udid}`);
84
+ }
85
+ const signerIdentifier = appInfo.SignerIdentity;
86
+ log.info(`SignerIdentifier: ${signerIdentifier}`);
87
+ const appContainer = appInfo.Container;
88
+ const execName = appInfo.CFBundleExecutable;
89
+ if (!execName.endsWith(XCTEST_EXECUTABLE_SUFFIX)) {
90
+ throw new Error(
91
+ `Invalid CFBundleExecutable ${execName} from ${this.xctestBundleId}, is this bundle a valid xctest app?`,
92
+ );
93
+ }
94
+ const targetName = execName.substr(0, execName.indexOf(XCTEST_EXECUTABLE_SUFFIX));
95
+ const xctestPath = `${TMP_FOLDER_PREFIX}/${targetName}-${sessionIdentifier.toUpperCase()}${XCTEST_CONFIGURATION_EXTENSION}`;
96
+ // @ts-ignore This works
97
+ const xctestConfiguration = new XCTestConfiguration({
98
+ ...this._conf,
99
+ // properties below should not be override
100
+ testBundleURL: `file://${appInfo.Path}/PlugIns/${targetName}.xctest`,
101
+ sessionIdentifier,
102
+ targetApplicationBundleID: this.targetBundleId,
103
+ });
104
+ await this._writeConfigurationToDevice(xctestConfiguration, xctestPath);
105
+ this._instrumentService = await startInstrumentService(this.udid);
106
+ this._instrumentService.registerLifecycleCallback('close', this.stop.bind(this));
107
+ await this._instrumentService.callChannel(
108
+ PROCESS_CONTROL,
109
+ 'processIdentifierForBundleIdentifier:',
110
+ this.xctestBundleId,
111
+ );
112
+ const appPath = appInfo.Path;
113
+ const xctestConfigurationPath = appContainer + xctestPath;
114
+ const appEnv = {
115
+ CA_ASSERT_MAIN_THREAD_TRANSACTIONS: '0',
116
+ CA_DEBUG_TRANSACTIONS: '0',
117
+ DYLD_FRAMEWORK_PATH: `${appPath}/Frameworks:`,
118
+ DYLD_LIBRARY_PATH: `${appPath}/Frameworks`,
119
+ NSUnbufferedIO: 'YES',
120
+ SQLITE_ENABLE_THREAD_ASSERTIONS: '1',
121
+ WDA_PRODUCT_BUNDLE_IDENTIFIER: '',
122
+ XCTestConfigurationFilePath: xctestConfigurationPath,
123
+ XCODE_DBG_XPC_EXCLUSIONS: 'com.apple.dt.xctestSymbolicator',
124
+ MJPEG_SERVER_PORT: '',
125
+ USE_PORT: '',
126
+ // %p means pid
127
+ LLVM_PROFILE_FILE: `${appContainer}/tmp/%p.profraw`,
128
+ ...this._env,
129
+ };
130
+ if (majorVersion >= MAJOR_IOS_VERSION_11) {
131
+ appEnv.DYLD_INSERT_LIBRARIES = '/Developer/usr/lib/libMainThreadChecker.dylib';
132
+ appEnv.OS_ACTIVITY_DT_MODE = 'YES';
175
133
  }
134
+ const appArgs = ['-NSTreatUnknownArgumentsAsOpen', 'NO', '-ApplePersistenceIgnoreState', 'YES'];
135
+ const appOptions = {StartSuspendedKey: false};
136
+ if (majorVersion >= MAJOR_IOS_VERSION_12) {
137
+ appOptions.ActivateSuspended = true;
138
+ appOptions.__ActivateSuspended = true;
139
+ }
140
+ const launchResult = await this._instrumentService.callChannel(
141
+ PROCESS_CONTROL,
142
+ 'launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:',
143
+ appPath,
144
+ this.xctestBundleId,
145
+ appEnv,
146
+ appArgs,
147
+ appOptions,
148
+ );
149
+ const pid = launchResult.selector;
150
+ if (typeof pid !== 'number') {
151
+ throw new Error(`Failed on launching ${this.xctestBundleId}: ${launchResult}`);
152
+ }
153
+ log.info(`Pid of launched ${this.xctestBundleId}: ${pid}`);
154
+ const msg = new DTXMessageAuxBuffer();
155
+ msg.appendObject(pid);
156
+ await this._instrumentService.callChannel(PROCESS_CONTROL, 'startObservingPid:', msg);
157
+ return pid;
158
+ }
176
159
 
177
- async _startInitialSession(majorVersion) {
178
- this._initialControlSession = await startTestmanagerdService(this.udid);
179
- this._initialControlSession.registerLifecycleCallback('close', this.stop.bind(this));
180
- if (majorVersion < MAJOR_IOS_VERSION_11) {
181
- return;
160
+ /**
161
+ * @param {XCTestConfiguration} xctestConfiguration plist contains
162
+ * @param {string} xctestPath where xctestConfiguration should be place in app sandbox.
163
+ */
164
+ async _writeConfigurationToDevice(xctestConfiguration, xctestPath) {
165
+ const xctestContent = xctestConfiguration.getBytes();
166
+ const houseArrestService = await startHouseArrestService(this.udid);
167
+ let vendContainer;
168
+ let stream;
169
+ try {
170
+ vendContainer = await houseArrestService.vendContainer(this.xctestBundleId);
171
+ const list = await vendContainer.listDirectory(TMP_FOLDER_PREFIX);
172
+ for (const file of list) {
173
+ if (file.endsWith(XCTEST_CONFIGURATION_EXTENSION)) {
174
+ const fullPath = `${TMP_FOLDER_PREFIX}/${file}`;
175
+ log.debug(`removing ${fullPath}`);
176
+ await vendContainer.deleteDirectory(fullPath);
182
177
  }
183
- const msg = new DTXMessageAuxBuffer();
184
- msg.appendObject(XCODE_VERSION);
185
- await this._initialControlSession.callChannel(DAEMON_CONNECTION_INTERFACE,
186
- '_IDE_initiateControlSessionWithProtocolVersion:', msg);
178
+ }
179
+ stream = await vendContainer.createWriteStream(xctestPath, {});
180
+ await new B((resolve, reject) => {
181
+ stream.write(xctestContent, resolve);
182
+ stream.on('error', reject);
183
+ });
184
+ } finally {
185
+ stream?.end();
186
+ vendContainer?.close();
187
+ houseArrestService.close();
187
188
  }
189
+ }
188
190
 
189
- async _startExecSession(sessionIdentifier) {
190
- this._execTestPlanSession = await startTestmanagerdService(this.udid);
191
- this._execTestPlanSession.registerLifecycleCallback('close', this.stop.bind(this));
192
- const startExecuting = () => {
193
- if (this._executing) {
194
- return;
195
- }
196
- this._executing = true;
197
- const msg = new DTXMessageAuxBuffer();
198
- msg.appendObject(XCODE_VERSION);
199
- // @ts-ignore _execTestPlanSession must be defined here
200
- this._execTestPlanSession._callChannel(false, MAGIC_CHANNEL, '_IDE_startExecutingTestPlanWithProtocolVersion:', msg);
201
- };
202
- const showLogMessage = (message) => {
203
- if (message.auxiliaries.join('').includes('Received test runner ready reply with error: (null')) {
204
- log.info('Test runner ready');
205
- //A magic thing is that if not using a delay this would fail on iPhone7 iOS 13.6.1
206
- setTimeout(() => startExecuting(), 1000);
207
- }
208
- };
209
- this._execTestPlanSession.registerSelectorCallback('_XCT_testBundleReadyWithProtocolVersion:minimumVersion:', startExecuting);
210
- this._execTestPlanSession.registerSelectorCallback('_XCT_logDebugMessage:', showLogMessage);
211
- const msg = new DTXMessageAuxBuffer();
212
- msg.appendObject(new NSUUID(sessionIdentifier));
213
- msg.appendObject(`${sessionIdentifier}-746F-006D726964646C79`);
214
- msg.appendObject(XCODE_BUILD_PATH);
215
- msg.appendObject(XCODE_VERSION);
216
- await this._execTestPlanSession.callChannel(DAEMON_CONNECTION_INTERFACE,
217
- '_IDE_initiateSessionWithIdentifier:forClient:atPath:protocolVersion:', msg);
191
+ async _startInitialSession(majorVersion) {
192
+ this._initialControlSession = await startTestmanagerdService(this.udid);
193
+ this._initialControlSession.registerLifecycleCallback('close', this.stop.bind(this));
194
+ if (majorVersion < MAJOR_IOS_VERSION_11) {
195
+ return;
218
196
  }
197
+ const msg = new DTXMessageAuxBuffer();
198
+ msg.appendObject(XCODE_VERSION);
199
+ await this._initialControlSession.callChannel(
200
+ DAEMON_CONNECTION_INTERFACE,
201
+ '_IDE_initiateControlSessionWithProtocolVersion:',
202
+ msg,
203
+ );
204
+ }
219
205
 
220
- async _notifyTestProcessId(pid, majorVersion) {
221
- const msg = new DTXMessageAuxBuffer();
222
- msg.appendObject(pid);
223
- if (majorVersion >= MAJOR_IOS_VERSION_12) {
224
- // @ts-ignore _initialControlSession must be defined here
225
- return await this._initialControlSession.callChannel(DAEMON_CONNECTION_INTERFACE,
226
- '_IDE_authorizeTestSessionWithProcessID:', msg);
227
- }
228
- if (majorVersion <= MAJOR_IOS_VERSION_9) {
229
- // @ts-ignore _initialControlSession must be defined here
230
- return await this._initialControlSession.callChannel(DAEMON_CONNECTION_INTERFACE,
231
- '_IDE_initiateControlSessionForTestProcessID:', msg);
232
- }
233
- msg.appendObject(XCODE_VERSION);
234
- // @ts-ignore _initialControlSession must be defined here
235
- return await this._initialControlSession.callChannel(DAEMON_CONNECTION_INTERFACE,
236
- '_IDE_initiateControlSessionForTestProcessID:protocolVersion:', msg);
206
+ async _startExecSession(sessionIdentifier) {
207
+ this._execTestPlanSession = await startTestmanagerdService(this.udid);
208
+ this._execTestPlanSession.registerLifecycleCallback('close', this.stop.bind(this));
209
+ const startExecuting = () => {
210
+ if (this._executing) {
211
+ return;
212
+ }
213
+ this._executing = true;
214
+ const msg = new DTXMessageAuxBuffer();
215
+ msg.appendObject(XCODE_VERSION);
216
+ // @ts-ignore _execTestPlanSession must be defined here
217
+ this._execTestPlanSession._callChannel(
218
+ false,
219
+ MAGIC_CHANNEL,
220
+ '_IDE_startExecutingTestPlanWithProtocolVersion:',
221
+ msg,
222
+ );
223
+ };
224
+ const showLogMessage = (message) => {
225
+ if (
226
+ message.auxiliaries.join('').includes('Received test runner ready reply with error: (null')
227
+ ) {
228
+ log.info('Test runner ready');
229
+ //A magic thing is that if not using a delay this would fail on iPhone7 iOS 13.6.1
230
+ setTimeout(() => startExecuting(), 1000);
231
+ }
232
+ };
233
+ this._execTestPlanSession.registerSelectorCallback(
234
+ '_XCT_testBundleReadyWithProtocolVersion:minimumVersion:',
235
+ startExecuting,
236
+ );
237
+ this._execTestPlanSession.registerSelectorCallback('_XCT_logDebugMessage:', showLogMessage);
238
+ const msg = new DTXMessageAuxBuffer();
239
+ msg.appendObject(new NSUUID(sessionIdentifier));
240
+ msg.appendObject(`${sessionIdentifier}-746F-006D726964646C79`);
241
+ msg.appendObject(XCODE_BUILD_PATH);
242
+ msg.appendObject(XCODE_VERSION);
243
+ await this._execTestPlanSession.callChannel(
244
+ DAEMON_CONNECTION_INTERFACE,
245
+ '_IDE_initiateSessionWithIdentifier:forClient:atPath:protocolVersion:',
246
+ msg,
247
+ );
248
+ }
249
+
250
+ async _notifyTestProcessId(pid, majorVersion) {
251
+ const msg = new DTXMessageAuxBuffer();
252
+ msg.appendObject(pid);
253
+ if (majorVersion >= MAJOR_IOS_VERSION_12) {
254
+ // @ts-ignore _initialControlSession must be defined here
255
+ return await this._initialControlSession.callChannel(
256
+ DAEMON_CONNECTION_INTERFACE,
257
+ '_IDE_authorizeTestSessionWithProcessID:',
258
+ msg,
259
+ );
237
260
  }
261
+ if (majorVersion <= MAJOR_IOS_VERSION_9) {
262
+ // @ts-ignore _initialControlSession must be defined here
263
+ return await this._initialControlSession.callChannel(
264
+ DAEMON_CONNECTION_INTERFACE,
265
+ '_IDE_initiateControlSessionForTestProcessID:',
266
+ msg,
267
+ );
268
+ }
269
+ msg.appendObject(XCODE_VERSION);
270
+ // @ts-ignore _initialControlSession must be defined here
271
+ return await this._initialControlSession.callChannel(
272
+ DAEMON_CONNECTION_INTERFACE,
273
+ '_IDE_initiateControlSessionForTestProcessID:protocolVersion:',
274
+ msg,
275
+ );
276
+ }
238
277
 
239
- /**
240
- * Start xctest process. If this method has been called before and the `stop()` method has not been called,
241
- * calling this again would return directly.
242
- * @throws If xctest bundle id invalid or not installed.
243
- */
244
- async start() {
245
- if (this.running) {
246
- const targetMessage = this.targetBundleId ? `(targeting ${this.targetBundleId})` : '';
247
- const message = `Xctest for ${this.xctestBundleId}${targetMessage} on device ${this.udid} is already running!`;
248
- log.info(`${message} Doing nothing here`);
249
- return;
250
- }
251
- this.running = true;
252
- try {
253
- const productVersion = await getOSVersion(this.udid);
254
- const majorVersion = parseInt(productVersion.split('.')[0], 10);
255
- const sessionIdentifier = util.uuidV4();
256
- //first connection
257
- await this._startInitialSession(majorVersion);
278
+ /**
279
+ * Start xctest process. If this method has been called before and the `stop()` method has not been called,
280
+ * calling this again would return directly.
281
+ * @throws If xctest bundle id invalid or not installed.
282
+ */
283
+ async start() {
284
+ if (this.running) {
285
+ const targetMessage = this.targetBundleId ? `(targeting ${this.targetBundleId})` : '';
286
+ const message = `Xctest for ${this.xctestBundleId}${targetMessage} on device ${this.udid} is already running!`;
287
+ log.info(`${message} Doing nothing here`);
288
+ return;
289
+ }
290
+ this.running = true;
291
+ try {
292
+ const productVersion = await getOSVersion(this.udid);
293
+ const majorVersion = parseInt(productVersion.split('.')[0], 10);
294
+ const sessionIdentifier = util.uuidV4();
295
+ //first connection
296
+ await this._startInitialSession(majorVersion);
258
297
 
259
- //second connection
260
- await this._startExecSession(sessionIdentifier);
298
+ //second connection
299
+ await this._startExecSession(sessionIdentifier);
261
300
 
262
- const pid = await this._launchAppRunner(majorVersion, sessionIdentifier);
263
- await this._notifyTestProcessId(pid, majorVersion);
264
- } catch (e) {
265
- this.stop();
266
- throw e;
267
- }
301
+ const pid = await this._launchAppRunner(majorVersion, sessionIdentifier);
302
+ await this._notifyTestProcessId(pid, majorVersion);
303
+ } catch (e) {
304
+ this.stop();
305
+ throw e;
268
306
  }
307
+ }
269
308
 
270
- /**
271
- * Stop xctest process.
272
- */
273
- stop() {
274
- if (!this.running) {
275
- // not started or already called `stop()`
276
- return;
277
- }
278
- this.running = false;
279
- this._instrumentService?.close();
280
- this._instrumentService?.dispose();
281
- this._instrumentService = undefined;
282
- this._execTestPlanSession?.close();
283
- this._execTestPlanSession?.dispose();
284
- this._execTestPlanSession = undefined;
285
- this._initialControlSession?.close();
286
- this._initialControlSession?.dispose();
287
- this._initialControlSession = undefined;
288
- this._executing = false;
289
- const targetMessage = this.targetBundleId ? `(targeting ${this.targetBundleId})` : '';
290
- const message = `Xctest for ${this.xctestBundleId}${targetMessage} on device ${this.udid} has stopped!`;
291
- log.debug(message);
309
+ /**
310
+ * Stop xctest process.
311
+ */
312
+ stop() {
313
+ if (!this.running) {
314
+ // not started or already called `stop()`
315
+ return;
292
316
  }
317
+ this.running = false;
318
+ this._instrumentService?.close();
319
+ this._instrumentService?.dispose();
320
+ this._instrumentService = undefined;
321
+ this._execTestPlanSession?.close();
322
+ this._execTestPlanSession?.dispose();
323
+ this._execTestPlanSession = undefined;
324
+ this._initialControlSession?.close();
325
+ this._initialControlSession?.dispose();
326
+ this._initialControlSession = undefined;
327
+ this._executing = false;
328
+ const targetMessage = this.targetBundleId ? `(targeting ${this.targetBundleId})` : '';
329
+ const message = `Xctest for ${this.xctestBundleId}${targetMessage} on device ${this.udid} has stopped!`;
330
+ log.debug(message);
331
+ }
293
332
  }
294
333
 
295
- export { Xctest };
334
+ export {Xctest};
296
335
  export default Xctest;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "appium"
6
6
  ],
7
- "version": "3.1.9",
7
+ "version": "3.1.11",
8
8
  "author": "Appium Contributors",
9
9
  "license": "Apache-2.0",
10
10
  "repository": {
@@ -46,6 +46,8 @@
46
46
  "clean": "npm run build -- --clean",
47
47
  "lint": "eslint .",
48
48
  "lint:fix": "npm run lint -- --fix",
49
+ "format": "prettier -w ./lib ./test",
50
+ "format:check": "prettier --check ./lib ./test",
49
51
  "prepare": "npm run build",
50
52
  "test": "mocha --exit --timeout 1m \"./test/**/*-specs.js\""
51
53
  },
@@ -71,6 +73,6 @@
71
73
  "prettier": "^3.0.0",
72
74
  "semantic-release": "^25.0.2",
73
75
  "ts-node": "^10.9.1",
74
- "typescript": "^5.4.2"
76
+ "typescript": "^6.0.3"
75
77
  }
76
78
  }