appium-xcuitest-driver 7.20.2 → 7.21.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/log.d.ts +0 -8
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +4 -13
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/types.d.ts +5 -0
- package/build/lib/commands/types.d.ts.map +1 -1
- package/build/lib/device-log/helpers.d.ts +3 -0
- package/build/lib/device-log/helpers.d.ts.map +1 -0
- package/build/lib/device-log/helpers.js +11 -0
- package/build/lib/device-log/helpers.js.map +1 -0
- package/build/lib/device-log/ios-crash-log.d.ts +6 -17
- package/build/lib/device-log/ios-crash-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-crash-log.js +4 -10
- package/build/lib/device-log/ios-crash-log.js.map +1 -1
- package/build/lib/device-log/ios-device-log.d.ts +5 -2
- package/build/lib/device-log/ios-device-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-device-log.js +3 -0
- package/build/lib/device-log/ios-device-log.js.map +1 -1
- package/build/lib/device-log/ios-log.d.ts +36 -7
- package/build/lib/device-log/ios-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-log.js +73 -25
- package/build/lib/device-log/ios-log.js.map +1 -1
- package/build/lib/device-log/ios-performance-log.d.ts +25 -8
- package/build/lib/device-log/ios-performance-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-performance-log.js +40 -23
- package/build/lib/device-log/ios-performance-log.js.map +1 -1
- package/build/lib/device-log/ios-simulator-log.d.ts +11 -4
- package/build/lib/device-log/ios-simulator-log.d.ts.map +1 -1
- package/build/lib/device-log/ios-simulator-log.js +41 -47
- package/build/lib/device-log/ios-simulator-log.js.map +1 -1
- package/build/lib/driver.d.ts +13 -0
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/execute-method-map.d.ts +13 -0
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +13 -0
- package/build/lib/execute-method-map.js.map +1 -1
- package/lib/commands/log.js +6 -14
- package/lib/commands/types.ts +6 -0
- package/lib/device-log/helpers.ts +9 -0
- package/lib/device-log/ios-crash-log.js +4 -11
- package/lib/device-log/ios-device-log.js +4 -2
- package/lib/device-log/ios-log.js +78 -27
- package/lib/device-log/ios-performance-log.js +40 -29
- package/lib/device-log/ios-simulator-log.js +45 -49
- package/lib/execute-method-map.ts +13 -0
- package/npm-shrinkwrap.json +81 -146
- package/package.json +2 -2
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import {EventEmitter} from 'events';
|
|
2
|
+
import { LRUCache } from 'lru-cache';
|
|
3
|
+
import { toLogEntry } from './helpers';
|
|
2
4
|
|
|
3
5
|
// We keep only the most recent log entries to avoid out of memory error
|
|
4
6
|
const MAX_LOG_ENTRIES_COUNT = 10000;
|
|
5
7
|
|
|
6
|
-
class
|
|
7
|
-
|
|
8
|
+
// TODO: Rewrite this class to typescript for better generic typing
|
|
9
|
+
|
|
10
|
+
export class IOSLog extends EventEmitter {
|
|
11
|
+
constructor(maxBufferSize = MAX_LOG_ENTRIES_COUNT) {
|
|
8
12
|
super();
|
|
9
|
-
this.
|
|
10
|
-
|
|
11
|
-
this.
|
|
13
|
+
this.maxBufferSize = maxBufferSize;
|
|
14
|
+
/** @type {LRUCache<number, any>} */
|
|
15
|
+
this.logs = new LRUCache({
|
|
16
|
+
max: this.maxBufferSize,
|
|
17
|
+
});
|
|
18
|
+
/** @type {number?} */
|
|
19
|
+
this.logIndexSinceLastRequest = null;
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
/** @returns {Promise<void>} */
|
|
@@ -28,38 +36,81 @@ class IOSLog extends EventEmitter {
|
|
|
28
36
|
throw new Error(`Sub-classes need to implement a 'isCapturing' function`);
|
|
29
37
|
}
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param {any} entry
|
|
42
|
+
* @returns {void}
|
|
43
|
+
*/
|
|
44
|
+
broadcast(entry) {
|
|
45
|
+
let recentIndex = -1;
|
|
46
|
+
for (const key of this.logs.rkeys()) {
|
|
47
|
+
recentIndex = key;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
const serializedEntry = this._serializeEntry(entry);
|
|
51
|
+
this.logs.set(++recentIndex, serializedEntry);
|
|
52
|
+
if (this.listenerCount('output')) {
|
|
53
|
+
this.emit('output', this._deserializeEntry(serializedEntry));
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
56
|
|
|
57
|
+
/**
|
|
58
|
+
*
|
|
59
|
+
* @returns {import('../commands/types').LogEntry[]}
|
|
60
|
+
*/
|
|
47
61
|
getLogs() {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
/** @type {import('../commands/types').LogEntry[]} */
|
|
63
|
+
const result = [];
|
|
64
|
+
/** @type {number?} */
|
|
65
|
+
let recentLogIndex = null;
|
|
66
|
+
for (const [index, value] of this.logs.entries()) {
|
|
67
|
+
if (this.logIndexSinceLastRequest && index > this.logIndexSinceLastRequest
|
|
68
|
+
|| !this.logIndexSinceLastRequest) {
|
|
69
|
+
recentLogIndex = index;
|
|
70
|
+
result.push(this._deserializeEntry(value));
|
|
52
71
|
}
|
|
53
|
-
this.logIdxSinceLastRequest = this.logs.length;
|
|
54
|
-
return result;
|
|
55
72
|
}
|
|
56
|
-
|
|
73
|
+
if (recentLogIndex !== null) {
|
|
74
|
+
this.logIndexSinceLastRequest = recentLogIndex;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
57
77
|
}
|
|
58
78
|
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @returns {import('../commands/types').LogEntry[]}
|
|
82
|
+
*/
|
|
59
83
|
getAllLogs() {
|
|
60
|
-
|
|
84
|
+
/** @type {import('../commands/types').LogEntry[]} */
|
|
85
|
+
const result = [];
|
|
86
|
+
for (const value of this.logs.values()) {
|
|
87
|
+
result.push(this._deserializeEntry(value));
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @param {any} value
|
|
95
|
+
* @returns {any}
|
|
96
|
+
*/
|
|
97
|
+
_serializeEntry(value) {
|
|
98
|
+
return [value, Date.now()];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
*
|
|
103
|
+
* @param {any} value
|
|
104
|
+
* @returns {any}
|
|
105
|
+
*/
|
|
106
|
+
_deserializeEntry(value) {
|
|
107
|
+
const [message, timestamp] = value;
|
|
108
|
+
return toLogEntry(message, timestamp);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_clearEntries() {
|
|
112
|
+
this.logs.clear();
|
|
61
113
|
}
|
|
62
114
|
}
|
|
63
115
|
|
|
64
|
-
export {IOSLog};
|
|
65
116
|
export default IOSLog;
|
|
@@ -1,57 +1,68 @@
|
|
|
1
1
|
import {logger} from 'appium/support';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
+
import { IOSLog } from './ios-log';
|
|
3
4
|
|
|
4
5
|
const log = logger.getLogger('IOSPerformanceLog');
|
|
5
6
|
const MAX_EVENTS = 5000;
|
|
6
7
|
|
|
7
|
-
class IOSPerformanceLog {
|
|
8
|
+
export class IOSPerformanceLog extends IOSLog {
|
|
8
9
|
constructor(remoteDebugger, maxEvents = MAX_EVENTS) {
|
|
10
|
+
super(maxEvents);
|
|
9
11
|
this.remoteDebugger = remoteDebugger;
|
|
10
12
|
this.maxEvents = parseInt(String(maxEvents), 10);
|
|
11
|
-
|
|
12
|
-
this.timelineEvents = [];
|
|
13
|
+
this._started = false;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @override
|
|
18
|
+
*/
|
|
15
19
|
async startCapture() {
|
|
16
20
|
log.debug('Starting performance (Timeline) log capture');
|
|
17
|
-
this.
|
|
18
|
-
|
|
21
|
+
this._clearEntries();
|
|
22
|
+
const result = await this.remoteDebugger.startTimeline(this.onTimelineEvent.bind(this));
|
|
23
|
+
this._started = true;
|
|
24
|
+
return result;
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @override
|
|
29
|
+
*/
|
|
21
30
|
async stopCapture() {
|
|
22
31
|
log.debug('Stopping performance (Timeline) log capture');
|
|
23
|
-
|
|
32
|
+
const result = await this.remoteDebugger.stopTimeline();
|
|
33
|
+
this._started = false;
|
|
34
|
+
return result;
|
|
24
35
|
}
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (this.timelineEvents.length > this.maxEvents) {
|
|
32
|
-
let removedEvent = this.timelineEvents.shift();
|
|
33
|
-
log.warn(
|
|
34
|
-
`Too many Timeline events, removing earliest: ${_.truncate(JSON.stringify(removedEvent))}`,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
+
/**
|
|
38
|
+
* @override
|
|
39
|
+
*/
|
|
40
|
+
get isCapturing() {
|
|
41
|
+
return this._started;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.timelineEvents = [];
|
|
44
|
+
/**
|
|
45
|
+
* @override
|
|
46
|
+
*/
|
|
47
|
+
_serializeEntry(value) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
/**
|
|
52
|
+
* @override
|
|
53
|
+
*/
|
|
54
|
+
_deserializeEntry(value) {
|
|
55
|
+
return value;
|
|
48
56
|
}
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param {import('../commands/types').LogEntry} event
|
|
61
|
+
*/
|
|
62
|
+
onTimelineEvent(event) {
|
|
63
|
+
log.debug(`Received Timeline event: ${_.truncate(JSON.stringify(event))}`);
|
|
64
|
+
this.broadcast(event);
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
67
|
|
|
56
|
-
export {IOSPerformanceLog};
|
|
57
68
|
export default IOSPerformanceLog;
|
|
@@ -4,10 +4,11 @@ import {logger} from 'appium/support';
|
|
|
4
4
|
import {exec} from 'teen_process';
|
|
5
5
|
|
|
6
6
|
const log = logger.getLogger('IOSSimulatorLog');
|
|
7
|
+
const EXECVP_ERROR_PATTERN = /execvp\(\)/;
|
|
7
8
|
|
|
8
9
|
const START_TIMEOUT = 10000;
|
|
9
10
|
|
|
10
|
-
class IOSSimulatorLog extends IOSLog {
|
|
11
|
+
export class IOSSimulatorLog extends IOSLog {
|
|
11
12
|
constructor({sim, showLogs, xcodeVersion, iosSimulatorLogsPredicate}) {
|
|
12
13
|
super();
|
|
13
14
|
this.sim = sim;
|
|
@@ -17,6 +18,9 @@ class IOSSimulatorLog extends IOSLog {
|
|
|
17
18
|
this.proc = null;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @override
|
|
23
|
+
*/
|
|
20
24
|
async startCapture() {
|
|
21
25
|
if (_.isUndefined(this.sim.udid)) {
|
|
22
26
|
throw new Error(`Log capture requires a sim udid`);
|
|
@@ -44,41 +48,9 @@ class IOSSimulatorLog extends IOSLog {
|
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
let firstLine = true;
|
|
52
|
-
let logRow = '';
|
|
53
|
-
this.proc.on('output', (stdout, stderr) => {
|
|
54
|
-
if (stdout) {
|
|
55
|
-
if (firstLine) {
|
|
56
|
-
if (stdout.endsWith('\n')) {
|
|
57
|
-
// don't store the first line of the log because it came before the sim was launched
|
|
58
|
-
firstLine = false;
|
|
59
|
-
}
|
|
60
|
-
} else {
|
|
61
|
-
logRow += stdout;
|
|
62
|
-
if (stdout.endsWith('\n')) {
|
|
63
|
-
this.onOutput(logRow);
|
|
64
|
-
logRow = '';
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (stderr) {
|
|
69
|
-
this.onOutput(logRow, 'STDERR');
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
let sd = (stdout, stderr) => {
|
|
74
|
-
if (/execvp\(\)/.test(stderr)) {
|
|
75
|
-
throw new Error('iOS log capture process failed to start');
|
|
76
|
-
}
|
|
77
|
-
return stdout || stderr;
|
|
78
|
-
};
|
|
79
|
-
await this.proc.start(sd, START_TIMEOUT);
|
|
80
|
-
}
|
|
81
|
-
|
|
51
|
+
/**
|
|
52
|
+
* @override
|
|
53
|
+
*/
|
|
82
54
|
async stopCapture() {
|
|
83
55
|
if (!this.proc) {
|
|
84
56
|
return;
|
|
@@ -87,6 +59,25 @@ class IOSSimulatorLog extends IOSLog {
|
|
|
87
59
|
this.proc = null;
|
|
88
60
|
}
|
|
89
61
|
|
|
62
|
+
/**
|
|
63
|
+
* @override
|
|
64
|
+
*/
|
|
65
|
+
get isCapturing() {
|
|
66
|
+
return this.proc && this.proc.isRunning;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {string} logRow
|
|
71
|
+
* @param {string} [prefix='']
|
|
72
|
+
*/
|
|
73
|
+
onOutput(logRow, prefix = '') {
|
|
74
|
+
this.broadcast(logRow);
|
|
75
|
+
if (this.showLogs) {
|
|
76
|
+
const space = prefix.length > 0 ? ' ' : '';
|
|
77
|
+
log.info(`[IOS_SYSLOG_ROW${space}${prefix}] ${logRow}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
90
81
|
async killLogSubProcess() {
|
|
91
82
|
if (!this.proc.isRunning) {
|
|
92
83
|
return;
|
|
@@ -103,22 +94,27 @@ class IOSSimulatorLog extends IOSLog {
|
|
|
103
94
|
}
|
|
104
95
|
}
|
|
105
96
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
97
|
+
async finishStartingLogCapture() {
|
|
98
|
+
if (!this.proc) {
|
|
99
|
+
log.errorAndThrow('Could not capture simulator log');
|
|
100
|
+
}
|
|
109
101
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const space = prefix.length > 0 ? ' ' : '';
|
|
117
|
-
log.info(`[IOS_SYSLOG_ROW${space}${prefix}] ${logLine}`);
|
|
118
|
-
}
|
|
102
|
+
for (const streamName of ['stdout', 'stderr']) {
|
|
103
|
+
this.proc.on(`lines-${streamName}`, (/** @type {string[]} */ lines) => {
|
|
104
|
+
for (const line of lines) {
|
|
105
|
+
this.onOutput(line, ...(streamName === 'stderr' ? ['STDERR'] : []));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
119
108
|
}
|
|
109
|
+
|
|
110
|
+
const startDetector = (/** @type {string} */ stdout, /** @type {string} */ stderr) => {
|
|
111
|
+
if (EXECVP_ERROR_PATTERN.test(stderr)) {
|
|
112
|
+
throw new Error('iOS log capture process failed to start');
|
|
113
|
+
}
|
|
114
|
+
return stdout || stderr;
|
|
115
|
+
};
|
|
116
|
+
await this.proc.start(startDetector, START_TIMEOUT);
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
|
|
123
|
-
export {IOSSimulatorLog};
|
|
124
120
|
export default IOSSimulatorLog;
|
|
@@ -333,6 +333,19 @@ export const executeMethodMap = {
|
|
|
333
333
|
required: ['style'],
|
|
334
334
|
},
|
|
335
335
|
},
|
|
336
|
+
'mobile: getClipboard': {
|
|
337
|
+
command: 'getClipboard',
|
|
338
|
+
params: {
|
|
339
|
+
optional: ['contentType'],
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
'mobile: setClipboard': {
|
|
343
|
+
command: 'setClipboard',
|
|
344
|
+
params: {
|
|
345
|
+
required: ['content'],
|
|
346
|
+
optional: ['contentType'],
|
|
347
|
+
},
|
|
348
|
+
},
|
|
336
349
|
'mobile: siriCommand': {
|
|
337
350
|
command: 'mobileSiriCommand',
|
|
338
351
|
params: {
|