appium-xcuitest-driver 10.3.0 → 10.4.1
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 +12 -0
- package/build/lib/commands/active-app-info.d.ts +9 -0
- package/build/lib/commands/active-app-info.d.ts.map +1 -0
- package/build/lib/commands/active-app-info.js +14 -0
- package/build/lib/commands/active-app-info.js.map +1 -0
- package/build/lib/commands/alert.d.ts +42 -45
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +66 -62
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +150 -153
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +300 -286
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/app-strings.d.ts +14 -17
- package/build/lib/commands/app-strings.d.ts.map +1 -1
- package/build/lib/commands/app-strings.js +23 -24
- package/build/lib/commands/app-strings.js.map +1 -1
- package/build/lib/commands/appearance.d.ts +19 -22
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +56 -56
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/audit.d.ts +22 -17
- package/build/lib/commands/audit.d.ts.map +1 -1
- package/build/lib/commands/audit.js +17 -18
- package/build/lib/commands/audit.js.map +1 -1
- package/build/lib/commands/battery.d.ts +11 -14
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +36 -37
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/biometric.d.ts +30 -33
- package/build/lib/commands/biometric.d.ts.map +1 -1
- package/build/lib/commands/biometric.js +42 -41
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/certificate.d.ts +48 -45
- package/build/lib/commands/certificate.d.ts.map +1 -1
- package/build/lib/commands/certificate.js +218 -205
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/clipboard.d.ts +19 -22
- package/build/lib/commands/clipboard.d.ts.map +1 -1
- package/build/lib/commands/clipboard.js +30 -30
- package/build/lib/commands/clipboard.js.map +1 -1
- package/build/lib/commands/condition.d.ts +49 -26
- package/build/lib/commands/condition.d.ts.map +1 -1
- package/build/lib/commands/condition.js +87 -86
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/content-size.d.ts +26 -29
- package/build/lib/commands/content-size.d.ts.map +1 -1
- package/build/lib/commands/content-size.js +36 -36
- package/build/lib/commands/content-size.js.map +1 -1
- package/build/lib/commands/context.d.ts +161 -108
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +530 -517
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/deviceInfo.d.ts +9 -12
- package/build/lib/commands/deviceInfo.d.ts.map +1 -1
- package/build/lib/commands/deviceInfo.js +17 -18
- package/build/lib/commands/deviceInfo.js.map +1 -1
- package/build/lib/commands/element.d.ts +102 -105
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +337 -323
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +24 -19
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +63 -62
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-movement.d.ts +77 -80
- package/build/lib/commands/file-movement.d.ts.map +1 -1
- package/build/lib/commands/file-movement.js +130 -124
- package/build/lib/commands/file-movement.js.map +1 -1
- package/build/lib/commands/find.d.ts +18 -21
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +158 -156
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +124 -116
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +248 -232
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts +43 -46
- package/build/lib/commands/geolocation.d.ts.map +1 -1
- package/build/lib/commands/geolocation.js +10 -11
- package/build/lib/commands/geolocation.js.map +1 -1
- package/build/lib/commands/gesture.d.ts +273 -276
- package/build/lib/commands/gesture.d.ts.map +1 -1
- package/build/lib/commands/gesture.js +506 -492
- package/build/lib/commands/gesture.js.map +1 -1
- package/build/lib/commands/increase-contrast.d.ts +20 -23
- package/build/lib/commands/increase-contrast.d.ts.map +1 -1
- package/build/lib/commands/increase-contrast.js +30 -30
- package/build/lib/commands/increase-contrast.js.map +1 -1
- package/build/lib/commands/iohid.d.ts +1370 -1373
- package/build/lib/commands/iohid.d.ts.map +1 -1
- package/build/lib/commands/iohid.js +30 -31
- package/build/lib/commands/iohid.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +29 -32
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +53 -51
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/keychains.d.ts +9 -12
- package/build/lib/commands/keychains.d.ts.map +1 -1
- package/build/lib/commands/keychains.js +13 -14
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.d.ts +16 -19
- package/build/lib/commands/localization.d.ts.map +1 -1
- package/build/lib/commands/localization.js +25 -26
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/location.d.ts +36 -39
- package/build/lib/commands/location.d.ts.map +1 -1
- package/build/lib/commands/location.js +99 -98
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/lock.d.ts +21 -24
- package/build/lib/commands/lock.d.ts.map +1 -1
- package/build/lib/commands/lock.js +39 -38
- package/build/lib/commands/lock.js.map +1 -1
- package/build/lib/commands/log.d.ts +43 -37
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +174 -171
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.d.ts +9 -12
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +37 -38
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/navigation.d.ts +30 -33
- package/build/lib/commands/navigation.d.ts.map +1 -1
- package/build/lib/commands/navigation.js +92 -92
- package/build/lib/commands/navigation.js.map +1 -1
- package/build/lib/commands/notifications.d.ts +26 -29
- package/build/lib/commands/notifications.d.ts.map +1 -1
- package/build/lib/commands/notifications.js +53 -53
- package/build/lib/commands/notifications.js.map +1 -1
- package/build/lib/commands/pasteboard.d.ts +21 -24
- package/build/lib/commands/pasteboard.d.ts.map +1 -1
- package/build/lib/commands/pasteboard.js +37 -37
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/pcap.d.ts +39 -26
- package/build/lib/commands/pcap.d.ts.map +1 -1
- package/build/lib/commands/pcap.js +81 -81
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/performance.d.ts +63 -44
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +105 -105
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +33 -36
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +66 -65
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/proxy-helper.d.ts +12 -15
- package/build/lib/commands/proxy-helper.d.ts.map +1 -1
- package/build/lib/commands/proxy-helper.js +53 -54
- package/build/lib/commands/proxy-helper.js.map +1 -1
- package/build/lib/commands/record-audio.d.ts +49 -29
- package/build/lib/commands/record-audio.d.ts.map +1 -1
- package/build/lib/commands/record-audio.js +100 -104
- package/build/lib/commands/record-audio.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +54 -18
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +127 -129
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/screenshots.d.ts +14 -17
- package/build/lib/commands/screenshots.d.ts.map +1 -1
- package/build/lib/commands/screenshots.js +108 -107
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/simctl.d.ts +11 -14
- package/build/lib/commands/simctl.d.ts.map +1 -1
- package/build/lib/commands/simctl.js +23 -26
- package/build/lib/commands/simctl.js.map +1 -1
- package/build/lib/commands/source.d.ts +14 -17
- package/build/lib/commands/source.d.ts.map +1 -1
- package/build/lib/commands/source.js +40 -43
- package/build/lib/commands/source.js.map +1 -1
- package/build/lib/commands/timeouts.d.ts +44 -33
- package/build/lib/commands/timeouts.d.ts.map +1 -1
- package/build/lib/commands/timeouts.js +65 -63
- package/build/lib/commands/timeouts.js.map +1 -1
- package/build/lib/commands/web.d.ts +275 -197
- package/build/lib/commands/web.d.ts.map +1 -1
- package/build/lib/commands/web.js +866 -785
- package/build/lib/commands/web.js.map +1 -1
- package/build/lib/commands/xctest-record-screen.d.ts +63 -66
- package/build/lib/commands/xctest-record-screen.d.ts.map +1 -1
- package/build/lib/commands/xctest-record-screen.js +103 -102
- package/build/lib/commands/xctest-record-screen.js.map +1 -1
- package/build/lib/commands/xctest.d.ts +55 -51
- package/build/lib/commands/xctest.d.ts.map +1 -1
- package/build/lib/commands/xctest.js +116 -117
- package/build/lib/commands/xctest.js.map +1 -1
- package/build/lib/driver.d.ts +277 -1597
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +318 -235
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +9 -0
- package/build/lib/execute-method-map.js.map +1 -1
- package/lib/commands/active-app-info.js +12 -0
- package/lib/commands/alert.js +68 -65
- package/lib/commands/app-management.js +308 -301
- package/lib/commands/app-strings.js +24 -26
- package/lib/commands/appearance.js +54 -56
- package/lib/commands/audit.js +18 -20
- package/lib/commands/battery.js +35 -37
- package/lib/commands/biometric.js +44 -46
- package/lib/commands/certificate.js +226 -215
- package/lib/commands/clipboard.js +30 -32
- package/lib/commands/condition.js +98 -100
- package/lib/commands/content-size.js +36 -38
- package/lib/commands/context.js +495 -490
- package/lib/commands/deviceInfo.js +19 -20
- package/lib/commands/element.js +367 -357
- package/lib/commands/execute.js +72 -72
- package/lib/commands/file-movement.js +132 -134
- package/lib/commands/find.js +160 -159
- package/lib/commands/general.js +238 -231
- package/lib/commands/geolocation.js +6 -14
- package/lib/commands/gesture.js +525 -515
- package/lib/commands/increase-contrast.js +30 -32
- package/lib/commands/iohid.js +32 -34
- package/lib/commands/keyboard.js +49 -51
- package/lib/commands/keychains.js +12 -14
- package/lib/commands/localization.js +24 -26
- package/lib/commands/location.js +102 -104
- package/lib/commands/lock.js +38 -38
- package/lib/commands/log.js +197 -198
- package/lib/commands/memory.js +40 -42
- package/lib/commands/navigation.js +96 -100
- package/lib/commands/notifications.js +57 -59
- package/lib/commands/pasteboard.js +37 -39
- package/lib/commands/pcap.js +84 -86
- package/lib/commands/performance.js +132 -133
- package/lib/commands/permissions.js +67 -69
- package/lib/commands/proxy-helper.js +60 -61
- package/lib/commands/record-audio.js +115 -120
- package/lib/commands/recordscreen.js +145 -149
- package/lib/commands/screenshots.js +116 -116
- package/lib/commands/simctl.js +25 -29
- package/lib/commands/source.js +42 -46
- package/lib/commands/timeouts.js +59 -63
- package/lib/commands/web.js +932 -859
- package/lib/commands/xctest-record-screen.js +103 -105
- package/lib/commands/xctest.js +134 -139
- package/lib/driver.js +286 -235
- package/lib/execute-method-map.ts +9 -0
- package/npm-shrinkwrap.json +8 -8
- package/package.json +1 -1
- package/build/lib/commands/activeAppInfo.d.ts +0 -12
- package/build/lib/commands/activeAppInfo.d.ts.map +0 -1
- package/build/lib/commands/activeAppInfo.js +0 -15
- package/build/lib/commands/activeAppInfo.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -96
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -100
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/cookies.d.ts +0 -15
- package/build/lib/cookies.d.ts.map +0 -1
- package/build/lib/cookies.js +0 -84
- package/build/lib/cookies.js.map +0 -1
- package/lib/commands/activeAppInfo.js +0 -14
- package/lib/commands/index.js +0 -95
- package/lib/cookies.js +0 -92
package/lib/commands/lock.js
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
import B from 'bluebird';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Lock the device (and optionally unlock the device after a certain amount of time)
|
|
5
|
+
*
|
|
6
|
+
* @param {number|string} [seconds] - the number of seconds after which to unlock the device. Set to `0` or leave empty to require manual unlock (do not automatically unlock).
|
|
7
|
+
* @defaultValue 0
|
|
8
|
+
* @this {XCUITestDriver}
|
|
9
|
+
*/
|
|
10
|
+
export async function lock(seconds) {
|
|
11
|
+
await this.proxyCommand('/wda/lock', 'POST');
|
|
12
|
+
if (isNaN(Number(seconds))) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const floatSeconds = parseFloat(String(seconds));
|
|
17
|
+
if (floatSeconds <= 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
await B.delay(floatSeconds * 1000);
|
|
22
|
+
await this.proxyCommand('/wda/unlock', 'POST');
|
|
23
|
+
}
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Unlock the device
|
|
27
|
+
*
|
|
28
|
+
* @this {XCUITestDriver}
|
|
29
|
+
*/
|
|
30
|
+
export async function unlock() {
|
|
31
|
+
await this.proxyCommand('/wda/unlock', 'POST');
|
|
32
|
+
}
|
|
21
33
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
await this.proxyCommand('/wda/unlock', 'POST');
|
|
32
|
-
},
|
|
33
|
-
/**
|
|
34
|
-
* Determine whether the device is locked
|
|
35
|
-
*
|
|
36
|
-
* @this {XCUITestDriver}
|
|
37
|
-
* @returns {Promise<boolean>} `true` if the device is locked, `false` otherwise
|
|
38
|
-
*/
|
|
39
|
-
async isLocked() {
|
|
40
|
-
return /** @type {boolean} */ (await this.proxyCommand('/wda/locked', 'GET'));
|
|
41
|
-
},
|
|
42
|
-
};
|
|
34
|
+
/**
|
|
35
|
+
* Determine whether the device is locked
|
|
36
|
+
*
|
|
37
|
+
* @this {XCUITestDriver}
|
|
38
|
+
* @returns {Promise<boolean>} `true` if the device is locked, `false` otherwise
|
|
39
|
+
*/
|
|
40
|
+
export async function isLocked() {
|
|
41
|
+
return /** @type {boolean} */ (await this.proxyCommand('/wda/locked', 'GET'));
|
|
42
|
+
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
package/lib/commands/log.js
CHANGED
|
@@ -22,19 +22,6 @@ const WEBSOCKET_ENDPOINT = (sessionId) =>
|
|
|
22
22
|
const COLOR_CODE_PATTERN = /\u001b\[(\d+(;\d+)*)?m/g; // eslint-disable-line no-control-regex
|
|
23
23
|
const GET_SERVER_LOGS_FEATURE = 'get_server_logs';
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
* @param {Object} x
|
|
28
|
-
* @returns {import('./types').LogEntry}
|
|
29
|
-
*/
|
|
30
|
-
function nativeLogEntryToSeleniumEntry (x) {
|
|
31
|
-
const msg = _.isEmpty(x.prefix) ? x.message : `[${x.prefix}] ${x.message}`;
|
|
32
|
-
return toLogEntry(
|
|
33
|
-
_.replace(msg, COLOR_CODE_PATTERN, ''),
|
|
34
|
-
/** @type {any} */ (x).timestamp ?? Date.now()
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
25
|
/**
|
|
39
26
|
* @type {import('@appium/types').LogDefRecord}
|
|
40
27
|
* @privateRemarks The return types for these getters should be specified
|
|
@@ -78,216 +65,215 @@ const LOG_NAMES_TO_CAPABILITY_NAMES_MAP = {
|
|
|
78
65
|
enablePerformanceLogging: 'enablePerformanceLogging',
|
|
79
66
|
};
|
|
80
67
|
|
|
81
|
-
export
|
|
82
|
-
supportedLogTypes: SUPPORTED_LOG_TYPES,
|
|
83
|
-
/**
|
|
84
|
-
*
|
|
85
|
-
* @param {XCUITestDriverLogTypes} logType
|
|
86
|
-
* @param {Partial<Record<XCUITestDriverLogTypes,{getLogs(): Promise<any>}>>} [logsContainer]
|
|
87
|
-
* @this {XCUITestDriver}
|
|
88
|
-
*/
|
|
89
|
-
async extractLogs(logType, logsContainer = {}) {
|
|
90
|
-
// make sure that we have logs at all
|
|
91
|
-
// otherwise it's not been initialized
|
|
92
|
-
if (_.isEmpty(logsContainer)) {
|
|
93
|
-
throw new Error('No logs currently available. Is the device/simulator started?');
|
|
94
|
-
}
|
|
68
|
+
export const supportedLogTypes = SUPPORTED_LOG_TYPES;
|
|
95
69
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @param {XCUITestDriverLogTypes} logType
|
|
73
|
+
* @param {Partial<Record<XCUITestDriverLogTypes,{getLogs(): Promise<any>}>>} [logsContainer]
|
|
74
|
+
* @this {XCUITestDriver}
|
|
75
|
+
*/
|
|
76
|
+
export async function extractLogs(logType, logsContainer = {}) {
|
|
77
|
+
// make sure that we have logs at all
|
|
78
|
+
// otherwise it's not been initialized
|
|
79
|
+
if (_.isEmpty(logsContainer)) {
|
|
80
|
+
throw new Error('No logs currently available. Is the device/simulator started?');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If logs captured successfully send response with data, else send error
|
|
84
|
+
const logObject = logsContainer[logType];
|
|
85
|
+
if (logObject) {
|
|
86
|
+
return await logObject.getLogs();
|
|
87
|
+
}
|
|
88
|
+
if (logType in LOG_NAMES_TO_CAPABILITY_NAMES_MAP) {
|
|
107
89
|
throw new Error(
|
|
108
|
-
|
|
90
|
+
`${logType} logs are not enabled. Make sure you've set a proper value ` +
|
|
91
|
+
`to the 'appium:${LOG_NAMES_TO_CAPABILITY_NAMES_MAP[logType]}' capability.`
|
|
109
92
|
);
|
|
110
|
-
}
|
|
93
|
+
}
|
|
94
|
+
throw new Error(
|
|
95
|
+
`No logs of type '${logType}' found. Supported log types are: ${_.keys(SUPPORTED_LOG_TYPES)}.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
111
98
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
99
|
+
/**
|
|
100
|
+
* @this {XCUITestDriver}
|
|
101
|
+
*/
|
|
102
|
+
export async function startLogCapture() {
|
|
103
|
+
this.logs = this.logs || {};
|
|
104
|
+
if (!_.isUndefined(this.logs.syslog) && this.logs.syslog.isCapturing) {
|
|
105
|
+
this.log.warn('Trying to start iOS log capture but it has already started!');
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
121
108
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
109
|
+
if (_.isUndefined(this.logs.syslog)) {
|
|
110
|
+
[this.logs.crashlog,] = assignBiDiLogListener.bind(this)(
|
|
111
|
+
new IOSCrashLog({
|
|
112
|
+
sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
|
|
113
|
+
udid: this.isRealDevice() ? this.opts.udid : undefined,
|
|
114
|
+
log: this.log,
|
|
115
|
+
}), {
|
|
116
|
+
type: 'crashlog',
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
[this.logs.syslog,] = assignBiDiLogListener.bind(this)(
|
|
120
|
+
this.isRealDevice()
|
|
121
|
+
? new IOSDeviceLog({
|
|
122
|
+
udid: this.opts.udid,
|
|
123
|
+
showLogs: this.opts.showIOSLog,
|
|
124
|
+
log: this.log,
|
|
125
|
+
})
|
|
126
|
+
: new IOSSimulatorLog({
|
|
125
127
|
sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
|
|
126
|
-
|
|
128
|
+
showLogs: this.opts.showIOSLog,
|
|
129
|
+
iosSimulatorLogsPredicate: this.opts.iosSimulatorLogsPredicate,
|
|
130
|
+
simulatorLogLevel: this.opts.simulatorLogLevel,
|
|
131
|
+
log: this.log,
|
|
132
|
+
iosSyslogFile: this.opts.iosSyslogFile
|
|
133
|
+
}),
|
|
134
|
+
{
|
|
135
|
+
type: 'syslog',
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
if (_.isBoolean(this.opts.showSafariConsoleLog)) {
|
|
139
|
+
[this.logs.safariConsole,] = assignBiDiLogListener.bind(this)(
|
|
140
|
+
new SafariConsoleLog({
|
|
141
|
+
showLogs: this.opts.showSafariConsoleLog,
|
|
127
142
|
log: this.log,
|
|
128
143
|
}), {
|
|
129
|
-
type: '
|
|
144
|
+
type: 'safariConsole',
|
|
130
145
|
}
|
|
131
146
|
);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
:
|
|
140
|
-
sim: /** @type {import('appium-ios-simulator').Simulator} */ (this.device),
|
|
141
|
-
showLogs: this.opts.showIOSLog,
|
|
142
|
-
iosSimulatorLogsPredicate: this.opts.iosSimulatorLogsPredicate,
|
|
143
|
-
simulatorLogLevel: this.opts.simulatorLogLevel,
|
|
144
|
-
log: this.log,
|
|
145
|
-
iosSyslogFile: this.opts.iosSyslogFile
|
|
146
|
-
}),
|
|
147
|
-
{
|
|
148
|
-
type: 'syslog',
|
|
147
|
+
}
|
|
148
|
+
if (_.isBoolean(this.opts.showSafariNetworkLog)) {
|
|
149
|
+
[this.logs.safariNetwork,] = assignBiDiLogListener.bind(this)(
|
|
150
|
+
new SafariNetworkLog({
|
|
151
|
+
showLogs: this.opts.showSafariNetworkLog,
|
|
152
|
+
log: this.log,
|
|
153
|
+
}), {
|
|
154
|
+
type: 'safariNetwork',
|
|
149
155
|
}
|
|
150
156
|
);
|
|
151
|
-
if (_.isBoolean(this.opts.showSafariConsoleLog)) {
|
|
152
|
-
[this.logs.safariConsole,] = assignBiDiLogListener.bind(this)(
|
|
153
|
-
new SafariConsoleLog({
|
|
154
|
-
showLogs: this.opts.showSafariConsoleLog,
|
|
155
|
-
log: this.log,
|
|
156
|
-
}), {
|
|
157
|
-
type: 'safariConsole',
|
|
158
|
-
}
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
if (_.isBoolean(this.opts.showSafariNetworkLog)) {
|
|
162
|
-
[this.logs.safariNetwork,] = assignBiDiLogListener.bind(this)(
|
|
163
|
-
new SafariNetworkLog({
|
|
164
|
-
showLogs: this.opts.showSafariNetworkLog,
|
|
165
|
-
log: this.log,
|
|
166
|
-
}), {
|
|
167
|
-
type: 'safariNetwork',
|
|
168
|
-
}
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
if (this.isFeatureEnabled(GET_SERVER_LOGS_FEATURE)) {
|
|
172
|
-
[, this._bidiServerLogListener] = assignBiDiLogListener.bind(this)(
|
|
173
|
-
this.log.unwrap(), {
|
|
174
|
-
type: 'server',
|
|
175
|
-
srcEventName: 'log',
|
|
176
|
-
entryTransformer: nativeLogEntryToSeleniumEntry,
|
|
177
|
-
}
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
157
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await this.logs.syslog?.startCapture();
|
|
188
|
-
didStartSyslog = true;
|
|
189
|
-
this.eventEmitter.emit('syslogStarted', this.logs.syslog);
|
|
190
|
-
} catch (err) {
|
|
191
|
-
this.log.debug(err.stack);
|
|
192
|
-
this.log.warn(`Continuing without capturing device logs: ${err.message}`);
|
|
158
|
+
if (this.isFeatureEnabled(GET_SERVER_LOGS_FEATURE)) {
|
|
159
|
+
[, this._bidiServerLogListener] = assignBiDiLogListener.bind(this)(
|
|
160
|
+
this.log.unwrap(), {
|
|
161
|
+
type: 'server',
|
|
162
|
+
srcEventName: 'log',
|
|
163
|
+
entryTransformer: nativeLogEntryToSeleniumEntry,
|
|
193
164
|
}
|
|
194
|
-
})(),
|
|
195
|
-
this.logs.crashlog?.startCapture() ?? B.resolve(),
|
|
196
|
-
];
|
|
197
|
-
await B.all(promises);
|
|
198
|
-
|
|
199
|
-
return didStartSyslog;
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Starts an iOS system logs broadcast websocket.
|
|
204
|
-
*
|
|
205
|
-
* The websocket listens on the same host and port as Appium. The endpoint created is `/ws/session/:sessionId:/appium/syslog`.
|
|
206
|
-
*
|
|
207
|
-
* If the websocket is already running, this command does nothing.
|
|
208
|
-
*
|
|
209
|
-
* Each connected webcoket listener will receive syslog lines as soon as they are visible to Appium.
|
|
210
|
-
* @see https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium
|
|
211
|
-
* @returns {Promise<void>}
|
|
212
|
-
* @this {XCUITestDriver}
|
|
213
|
-
*/
|
|
214
|
-
async mobileStartLogsBroadcast() {
|
|
215
|
-
const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
|
|
216
|
-
if (
|
|
217
|
-
!_.isEmpty(
|
|
218
|
-
await /** @type {import('@appium/types').AppiumServer} */ (
|
|
219
|
-
this.server
|
|
220
|
-
).getWebSocketHandlers(pathname),
|
|
221
|
-
)
|
|
222
|
-
) {
|
|
223
|
-
this.log.debug(
|
|
224
|
-
`The system logs broadcasting web socket server is already listening at ${pathname}`,
|
|
225
165
|
);
|
|
226
|
-
return;
|
|
227
166
|
}
|
|
167
|
+
}
|
|
228
168
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.log.
|
|
240
|
-
} else {
|
|
241
|
-
this.log.debug('Established a new system logs listener web socket connection');
|
|
169
|
+
let didStartSyslog = false;
|
|
170
|
+
/** @type {Promise[]} */
|
|
171
|
+
const promises = [
|
|
172
|
+
(async () => {
|
|
173
|
+
try {
|
|
174
|
+
await this.logs.syslog?.startCapture();
|
|
175
|
+
didStartSyslog = true;
|
|
176
|
+
this.eventEmitter.emit('syslogStarted', this.logs.syslog);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
this.log.debug(err.stack);
|
|
179
|
+
this.log.warn(`Continuing without capturing device logs: ${err.message}`);
|
|
242
180
|
}
|
|
181
|
+
})(),
|
|
182
|
+
this.logs.crashlog?.startCapture() ?? B.resolve(),
|
|
183
|
+
];
|
|
184
|
+
await B.all(promises);
|
|
243
185
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (ws?.readyState === WebSocket.OPEN) {
|
|
247
|
-
ws.send(logRecord.message);
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
this.logs.syslog?.on('output', this._syslogWebsocketListener);
|
|
186
|
+
return didStartSyslog;
|
|
187
|
+
}
|
|
252
188
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Starts an iOS system logs broadcast websocket.
|
|
191
|
+
*
|
|
192
|
+
* The websocket listens on the same host and port as Appium. The endpoint created is `/ws/session/:sessionId:/appium/syslog`.
|
|
193
|
+
*
|
|
194
|
+
* If the websocket is already running, this command does nothing.
|
|
195
|
+
*
|
|
196
|
+
* Each connected webcoket listener will receive syslog lines as soon as they are visible to Appium.
|
|
197
|
+
* @see https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium
|
|
198
|
+
* @returns {Promise<void>}
|
|
199
|
+
* @this {XCUITestDriver}
|
|
200
|
+
*/
|
|
201
|
+
export async function mobileStartLogsBroadcast() {
|
|
202
|
+
const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
|
|
203
|
+
if (
|
|
204
|
+
!_.isEmpty(
|
|
205
|
+
await /** @type {import('@appium/types').AppiumServer} */ (
|
|
206
|
+
this.server
|
|
207
|
+
).getWebSocketHandlers(pathname),
|
|
208
|
+
)
|
|
209
|
+
) {
|
|
210
|
+
this.log.debug(
|
|
211
|
+
`The system logs broadcasting web socket server is already listening at ${pathname}`,
|
|
212
|
+
);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
258
215
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
216
|
+
this.log.info(`Assigning system logs broadcasting web socket server to ${pathname}`);
|
|
217
|
+
// https://github.com/websockets/ws/blob/master/doc/ws.md
|
|
218
|
+
const wss = new WebSocket.Server({
|
|
219
|
+
noServer: true,
|
|
220
|
+
});
|
|
221
|
+
wss.on('connection', (ws, req) => {
|
|
222
|
+
if (req) {
|
|
223
|
+
const remoteIp = _.isEmpty(req.headers['x-forwarded-for'])
|
|
224
|
+
? req.connection?.remoteAddress
|
|
225
|
+
: req.headers['x-forwarded-for'];
|
|
226
|
+
this.log.debug(`Established a new system logs listener web socket connection from ${remoteIp}`);
|
|
227
|
+
} else {
|
|
228
|
+
this.log.debug('Established a new system logs listener web socket connection');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (_.isEmpty(this._syslogWebsocketListener)) {
|
|
232
|
+
this._syslogWebsocketListener = (logRecord) => {
|
|
233
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
234
|
+
ws.send(logRecord.message);
|
|
265
235
|
}
|
|
266
|
-
|
|
267
|
-
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
this.logs.syslog?.on('output', this._syslogWebsocketListener);
|
|
239
|
+
|
|
240
|
+
ws.on('close', (code, reason) => {
|
|
241
|
+
if (!_.isEmpty(this._syslogWebsocketListener)) {
|
|
242
|
+
this.logs.syslog?.removeListener('output', this._syslogWebsocketListener);
|
|
243
|
+
this._syslogWebsocketListener = null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let closeMsg = 'System logs listener web socket is closed.';
|
|
247
|
+
if (!_.isEmpty(code)) {
|
|
248
|
+
closeMsg += ` Code: ${code}.`;
|
|
249
|
+
}
|
|
250
|
+
if (!_.isEmpty(reason)) {
|
|
251
|
+
closeMsg += ` Reason: ${reason.toString()}.`;
|
|
252
|
+
}
|
|
253
|
+
this.log.debug(closeMsg);
|
|
268
254
|
});
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
)
|
|
273
|
-
|
|
255
|
+
});
|
|
256
|
+
await /** @type {AppiumServer} */ (this.server).addWebSocketHandler(
|
|
257
|
+
pathname,
|
|
258
|
+
/** @type {import('@appium/types').WSServer} */ (wss),
|
|
259
|
+
);
|
|
260
|
+
}
|
|
274
261
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
262
|
+
/**
|
|
263
|
+
* Stops the syslog broadcasting wesocket server previously started by `mobile: startLogsBroadcast`.
|
|
264
|
+
* If no websocket server is running, this command does nothing.
|
|
265
|
+
* @this {XCUITestDriver}
|
|
266
|
+
* @returns {Promise<void>}
|
|
267
|
+
*/
|
|
268
|
+
export async function mobileStopLogsBroadcast() {
|
|
269
|
+
const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
|
|
270
|
+
if (_.isEmpty(await /** @type {AppiumServer} */ (this.server).getWebSocketHandlers(pathname))) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
286
273
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
};
|
|
274
|
+
this.log.debug('Stopping the system logs broadcasting web socket server');
|
|
275
|
+
await /** @type {AppiumServer} */ (this.server).removeWebSocketHandler(pathname);
|
|
276
|
+
}
|
|
291
277
|
|
|
292
278
|
/**
|
|
293
279
|
* https://w3c.github.io/webdriver-bidi/#event-log-entryAdded
|
|
@@ -313,6 +299,19 @@ export function assignBiDiLogListener (logEmitter, properties) {
|
|
|
313
299
|
return [logEmitter, listener];
|
|
314
300
|
}
|
|
315
301
|
|
|
302
|
+
/**
|
|
303
|
+
*
|
|
304
|
+
* @param {Object} x
|
|
305
|
+
* @returns {import('./types').LogEntry}
|
|
306
|
+
*/
|
|
307
|
+
function nativeLogEntryToSeleniumEntry (x) {
|
|
308
|
+
const msg = _.isEmpty(x.prefix) ? x.message : `[${x.prefix}] ${x.message}`;
|
|
309
|
+
return toLogEntry(
|
|
310
|
+
_.replace(msg, COLOR_CODE_PATTERN, ''),
|
|
311
|
+
/** @type {any} */ (x).timestamp ?? Date.now()
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
316
315
|
/**
|
|
317
316
|
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
318
317
|
* @typedef {keyof typeof SUPPORTED_LOG_TYPES} XCUITestDriverLogTypes
|
package/lib/commands/memory.js
CHANGED
|
@@ -1,52 +1,50 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { errors } from 'appium/driver';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
4
|
+
/**
|
|
5
|
+
* Simulates Low Memory warning on the given application
|
|
6
|
+
*
|
|
7
|
+
* @since Xcode 15
|
|
8
|
+
* @param {string} bundleId - The bundle identifier of the target app. The app must be running
|
|
9
|
+
* @this {XCUITestDriver}
|
|
10
|
+
* @throws {Error} if the app is not running or is not installed
|
|
11
|
+
*/
|
|
12
|
+
export async function mobileSendMemoryWarning(bundleId) {
|
|
13
|
+
if (!this.isRealDevice()) {
|
|
14
|
+
throw new Error('Memory warning simulation is only supported on real devices');
|
|
15
|
+
}
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
const device = /** @type {import('../real-device').RealDevice} */ (this.device);
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const appInfos = await device.devicectl.listApps(bundleId);
|
|
20
|
+
if (_.isEmpty(appInfos)) {
|
|
21
|
+
throw new errors.InvalidArgumentError(
|
|
22
|
+
`The application identified by ${bundleId} cannot be found on the device. Is it installed?`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
this.log.info(`Emulating Low Memory warning for the process id ${pids[0]}, bundle id ${bundleId}`);
|
|
47
|
-
await device.devicectl.sendMemoryWarning(pids[0]);
|
|
26
|
+
// This regexp tries to match the process name of the main bundle executable.
|
|
27
|
+
// For example, if 'url' contains something like
|
|
28
|
+
// `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/`
|
|
29
|
+
// and the following processes might be running:
|
|
30
|
+
// `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/Target`
|
|
31
|
+
// `file:///private/var/containers/Bundle/Application/093ACA6D-8F0B-4601-87B9-4099E43A1A20/Target.app/PlugIns/WidgetExtension.appex/WidgetExtension`
|
|
32
|
+
// then we only want to match the first one.
|
|
33
|
+
// Unfortunately devicectl does not provide more info which would
|
|
34
|
+
// allow to connect a bundle id to a process id.
|
|
35
|
+
const pattern = new RegExp(`^${_.escapeRegExp(appInfos[0].url)}[^/]+$`);
|
|
36
|
+
/** @type {number[]} */
|
|
37
|
+
const pids = (await device.devicectl.listProcesses())
|
|
38
|
+
.filter(({executable}) => pattern.test(executable))
|
|
39
|
+
.map(({processIdentifier}) => processIdentifier);
|
|
40
|
+
if (_.isEmpty(pids)) {
|
|
41
|
+
throw new errors.InvalidArgumentError(
|
|
42
|
+
`The application identified by ${bundleId} must be running in order to simulate the Low Memory warning`
|
|
43
|
+
);
|
|
48
44
|
}
|
|
49
|
-
};
|
|
45
|
+
this.log.info(`Emulating Low Memory warning for the process id ${pids[0]}, bundle id ${bundleId}`);
|
|
46
|
+
await device.devicectl.sendMemoryWarning(pids[0]);
|
|
47
|
+
}
|
|
50
48
|
|
|
51
49
|
/**
|
|
52
50
|
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|