appium-mac2-driver 3.2.3 → 3.2.4
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 +7 -0
- package/build/lib/commands/app-management.d.ts +18 -21
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +14 -25
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/applescript.d.ts +8 -9
- package/build/lib/commands/applescript.d.ts.map +1 -1
- package/build/lib/commands/applescript.js +14 -13
- package/build/lib/commands/applescript.js.map +1 -1
- package/build/lib/commands/execute.d.ts +5 -8
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +5 -13
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/find.d.ts +6 -8
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +8 -13
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/gestures.d.ts +105 -118
- package/build/lib/commands/gestures.d.ts.map +1 -1
- package/build/lib/commands/gestures.js +141 -154
- package/build/lib/commands/gestures.js.map +1 -1
- package/build/lib/commands/navigation.d.ts +4 -6
- package/build/lib/commands/navigation.d.ts.map +1 -1
- package/build/lib/commands/navigation.js +2 -8
- package/build/lib/commands/navigation.js.map +1 -1
- package/build/lib/commands/record-screen.d.ts +57 -98
- package/build/lib/commands/record-screen.d.ts.map +1 -1
- package/build/lib/commands/record-screen.js +81 -84
- package/build/lib/commands/record-screen.js.map +1 -1
- package/build/lib/commands/screenshots.d.ts +5 -5
- package/build/lib/commands/screenshots.d.ts.map +1 -1
- package/build/lib/commands/screenshots.js +3 -8
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/source.d.ts +4 -5
- package/build/lib/commands/source.d.ts.map +1 -1
- package/build/lib/commands/source.js +3 -8
- package/build/lib/commands/source.js.map +1 -1
- package/lib/commands/app-management.ts +88 -0
- package/lib/commands/{applescript.js → applescript.ts} +28 -24
- package/lib/commands/execute.ts +32 -0
- package/lib/commands/find.ts +34 -0
- package/lib/commands/{gestures.js → gestures.ts} +333 -238
- package/lib/commands/navigation.ts +19 -0
- package/lib/commands/{record-screen.js → record-screen.ts} +165 -138
- package/lib/commands/screenshots.ts +18 -0
- package/lib/commands/{source.js → source.ts} +10 -11
- package/npm-shrinkwrap.json +5 -5
- package/package.json +1 -1
- package/lib/commands/app-management.js +0 -83
- package/lib/commands/execute.js +0 -33
- package/lib/commands/find.js +0 -31
- package/lib/commands/navigation.js +0 -18
- package/lib/commands/screenshots.js +0 -18
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Mac2Driver } from '../driver';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Opens the given URL with the default or the given application.
|
|
5
|
+
* Xcode must be at version 14.3+.
|
|
6
|
+
*
|
|
7
|
+
* @param url - The URL to be opened.
|
|
8
|
+
* @param bundleId - The bundle identifier of an application to open
|
|
9
|
+
* the given url with. If not provided then the default application
|
|
10
|
+
* for the given url scheme is going to be used.
|
|
11
|
+
*/
|
|
12
|
+
export async function macosDeepLink(
|
|
13
|
+
this: Mac2Driver,
|
|
14
|
+
url: string,
|
|
15
|
+
bundleId?: string
|
|
16
|
+
): Promise<unknown> {
|
|
17
|
+
return await this.wda.proxy.command('/url', 'POST', { url, bundleId });
|
|
18
|
+
}
|
|
19
|
+
|
|
@@ -4,7 +4,8 @@ import { util, fs, tempDir } from 'appium/support';
|
|
|
4
4
|
import { SubProcess } from 'teen_process';
|
|
5
5
|
import B from 'bluebird';
|
|
6
6
|
import { uploadRecordedMedia } from './helpers';
|
|
7
|
-
|
|
7
|
+
import type { Mac2Driver } from '../driver';
|
|
8
|
+
import type { AppiumLogger, StringRecord } from '@appium/types';
|
|
8
9
|
|
|
9
10
|
const RETRY_PAUSE = 300;
|
|
10
11
|
const RETRY_TIMEOUT = 5000;
|
|
@@ -15,94 +16,107 @@ const FFMPEG_BINARY = 'ffmpeg';
|
|
|
15
16
|
const DEFAULT_FPS = 15;
|
|
16
17
|
const DEFAULT_PRESET = 'veryfast';
|
|
17
18
|
|
|
19
|
+
type Preset = 'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast' | 'medium' | 'slow' | 'slower' | 'veryslow';
|
|
20
|
+
|
|
21
|
+
interface ScreenRecorderOptions {
|
|
22
|
+
fps?: number;
|
|
23
|
+
deviceId: string | number;
|
|
24
|
+
preset?: Preset;
|
|
25
|
+
captureCursor?: boolean;
|
|
26
|
+
captureClicks?: boolean;
|
|
27
|
+
videoFilter?: string;
|
|
28
|
+
timeLimit?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
/**
|
|
19
|
-
* @param
|
|
32
|
+
* @param log - Logger instance
|
|
20
33
|
*/
|
|
21
|
-
async function requireFfmpegPath
|
|
34
|
+
async function requireFfmpegPath(log: AppiumLogger): Promise<string> {
|
|
22
35
|
try {
|
|
23
36
|
return await fs.which(FFMPEG_BINARY);
|
|
24
37
|
} catch {
|
|
25
38
|
throw log.errorWithException(
|
|
26
|
-
`${FFMPEG_BINARY} has not been found in PATH. ` +
|
|
27
|
-
`Please make sure it is installed`
|
|
39
|
+
`${FFMPEG_BINARY} has not been found in PATH. ` + `Please make sure it is installed`
|
|
28
40
|
);
|
|
29
41
|
}
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
export class ScreenRecorder {
|
|
45
|
+
private readonly _log: AppiumLogger;
|
|
46
|
+
private readonly _videoPath: string;
|
|
47
|
+
private _process: SubProcess | null;
|
|
48
|
+
private readonly _fps: number;
|
|
49
|
+
private readonly _deviceId: string | number;
|
|
50
|
+
private readonly _captureCursor?: boolean;
|
|
51
|
+
private readonly _captureClicks?: boolean;
|
|
52
|
+
private readonly _preset: Preset;
|
|
53
|
+
private readonly _videoFilter?: string;
|
|
54
|
+
private readonly _timeLimit: number;
|
|
55
|
+
|
|
33
56
|
/**
|
|
34
57
|
*
|
|
35
|
-
* @param
|
|
36
|
-
* @param
|
|
37
|
-
* @param
|
|
58
|
+
* @param videoPath - Path to the video file
|
|
59
|
+
* @param log - Logger instance
|
|
60
|
+
* @param opts - Screen recorder options
|
|
38
61
|
*/
|
|
39
|
-
constructor
|
|
62
|
+
constructor(videoPath: string, log: AppiumLogger, opts: ScreenRecorderOptions) {
|
|
40
63
|
this._log = log;
|
|
41
64
|
this._videoPath = videoPath;
|
|
42
65
|
this._process = null;
|
|
43
|
-
this._fps =
|
|
66
|
+
this._fps = opts.fps && opts.fps > 0 ? opts.fps : DEFAULT_FPS;
|
|
44
67
|
this._deviceId = opts.deviceId;
|
|
45
68
|
this._captureCursor = opts.captureCursor;
|
|
46
69
|
this._captureClicks = opts.captureClicks;
|
|
47
70
|
this._preset = opts.preset || DEFAULT_PRESET;
|
|
48
71
|
this._videoFilter = opts.videoFilter;
|
|
49
|
-
this._timeLimit =
|
|
50
|
-
? opts.timeLimit
|
|
51
|
-
: DEFAULT_TIME_LIMIT;
|
|
72
|
+
this._timeLimit =
|
|
73
|
+
opts.timeLimit && opts.timeLimit > 0 ? opts.timeLimit : DEFAULT_TIME_LIMIT;
|
|
52
74
|
}
|
|
53
75
|
|
|
54
|
-
async getVideoPath
|
|
76
|
+
async getVideoPath(): Promise<string> {
|
|
55
77
|
return (await fs.exists(this._videoPath)) ? this._videoPath : '';
|
|
56
78
|
}
|
|
57
79
|
|
|
58
|
-
isRunning
|
|
80
|
+
isRunning(): boolean {
|
|
59
81
|
return !!(this._process?.isRunning);
|
|
60
82
|
}
|
|
61
83
|
|
|
62
|
-
async
|
|
63
|
-
if (this._process && this.isRunning()) {
|
|
64
|
-
this._log.debug('Force-stopping the currently running video recording');
|
|
65
|
-
try {
|
|
66
|
-
await this._process.stop('SIGKILL');
|
|
67
|
-
} catch {}
|
|
68
|
-
}
|
|
69
|
-
this._process = null;
|
|
70
|
-
const videoPath = await this.getVideoPath();
|
|
71
|
-
if (videoPath) {
|
|
72
|
-
await fs.rimraf(videoPath);
|
|
73
|
-
}
|
|
74
|
-
return '';
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async start () {
|
|
84
|
+
async start(): Promise<void> {
|
|
78
85
|
const ffmpeg = await requireFfmpegPath(this._log);
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
'
|
|
83
|
-
'-t',
|
|
84
|
-
|
|
87
|
+
const args: string[] = [
|
|
88
|
+
'-loglevel',
|
|
89
|
+
'error',
|
|
90
|
+
'-t',
|
|
91
|
+
`${this._timeLimit}`,
|
|
92
|
+
'-f',
|
|
93
|
+
'avfoundation',
|
|
85
94
|
...(this._captureCursor ? ['-capture_cursor', '1'] : []),
|
|
86
95
|
...(this._captureClicks ? ['-capture_mouse_clicks', '1'] : []),
|
|
87
|
-
'-framerate',
|
|
88
|
-
|
|
89
|
-
'-
|
|
90
|
-
|
|
91
|
-
'-
|
|
92
|
-
'
|
|
93
|
-
'-
|
|
94
|
-
|
|
95
|
-
'-
|
|
96
|
-
'
|
|
96
|
+
'-framerate',
|
|
97
|
+
`${this._fps}`,
|
|
98
|
+
'-i',
|
|
99
|
+
`${this._deviceId}`,
|
|
100
|
+
'-vcodec',
|
|
101
|
+
'libx264',
|
|
102
|
+
'-preset',
|
|
103
|
+
this._preset,
|
|
104
|
+
'-tune',
|
|
105
|
+
'zerolatency',
|
|
106
|
+
'-pix_fmt',
|
|
107
|
+
'yuv420p',
|
|
108
|
+
'-movflags',
|
|
109
|
+
'+faststart',
|
|
110
|
+
'-fflags',
|
|
111
|
+
'nobuffer',
|
|
112
|
+
'-f',
|
|
113
|
+
DEFAULT_EXT,
|
|
114
|
+
'-r',
|
|
115
|
+
`${this._fps}`,
|
|
97
116
|
...(this._videoFilter ? ['-filter:v', this._videoFilter] : []),
|
|
98
117
|
];
|
|
99
118
|
|
|
100
|
-
|
|
101
|
-
const fullCmd = [
|
|
102
|
-
ffmpeg,
|
|
103
|
-
...args,
|
|
104
|
-
this._videoPath,
|
|
105
|
-
];
|
|
119
|
+
const fullCmd: string[] = [ffmpeg, ...args, this._videoPath];
|
|
106
120
|
this._process = new SubProcess(fullCmd[0], fullCmd.slice(1));
|
|
107
121
|
this._log.debug(`Starting ${FFMPEG_BINARY}: ${util.quote(fullCmd)}`);
|
|
108
122
|
this._process.on('output', (stdout, stderr) => {
|
|
@@ -121,29 +135,34 @@ export class ScreenRecorder {
|
|
|
121
135
|
});
|
|
122
136
|
await this._process.start(0);
|
|
123
137
|
try {
|
|
124
|
-
await waitForCondition(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
138
|
+
await waitForCondition(
|
|
139
|
+
async () => {
|
|
140
|
+
if (await this.getVideoPath()) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
if (!this._process) {
|
|
144
|
+
throw new Error(`${FFMPEG_BINARY} process died unexpectedly`);
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
waitMs: RETRY_TIMEOUT,
|
|
150
|
+
intervalMs: RETRY_PAUSE,
|
|
130
151
|
}
|
|
131
|
-
|
|
132
|
-
}, {
|
|
133
|
-
waitMs: RETRY_TIMEOUT,
|
|
134
|
-
intervalMs: RETRY_PAUSE,
|
|
135
|
-
});
|
|
152
|
+
);
|
|
136
153
|
} catch {
|
|
137
154
|
await this._enforceTermination();
|
|
138
155
|
throw this._log.errorWithException(
|
|
139
156
|
`The expected screen record file '${this._videoPath}' does not exist. ` +
|
|
140
|
-
|
|
157
|
+
`Check the server log for more details`
|
|
141
158
|
);
|
|
142
159
|
}
|
|
143
|
-
this._log.info(
|
|
160
|
+
this._log.info(
|
|
161
|
+
`The video recording has started. Will timeout in ${util.pluralize('second', this._timeLimit, true)}`
|
|
162
|
+
);
|
|
144
163
|
}
|
|
145
164
|
|
|
146
|
-
async stop
|
|
165
|
+
async stop(force: boolean = false): Promise<string> {
|
|
147
166
|
if (force) {
|
|
148
167
|
return await this._enforceTermination();
|
|
149
168
|
}
|
|
@@ -156,7 +175,9 @@ export class ScreenRecorder {
|
|
|
156
175
|
return new B((resolve, reject) => {
|
|
157
176
|
const timer = setTimeout(async () => {
|
|
158
177
|
await this._enforceTermination();
|
|
159
|
-
reject(
|
|
178
|
+
reject(
|
|
179
|
+
new Error(`Screen recording has failed to exit after ${PROCESS_SHUTDOWN_TIMEOUT}ms`)
|
|
180
|
+
);
|
|
160
181
|
}, PROCESS_SHUTDOWN_TIMEOUT);
|
|
161
182
|
|
|
162
183
|
this._process?.once('exit', async (code, signal) => {
|
|
@@ -172,6 +193,23 @@ export class ScreenRecorder {
|
|
|
172
193
|
this._process?.proc?.stdin?.end();
|
|
173
194
|
});
|
|
174
195
|
}
|
|
196
|
+
|
|
197
|
+
private async _enforceTermination(): Promise<string> {
|
|
198
|
+
if (this._process && this.isRunning()) {
|
|
199
|
+
this._log.debug('Force-stopping the currently running video recording');
|
|
200
|
+
try {
|
|
201
|
+
await this._process.stop('SIGKILL');
|
|
202
|
+
} catch {
|
|
203
|
+
// Ignore errors during force stop
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
this._process = null;
|
|
207
|
+
const videoPath = await this.getVideoPath();
|
|
208
|
+
if (videoPath) {
|
|
209
|
+
await fs.rimraf(videoPath);
|
|
210
|
+
}
|
|
211
|
+
return '';
|
|
212
|
+
}
|
|
175
213
|
}
|
|
176
214
|
|
|
177
215
|
/**
|
|
@@ -181,47 +219,48 @@ export class ScreenRecorder {
|
|
|
181
219
|
* in System Preferences->Security & Privacy->Screen Recording.
|
|
182
220
|
* The resulting video uses H264 codec and is ready to be played by media players built-in into web browsers.
|
|
183
221
|
*
|
|
184
|
-
* @
|
|
185
|
-
* @param {string|number} deviceId Screen device index to use for the recording.
|
|
222
|
+
* @param deviceId - Screen device index to use for the recording.
|
|
186
223
|
* The list of available devices could be retrieved using
|
|
187
224
|
* `ffmpeg -f avfoundation -list_devices true -i` command.
|
|
188
|
-
* @param
|
|
225
|
+
* @param timeLimit - The maximum recording time, in seconds. The default
|
|
189
226
|
* value is 600 seconds (10 minutes).
|
|
190
|
-
* @param
|
|
227
|
+
* @param videoFilter - The video filter spec to apply for ffmpeg.
|
|
191
228
|
* See https://trac.ffmpeg.org/wiki/FilteringGuide for more details on the possible values.
|
|
192
229
|
* Example: Set it to `scale=ifnot(gte(iw\,1024)\,iw\,1024):-2` in order to limit the video width
|
|
193
230
|
* to 1024px. The height will be adjusted automatically to match the actual ratio.
|
|
194
|
-
* @param
|
|
231
|
+
* @param fps - The count of frames per second in the resulting video.
|
|
195
232
|
* The greater fps it has the bigger file size is. 15 by default.
|
|
196
|
-
* @param
|
|
197
|
-
* One of the supported encoding presets. A preset is a collection of options that will provide a
|
|
233
|
+
* @param preset - One of the supported encoding presets. A preset is a collection of options that will provide a
|
|
198
234
|
* certain encoding speed to compression ratio.
|
|
199
235
|
* A slower preset will provide better compression (compression is quality per filesize).
|
|
200
236
|
* This means that, for example, if you target a certain file size or constant bit rate, you will
|
|
201
237
|
* achieve better quality with a slower preset. Read https://trac.ffmpeg.org/wiki/Encode/H.264 for more details.
|
|
202
238
|
* `veryfast` by default
|
|
203
|
-
* @param
|
|
239
|
+
* @param captureCursor - Whether to capture the mouse cursor while recording the screen.
|
|
204
240
|
* False by default
|
|
205
|
-
* @param
|
|
241
|
+
* @param captureClicks - Whether to capture mouse clicks while recording the screen.
|
|
206
242
|
* False by default.
|
|
207
|
-
* @param
|
|
208
|
-
|
|
209
|
-
|
|
243
|
+
* @param forceRestart - Whether to ignore the call if a screen recording is currently running
|
|
244
|
+
* (`false`) or to start a new recording immediately and terminate the existing one
|
|
245
|
+
* if running (`true`). The default value is `true`.
|
|
210
246
|
* @throws {Error} If screen recording has failed to start or is not supported on the device under test.
|
|
211
247
|
*/
|
|
212
|
-
export async function startRecordingScreen
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
248
|
+
export async function startRecordingScreen(
|
|
249
|
+
this: Mac2Driver,
|
|
250
|
+
deviceId: string | number,
|
|
251
|
+
timeLimit?: string | number,
|
|
252
|
+
videoFilter?: string,
|
|
253
|
+
fps?: string | number,
|
|
254
|
+
preset?: Preset,
|
|
255
|
+
captureCursor?: boolean,
|
|
256
|
+
captureClicks?: boolean,
|
|
257
|
+
forceRestart: boolean = true
|
|
258
|
+
): Promise<void> {
|
|
222
259
|
if (_.isNil(deviceId)) {
|
|
223
|
-
throw new Error(
|
|
224
|
-
'
|
|
260
|
+
throw new Error(
|
|
261
|
+
`'deviceId' option must be provided. Run 'ffmpeg -f avfoundation -list_devices true -i' ` +
|
|
262
|
+
'to fetch the list of available device ids'
|
|
263
|
+
);
|
|
225
264
|
}
|
|
226
265
|
|
|
227
266
|
if (this._screenRecorder?.isRunning?.()) {
|
|
@@ -239,58 +278,60 @@ export async function startRecordingScreen (
|
|
|
239
278
|
prefix: util.uuidV4().substring(0, 8),
|
|
240
279
|
suffix: `.${DEFAULT_EXT}`,
|
|
241
280
|
});
|
|
242
|
-
this._screenRecorder = new ScreenRecorder(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
281
|
+
this._screenRecorder = new ScreenRecorder(
|
|
282
|
+
videoPath,
|
|
283
|
+
this.log,
|
|
284
|
+
{
|
|
285
|
+
fps: parseInt(`${fps}`, 10),
|
|
286
|
+
timeLimit: parseInt(`${timeLimit}`, 10),
|
|
287
|
+
preset,
|
|
288
|
+
captureCursor,
|
|
289
|
+
captureClicks,
|
|
290
|
+
videoFilter,
|
|
291
|
+
deviceId,
|
|
292
|
+
}
|
|
293
|
+
);
|
|
251
294
|
try {
|
|
252
295
|
await this._screenRecorder.start();
|
|
253
296
|
} catch (e) {
|
|
254
297
|
this._screenRecorder = null;
|
|
255
298
|
throw e;
|
|
256
299
|
}
|
|
257
|
-
}
|
|
300
|
+
}
|
|
258
301
|
|
|
259
302
|
/**
|
|
260
303
|
* Stop recording the screen.
|
|
261
304
|
* If no screen recording has been started before then the method returns an empty string.
|
|
262
305
|
*
|
|
263
|
-
* @param
|
|
306
|
+
* @param remotePath - The path to the remote location, where the resulting video should be uploaded.
|
|
264
307
|
* The following protocols are supported: http/https, ftp.
|
|
265
308
|
* Null or empty string value (the default setting) means the content of resulting
|
|
266
309
|
* file should be encoded as Base64 and passed as the endpoint response value.
|
|
267
310
|
* An exception will be thrown if the generated media file is too big to
|
|
268
311
|
* fit into the available process memory.
|
|
269
|
-
* @param
|
|
270
|
-
* @param
|
|
271
|
-
* @param
|
|
272
|
-
* @param
|
|
273
|
-
*
|
|
274
|
-
* @param {string} [fileFieldName] The name of the form field, where the file content BLOB should
|
|
312
|
+
* @param user - The name of the user for the remote authentication.
|
|
313
|
+
* @param pass - The password for the remote authentication.
|
|
314
|
+
* @param method - The http multipart upload method name. The 'PUT' one is used by default.
|
|
315
|
+
* @param headers - Additional headers mapping for multipart http(s) uploads
|
|
316
|
+
* @param fileFieldName - The name of the form field, where the file content BLOB should
|
|
275
317
|
* be stored for http(s) uploads
|
|
276
|
-
* @param
|
|
277
|
-
*
|
|
278
|
-
* @returns {Promise<string>} Base64-encoded content of the recorded media file if 'remotePath'
|
|
318
|
+
* @param formFields - Additional form fields for multipart http(s) uploads
|
|
319
|
+
* @returns Base64-encoded content of the recorded media file if 'remotePath'
|
|
279
320
|
* parameter is falsy or an empty string.
|
|
280
|
-
* @this {Mac2Driver}
|
|
281
321
|
* @throws {Error} If there was an error while getting the name of a media file
|
|
282
322
|
* or the file content cannot be uploaded to the remote location
|
|
283
323
|
* or screen recording is not supported on the device under test.
|
|
284
324
|
*/
|
|
285
|
-
export async function stopRecordingScreen
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
325
|
+
export async function stopRecordingScreen(
|
|
326
|
+
this: Mac2Driver,
|
|
327
|
+
remotePath?: string | null,
|
|
328
|
+
user?: string,
|
|
329
|
+
pass?: string,
|
|
330
|
+
method?: string,
|
|
331
|
+
headers?: StringRecord | [string, any][],
|
|
332
|
+
fileFieldName?: string,
|
|
333
|
+
formFields?: StringRecord | [string, string][]
|
|
334
|
+
): Promise<string> {
|
|
294
335
|
if (!this._screenRecorder) {
|
|
295
336
|
this.log.debug('No screen recording has been started. Doing nothing');
|
|
296
337
|
return '';
|
|
@@ -302,28 +343,14 @@ export async function stopRecordingScreen (
|
|
|
302
343
|
this.log.debug('No video data is found. Returning an empty string');
|
|
303
344
|
return '';
|
|
304
345
|
}
|
|
305
|
-
const options = {
|
|
346
|
+
const options: StringRecord = {
|
|
306
347
|
user,
|
|
307
348
|
pass,
|
|
308
349
|
method,
|
|
309
350
|
headers,
|
|
310
351
|
fileFieldName,
|
|
311
|
-
formFields
|
|
352
|
+
formFields,
|
|
312
353
|
};
|
|
313
354
|
return await uploadRecordedMedia.bind(this)(videoPath, remotePath, options);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* @typedef {import('../driver').Mac2Driver} Mac2Driver
|
|
318
|
-
*/
|
|
355
|
+
}
|
|
319
356
|
|
|
320
|
-
/**
|
|
321
|
-
* @typedef {Object} ScreenRecorderOptions
|
|
322
|
-
* @property {number} [fps]
|
|
323
|
-
* @property {string|number} deviceId
|
|
324
|
-
* @property {string} [preset]
|
|
325
|
-
* @property {boolean} [captureCursor]
|
|
326
|
-
* @property {boolean} [captureClicks]
|
|
327
|
-
* @property {string} [videoFilter]
|
|
328
|
-
* @property {number} [timeLimit]
|
|
329
|
-
*/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Mac2Driver } from '../driver';
|
|
2
|
+
import type { ScreenshotsInfo } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves screenshots of each display available to macOS
|
|
6
|
+
*
|
|
7
|
+
* @param displayId - macOS display identifier to take a screenshot for.
|
|
8
|
+
* If not provided then screenshots of all displays are going to be returned.
|
|
9
|
+
* If no matches were found then an error is thrown.
|
|
10
|
+
* @returns Screenshots information for the requested display(s)
|
|
11
|
+
*/
|
|
12
|
+
export async function macosScreenshots(
|
|
13
|
+
this: Mac2Driver,
|
|
14
|
+
displayId?: number
|
|
15
|
+
): Promise<ScreenshotsInfo> {
|
|
16
|
+
return (await this.wda.proxy.command('/wda/screenshots', 'POST', { displayId })) as ScreenshotsInfo;
|
|
17
|
+
}
|
|
18
|
+
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
+
import type { Mac2Driver } from '../driver';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Retrieves the string representation of the current application
|
|
3
5
|
*
|
|
4
|
-
* @
|
|
5
|
-
* @param {string} [format='xml'] The format of the application source to retrieve.
|
|
6
|
+
* @param format - The format of the application source to retrieve.
|
|
6
7
|
* Only two formats are supported:
|
|
7
8
|
* - xml: Returns the source formatted as XML document (the default setting)
|
|
8
9
|
* - description: Returns the source formatted as debugDescription output.
|
|
9
10
|
* See https://developer.apple.com/documentation/xctest/xcuielement/1500909-debugdescription?language=objc
|
|
10
11
|
* for more details.
|
|
11
|
-
* @returns
|
|
12
|
+
* @returns the page source in the requested format
|
|
12
13
|
*/
|
|
13
|
-
export async function macosSource
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
14
|
+
export async function macosSource(
|
|
15
|
+
this: Mac2Driver,
|
|
16
|
+
format: string = 'xml'
|
|
17
|
+
): Promise<string> {
|
|
18
|
+
return (await this.wda.proxy.command(`/source?format=${encodeURIComponent(format)}`, 'GET')) as string;
|
|
19
|
+
}
|
|
18
20
|
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {import('../driver').Mac2Driver} Mac2Driver
|
|
21
|
-
*/
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-mac2-driver",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.4",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "appium-mac2-driver",
|
|
9
|
-
"version": "3.2.
|
|
9
|
+
"version": "3.2.4",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@appium/strongbox": "^1.0.0-rc.1",
|
|
@@ -1574,9 +1574,9 @@
|
|
|
1574
1574
|
"license": "MIT"
|
|
1575
1575
|
},
|
|
1576
1576
|
"node_modules/color-string": {
|
|
1577
|
-
"version": "2.1.
|
|
1578
|
-
"resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.
|
|
1579
|
-
"integrity": "sha512-
|
|
1577
|
+
"version": "2.1.4",
|
|
1578
|
+
"resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz",
|
|
1579
|
+
"integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==",
|
|
1580
1580
|
"extraneous": true,
|
|
1581
1581
|
"license": "MIT",
|
|
1582
1582
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Start an app with given bundle identifier or activates it
|
|
3
|
-
* if the app is already running. An exception is thrown if the
|
|
4
|
-
* app with the given identifier cannot be found.
|
|
5
|
-
*
|
|
6
|
-
* @this {Mac2Driver}
|
|
7
|
-
* @param {string} [bundleId] Bundle identifier of the app to be launched or activated.
|
|
8
|
-
* Either this property or `path` must be provided
|
|
9
|
-
* @param {string} [path] Full path to the app bundle. Either this property or
|
|
10
|
-
* `bundleId` must be provided
|
|
11
|
-
* @param {string[]} [args] The list of command line arguments for the app to be launched with.
|
|
12
|
-
* This parameter is ignored if the app is already running.
|
|
13
|
-
* @param {import('@appium/types').StringRecord} [environment] Environment variables mapping.
|
|
14
|
-
* Custom variables are added to the default process environment.
|
|
15
|
-
*/
|
|
16
|
-
export async function macosLaunchApp (
|
|
17
|
-
bundleId,
|
|
18
|
-
path,
|
|
19
|
-
args,
|
|
20
|
-
environment,
|
|
21
|
-
) {
|
|
22
|
-
return await this.wda.proxy.command('/wda/apps/launch', 'POST', {
|
|
23
|
-
arguments: args,
|
|
24
|
-
environment,
|
|
25
|
-
bundleId,
|
|
26
|
-
path,
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Activate an app with given bundle identifier. An exception is thrown if the
|
|
32
|
-
* app cannot be found or is not running.
|
|
33
|
-
*
|
|
34
|
-
* @this {Mac2Driver}
|
|
35
|
-
* @param {string} [bundleId] Bundle identifier of the app to be activated.
|
|
36
|
-
* Either this property or `path` must be provided
|
|
37
|
-
* @param {string} [path] Full path to the app bundle. Either this property
|
|
38
|
-
* or `bundleId` must be provided
|
|
39
|
-
*/
|
|
40
|
-
export async function macosActivateApp (bundleId, path) {
|
|
41
|
-
return await this.wda.proxy.command('/wda/apps/activate', 'POST', { bundleId, path });
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Terminate an app with given bundle identifier. An exception is thrown if the
|
|
46
|
-
* app cannot be found.
|
|
47
|
-
*
|
|
48
|
-
* @this {Mac2Driver}
|
|
49
|
-
* @param {string} [bundleId] Bundle identifier of the app to be terminated.
|
|
50
|
-
* Either this property or `path` must be provided
|
|
51
|
-
* @param {string} [path] Full path to the app bundle. Either this property
|
|
52
|
-
* or `bundleId` must be provided
|
|
53
|
-
* @returns {Promise<boolean>} `true` if the app was running and has been successfully terminated.
|
|
54
|
-
* `false` if the app was not running before.
|
|
55
|
-
*/
|
|
56
|
-
export async function macosTerminateApp (bundleId, path) {
|
|
57
|
-
return /** @type {boolean} */ (
|
|
58
|
-
await this.wda.proxy.command('/wda/apps/terminate', 'POST', { bundleId, path })
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Query an app state with given bundle identifier. An exception is thrown if the
|
|
64
|
-
* app cannot be found.
|
|
65
|
-
*
|
|
66
|
-
* @this {Mac2Driver}
|
|
67
|
-
* @param {string} [bundleId] Bundle identifier of the app whose state should be queried.
|
|
68
|
-
* Either this property or `path` must be provided
|
|
69
|
-
* @param {string} [path] Full path to the app bundle. Either this property
|
|
70
|
-
* or `bundleId` must be provided
|
|
71
|
-
* @returns {Promise<number>} The application state code. See
|
|
72
|
-
* https://developer.apple.com/documentation/xctest/xcuiapplicationstate?language=objc
|
|
73
|
-
* for more details
|
|
74
|
-
*/
|
|
75
|
-
export async function macosQueryAppState (bundleId, path) {
|
|
76
|
-
return /** @type {number} */ (
|
|
77
|
-
await this.wda.proxy.command('/wda/apps/state', 'POST', { bundleId, path })
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* @typedef {import('../driver').Mac2Driver} Mac2Driver
|
|
83
|
-
*/
|