appium-xcuitest-driver 10.10.1 → 10.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/build/lib/app-infos-cache.d.ts +29 -31
- package/build/lib/app-infos-cache.d.ts.map +1 -1
- package/build/lib/app-infos-cache.js +29 -33
- package/build/lib/app-infos-cache.js.map +1 -1
- package/build/lib/app-utils.d.ts +30 -59
- package/build/lib/app-utils.d.ts.map +1 -1
- package/build/lib/app-utils.js +158 -211
- package/build/lib/app-utils.js.map +1 -1
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +4 -8
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/biometric.d.ts.map +1 -1
- package/build/lib/commands/biometric.js +1 -5
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/condition.js +4 -4
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/content-size.js +1 -1
- package/build/lib/commands/content-size.js.map +1 -1
- package/build/lib/commands/find.js +2 -2
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/increase-contrast.js +1 -1
- package/build/lib/commands/increase-contrast.js.map +1 -1
- package/build/lib/commands/keychains.d.ts.map +1 -1
- package/build/lib/commands/keychains.js +1 -5
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.d.ts.map +1 -1
- package/build/lib/commands/localization.js +1 -5
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/pasteboard.d.ts.map +1 -1
- package/build/lib/commands/pasteboard.js +10 -8
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/permissions.js +1 -1
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/css-converter.d.ts +3 -9
- package/build/lib/css-converter.d.ts.map +1 -1
- package/build/lib/css-converter.js +41 -52
- package/build/lib/css-converter.js.map +1 -1
- package/build/lib/device/real-device-management.js +14 -14
- package/build/lib/device/real-device-management.js.map +1 -1
- package/build/lib/device/simulator-management.d.ts.map +1 -1
- package/build/lib/device/simulator-management.js +8 -4
- package/build/lib/device/simulator-management.js.map +1 -1
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +3 -3
- package/build/lib/driver.js.map +1 -1
- package/build/lib/logger.d.ts +1 -2
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js +2 -2
- package/build/lib/logger.js.map +1 -1
- package/build/lib/utils.d.ts +76 -134
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +80 -141
- package/build/lib/utils.js.map +1 -1
- package/lib/{app-infos-cache.js → app-infos-cache.ts} +44 -46
- package/lib/{app-utils.js → app-utils.ts} +215 -245
- package/lib/commands/battery.js +3 -4
- package/lib/commands/biometric.js +1 -2
- package/lib/commands/condition.js +1 -1
- package/lib/commands/content-size.js +1 -1
- package/lib/commands/find.js +1 -1
- package/lib/commands/increase-contrast.js +1 -1
- package/lib/commands/keychains.js +1 -2
- package/lib/commands/localization.js +1 -2
- package/lib/commands/pasteboard.js +9 -8
- package/lib/commands/permissions.js +1 -1
- package/lib/{css-converter.js → css-converter.ts} +75 -88
- package/lib/device/real-device-management.ts +1 -1
- package/lib/device/simulator-management.ts +9 -4
- package/lib/driver.ts +6 -4
- package/lib/logger.ts +3 -0
- package/lib/{utils.js → utils.ts} +102 -139
- package/npm-shrinkwrap.json +121 -74
- package/package.json +4 -4
- package/lib/logger.js +0 -5
|
@@ -8,12 +8,17 @@ import path from 'node:path';
|
|
|
8
8
|
import url from 'node:url';
|
|
9
9
|
import * as semver from 'semver';
|
|
10
10
|
import {exec} from 'teen_process';
|
|
11
|
-
import log from './logger';
|
|
11
|
+
import {log} from './logger';
|
|
12
12
|
import {PLATFORM_NAME_TVOS, PLATFORM_NAME_IOS} from './desired-caps';
|
|
13
|
+
import type {XCUITestDriverOpts, XCUITestDriver} from './driver';
|
|
14
|
+
import type {XcodeVersion} from 'appium-xcode';
|
|
15
|
+
import type {Simulator} from 'appium-ios-simulator';
|
|
16
|
+
import type {HTTPHeaders} from '@appium/types';
|
|
17
|
+
import type {Method} from 'axios';
|
|
13
18
|
|
|
14
19
|
export const UDID_AUTO = 'auto';
|
|
15
20
|
const MODULE_NAME = 'appium-xcuitest-driver';
|
|
16
|
-
const DEFAULT_TIMEOUT_KEY = 'default';
|
|
21
|
+
export const DEFAULT_TIMEOUT_KEY = 'default';
|
|
17
22
|
const XCTEST_LOG_FILES_PATTERNS = [
|
|
18
23
|
/^Session-WebDriverAgentRunner.*\.log$/i,
|
|
19
24
|
/^StandardOutputAndStandardError\.txt$/i,
|
|
@@ -21,48 +26,25 @@ const XCTEST_LOG_FILES_PATTERNS = [
|
|
|
21
26
|
const XCTEST_LOGS_CACHE_FOLDER_PREFIX = 'com.apple.dt.XCTest';
|
|
22
27
|
export const NATIVE_WIN = 'NATIVE_APP';
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
* @privateRemarks Is the minimum version really Xcode 7.3?
|
|
26
|
-
* @returns {Promise<XcodeVersion>}
|
|
27
|
-
*/
|
|
28
|
-
async function getAndCheckXcodeVersion() {
|
|
29
|
-
/** @type {XcodeVersion} */
|
|
30
|
-
let version;
|
|
29
|
+
export async function getAndCheckXcodeVersion(): Promise<XcodeVersion> {
|
|
31
30
|
try {
|
|
32
|
-
|
|
33
|
-
} catch (err) {
|
|
34
|
-
log.
|
|
35
|
-
throw new Error(`Could not determine Xcode version: ${err.message}`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// we do not support Xcodes < 7.3,
|
|
39
|
-
if (version.versionFloat < 7.3) {
|
|
40
|
-
const msg = `Xcode ${version.versionString} is not supported. Please upgrade to version 7.3 or higher`;
|
|
41
|
-
log.error(msg);
|
|
42
|
-
throw new Error(msg);
|
|
31
|
+
return await xcode.getVersion(true);
|
|
32
|
+
} catch (err: any) {
|
|
33
|
+
throw log.errorWithException(`Could not determine Xcode version: ${err.message}`);
|
|
43
34
|
}
|
|
44
|
-
return version;
|
|
45
35
|
}
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
* @returns {Promise<string|null>}
|
|
49
|
-
*/
|
|
50
|
-
async function getAndCheckIosSdkVersion() {
|
|
37
|
+
export async function getAndCheckIosSdkVersion(): Promise<string | null> {
|
|
51
38
|
try {
|
|
52
39
|
return await xcode.getMaxIOSSDK();
|
|
53
|
-
} catch (err) {
|
|
40
|
+
} catch (err: any) {
|
|
54
41
|
throw log.errorWithException(`Could not determine iOS SDK version: ${err.message}`);
|
|
55
42
|
}
|
|
56
43
|
}
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @param {string[]} locations
|
|
61
|
-
* @returns {Promise<void>}
|
|
62
|
-
*/
|
|
63
|
-
async function clearLogs(locations) {
|
|
45
|
+
export async function clearLogs(locations: string[]): Promise<void> {
|
|
64
46
|
log.debug('Clearing log files');
|
|
65
|
-
const cleanupPromises = [];
|
|
47
|
+
const cleanupPromises: Promise<void>[] = [];
|
|
66
48
|
for (const location of locations) {
|
|
67
49
|
if (!(await fs.exists(location))) {
|
|
68
50
|
continue;
|
|
@@ -70,7 +52,7 @@ async function clearLogs(locations) {
|
|
|
70
52
|
|
|
71
53
|
cleanupPromises.push(
|
|
72
54
|
(async () => {
|
|
73
|
-
let size;
|
|
55
|
+
let size: string | undefined;
|
|
74
56
|
try {
|
|
75
57
|
const {stdout} = await exec('du', ['-sh', location]);
|
|
76
58
|
size = stdout.trim().split(/\s+/)[0];
|
|
@@ -78,7 +60,7 @@ async function clearLogs(locations) {
|
|
|
78
60
|
try {
|
|
79
61
|
log.debug(`Deleting '${location}'. ${size ? `Freeing ${size}.` : ''}`);
|
|
80
62
|
await fs.rimraf(location);
|
|
81
|
-
} catch (err) {
|
|
63
|
+
} catch (err: any) {
|
|
82
64
|
log.warn(`Unable to delete '${location}': ${err.message}`);
|
|
83
65
|
}
|
|
84
66
|
})(),
|
|
@@ -93,9 +75,9 @@ async function clearLogs(locations) {
|
|
|
93
75
|
// This map contains derived data logs folders as keys
|
|
94
76
|
// and values are the count of times the particular
|
|
95
77
|
// folder has been scheduled for removal
|
|
96
|
-
const derivedDataCleanupMarkers = new Map();
|
|
78
|
+
const derivedDataCleanupMarkers = new Map<string, number>();
|
|
97
79
|
|
|
98
|
-
async function markSystemFilesForCleanup(wda) {
|
|
80
|
+
export async function markSystemFilesForCleanup(wda: any): Promise<void> {
|
|
99
81
|
if (!wda || !(await wda.retrieveDerivedDataPath())) {
|
|
100
82
|
log.warn(
|
|
101
83
|
'No WebDriverAgent derived data available, so unable to mark system files for cleanup',
|
|
@@ -105,13 +87,14 @@ async function markSystemFilesForCleanup(wda) {
|
|
|
105
87
|
|
|
106
88
|
const logsRoot = path.resolve(await wda.retrieveDerivedDataPath(), 'Logs');
|
|
107
89
|
let markersCount = 0;
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
const existingCount = derivedDataCleanupMarkers.get(logsRoot);
|
|
91
|
+
if (existingCount !== undefined) {
|
|
92
|
+
markersCount = existingCount;
|
|
110
93
|
}
|
|
111
94
|
derivedDataCleanupMarkers.set(logsRoot, ++markersCount);
|
|
112
95
|
}
|
|
113
96
|
|
|
114
|
-
async function clearSystemFiles(wda) {
|
|
97
|
+
export async function clearSystemFiles(wda: any): Promise<void> {
|
|
115
98
|
// only want to clear the system files for the particular WDA xcode run
|
|
116
99
|
if (!wda || !(await wda.retrieveDerivedDataPath())) {
|
|
117
100
|
log.warn('No WebDriverAgent derived data available, so unable to clear system files');
|
|
@@ -119,8 +102,9 @@ async function clearSystemFiles(wda) {
|
|
|
119
102
|
}
|
|
120
103
|
|
|
121
104
|
const logsRoot = path.resolve(await wda.retrieveDerivedDataPath(), 'Logs');
|
|
122
|
-
|
|
123
|
-
|
|
105
|
+
const existingCount = derivedDataCleanupMarkers.get(logsRoot);
|
|
106
|
+
if (existingCount !== undefined) {
|
|
107
|
+
let markersCount = existingCount;
|
|
124
108
|
derivedDataCleanupMarkers.set(logsRoot, --markersCount);
|
|
125
109
|
if (markersCount > 0) {
|
|
126
110
|
log.info(
|
|
@@ -138,8 +122,7 @@ async function clearSystemFiles(wda) {
|
|
|
138
122
|
log.debug(`Did not find the temporary XCTest logs root at '${globPattern}'`);
|
|
139
123
|
} else {
|
|
140
124
|
// perform the cleanup asynchronously
|
|
141
|
-
|
|
142
|
-
const promises = [];
|
|
125
|
+
const promises: Promise<void>[] = [];
|
|
143
126
|
for (const dstFolder of dstFolders) {
|
|
144
127
|
const promise = (async () => {
|
|
145
128
|
try {
|
|
@@ -152,7 +135,7 @@ async function clearSystemFiles(wda) {
|
|
|
152
135
|
fs.rimraf(itemPath);
|
|
153
136
|
}
|
|
154
137
|
});
|
|
155
|
-
} catch (e) {
|
|
138
|
+
} catch (e: any) {
|
|
156
139
|
log.debug(e.stack);
|
|
157
140
|
log.info(e.message);
|
|
158
141
|
}
|
|
@@ -173,7 +156,7 @@ async function clearSystemFiles(wda) {
|
|
|
173
156
|
log.info(`There is no ${logsRoot} folder, so not cleaning files`);
|
|
174
157
|
}
|
|
175
158
|
|
|
176
|
-
async function checkAppPresent(app) {
|
|
159
|
+
export async function checkAppPresent(app: string): Promise<void> {
|
|
177
160
|
log.debug(`Checking whether app '${app}' is actually present on file system`);
|
|
178
161
|
if (!(await fs.exists(app))) {
|
|
179
162
|
throw log.errorWithException(`Could not find app at '${app}'`);
|
|
@@ -184,11 +167,13 @@ async function checkAppPresent(app) {
|
|
|
184
167
|
/**
|
|
185
168
|
* Reads the content to the current module's package.json
|
|
186
169
|
*
|
|
187
|
-
* @returns
|
|
188
|
-
* @throws
|
|
170
|
+
* @returns The full path to module root
|
|
171
|
+
* @throws If the current module's package.json cannot be determined
|
|
189
172
|
*/
|
|
190
|
-
const getModuleManifest = _.memoize(async function getModuleManifest() {
|
|
191
|
-
|
|
173
|
+
const getModuleManifest = _.memoize(async function getModuleManifest(): Promise<Record<string, any>> {
|
|
174
|
+
// Start from the directory containing the compiled output (build/lib) or source (lib)
|
|
175
|
+
// and walk up to find package.json
|
|
176
|
+
let currentDir = path.resolve(__dirname, '..');
|
|
192
177
|
let isAtFsRoot = false;
|
|
193
178
|
while (!isAtFsRoot) {
|
|
194
179
|
const manifestPath = path.join(currentDir, 'package.json');
|
|
@@ -200,8 +185,9 @@ const getModuleManifest = _.memoize(async function getModuleManifest() {
|
|
|
200
185
|
}
|
|
201
186
|
}
|
|
202
187
|
} catch {}
|
|
203
|
-
|
|
204
|
-
isAtFsRoot = currentDir.length <=
|
|
188
|
+
const parentDir = path.dirname(currentDir);
|
|
189
|
+
isAtFsRoot = currentDir.length <= parentDir.length;
|
|
190
|
+
currentDir = parentDir;
|
|
205
191
|
}
|
|
206
192
|
throw new Error(`Cannot find the package manifest of the ${MODULE_NAME} Node.js module`);
|
|
207
193
|
});
|
|
@@ -212,10 +198,15 @@ const getModuleManifest = _.memoize(async function getModuleManifest() {
|
|
|
212
198
|
* @property {string} built Driver build timestamp
|
|
213
199
|
*/
|
|
214
200
|
|
|
201
|
+
export interface DriverInfo {
|
|
202
|
+
version: string;
|
|
203
|
+
built: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
215
206
|
/**
|
|
216
|
-
* @returns
|
|
207
|
+
* @returns
|
|
217
208
|
*/
|
|
218
|
-
const getDriverInfo = _.memoize(async function getDriverInfo() {
|
|
209
|
+
export const getDriverInfo = _.memoize(async function getDriverInfo(): Promise<DriverInfo> {
|
|
219
210
|
const [stat, manifest] = await B.all([
|
|
220
211
|
fs.stat(path.resolve(__dirname, '..')),
|
|
221
212
|
getModuleManifest(),
|
|
@@ -226,13 +217,13 @@ const getDriverInfo = _.memoize(async function getDriverInfo() {
|
|
|
226
217
|
};
|
|
227
218
|
});
|
|
228
219
|
|
|
229
|
-
function normalizeCommandTimeouts(value) {
|
|
220
|
+
export function normalizeCommandTimeouts(value: string | Record<string, number>): Record<string, number> {
|
|
230
221
|
// The value is normalized already
|
|
231
222
|
if (typeof value !== 'string') {
|
|
232
223
|
return value;
|
|
233
224
|
}
|
|
234
225
|
|
|
235
|
-
let result = {};
|
|
226
|
+
let result: Record<string, number> = {};
|
|
236
227
|
// Use as default timeout for all commands if a single integer value is provided
|
|
237
228
|
if (!isNaN(Number(value))) {
|
|
238
229
|
result[DEFAULT_TIMEOUT_KEY] = _.toInteger(value);
|
|
@@ -250,7 +241,7 @@ function normalizeCommandTimeouts(value) {
|
|
|
250
241
|
`"commandTimeouts" capability should be a valid JSON object. "${value}" was given instead`,
|
|
251
242
|
);
|
|
252
243
|
}
|
|
253
|
-
for (
|
|
244
|
+
for (const [cmd, timeout] of _.toPairs(result)) {
|
|
254
245
|
if (!_.isInteger(timeout) || timeout <= 0) {
|
|
255
246
|
throw log.errorWithException(
|
|
256
247
|
`The timeout for "${cmd}" should be a valid natural number of milliseconds. "${timeout}" was given instead`,
|
|
@@ -260,11 +251,11 @@ function normalizeCommandTimeouts(value) {
|
|
|
260
251
|
return result;
|
|
261
252
|
}
|
|
262
253
|
|
|
263
|
-
async function printUser() {
|
|
254
|
+
export async function printUser(): Promise<void> {
|
|
264
255
|
try {
|
|
265
|
-
|
|
256
|
+
const {stdout} = await exec('whoami');
|
|
266
257
|
log.debug(`Current user: '${stdout.trim()}'`);
|
|
267
|
-
} catch (err) {
|
|
258
|
+
} catch (err: any) {
|
|
268
259
|
log.debug(`Unable to get username running server: ${err.message}`);
|
|
269
260
|
}
|
|
270
261
|
}
|
|
@@ -274,16 +265,19 @@ async function printUser() {
|
|
|
274
265
|
* It is also possible to apply additional filtering based on the
|
|
275
266
|
* process command line.
|
|
276
267
|
*
|
|
277
|
-
* @param
|
|
278
|
-
* @param
|
|
268
|
+
* @param port - The port number.
|
|
269
|
+
* @param filteringFunc - Optional lambda function, which
|
|
279
270
|
* receives command line string of the particular process
|
|
280
271
|
* listening on given port, and is expected to return
|
|
281
272
|
* either true or false to include/exclude the corresponding PID
|
|
282
273
|
* from the resulting array.
|
|
283
|
-
* @returns
|
|
274
|
+
* @returns - the list of matched process ids.
|
|
284
275
|
*/
|
|
285
|
-
async function getPIDsListeningOnPort(
|
|
286
|
-
|
|
276
|
+
export async function getPIDsListeningOnPort(
|
|
277
|
+
port: string | number,
|
|
278
|
+
filteringFunc: ((cmdLine: string) => boolean | Promise<boolean>) | null = null
|
|
279
|
+
): Promise<string[]> {
|
|
280
|
+
const result: string[] = [];
|
|
287
281
|
try {
|
|
288
282
|
// This only works since Mac OS X El Capitan
|
|
289
283
|
const {stdout} = await exec('lsof', ['-ti', `tcp:${port}`]);
|
|
@@ -314,19 +308,32 @@ async function getPIDsListeningOnPort(port, filteringFunc = null) {
|
|
|
314
308
|
* @property {Record<string, any> | [string, any][]} [formFields] - Additional form fields for multipart http(s) uploads
|
|
315
309
|
*/
|
|
316
310
|
|
|
311
|
+
export interface UploadOptions {
|
|
312
|
+
user?: string;
|
|
313
|
+
pass?: string;
|
|
314
|
+
method?: Method;
|
|
315
|
+
headers?: HTTPHeaders;
|
|
316
|
+
fileFieldName?: string;
|
|
317
|
+
formFields?: Record<string, any> | [string, any][];
|
|
318
|
+
}
|
|
319
|
+
|
|
317
320
|
/**
|
|
318
321
|
* Encodes the given local file to base64 and returns the resulting string
|
|
319
322
|
* or uploads it to a remote server using http/https or ftp protocols
|
|
320
323
|
* if `remotePath` is set
|
|
321
324
|
*
|
|
322
|
-
* @param
|
|
323
|
-
* @param
|
|
325
|
+
* @param localPath - The path to an existing local file
|
|
326
|
+
* @param remotePath - The path to the remote location, where
|
|
324
327
|
* this file should be uploaded
|
|
325
|
-
* @param
|
|
326
|
-
* @returns
|
|
328
|
+
* @param uploadOptions - Set of upload options
|
|
329
|
+
* @returns Either an empty string if the upload was successful or
|
|
327
330
|
* base64-encoded file representation if `remotePath` is falsy
|
|
328
331
|
*/
|
|
329
|
-
async function encodeBase64OrUpload(
|
|
332
|
+
export async function encodeBase64OrUpload(
|
|
333
|
+
localPath: string,
|
|
334
|
+
remotePath: string | null = null,
|
|
335
|
+
uploadOptions: UploadOptions = {}
|
|
336
|
+
): Promise<string> {
|
|
330
337
|
if (!(await fs.exists(localPath))) {
|
|
331
338
|
throw log.errorWithException(`The file at '${localPath}' does not exist or is not accessible`);
|
|
332
339
|
}
|
|
@@ -338,7 +345,7 @@ async function encodeBase64OrUpload(localPath, remotePath = null, uploadOptions
|
|
|
338
345
|
}
|
|
339
346
|
|
|
340
347
|
const {user, pass, method, headers, fileFieldName, formFields} = uploadOptions;
|
|
341
|
-
const options = {
|
|
348
|
+
const options: net.HttpUploadOptions & net.NetOptions = {
|
|
342
349
|
method: method || 'PUT',
|
|
343
350
|
headers,
|
|
344
351
|
fileFieldName,
|
|
@@ -347,7 +354,7 @@ async function encodeBase64OrUpload(localPath, remotePath = null, uploadOptions
|
|
|
347
354
|
if (user && pass) {
|
|
348
355
|
options.auth = {user, pass};
|
|
349
356
|
}
|
|
350
|
-
await net.uploadFile(localPath,
|
|
357
|
+
await net.uploadFile(localPath, remotePath as string, options);
|
|
351
358
|
return '';
|
|
352
359
|
}
|
|
353
360
|
|
|
@@ -356,9 +363,9 @@ async function encodeBase64OrUpload(localPath, remotePath = null, uploadOptions
|
|
|
356
363
|
* in scope of the current session.
|
|
357
364
|
*
|
|
358
365
|
* @this {XCUITestDriver}
|
|
359
|
-
* @returns
|
|
366
|
+
* @returns
|
|
360
367
|
*/
|
|
361
|
-
export async function removeAllSessionWebSocketHandlers() {
|
|
368
|
+
export async function removeAllSessionWebSocketHandlers(this: XCUITestDriver): Promise<void> {
|
|
362
369
|
if (!this.sessionId || !_.isFunction(this.server?.getWebSocketHandlers)) {
|
|
363
370
|
return;
|
|
364
371
|
}
|
|
@@ -371,12 +378,12 @@ export async function removeAllSessionWebSocketHandlers() {
|
|
|
371
378
|
|
|
372
379
|
/**
|
|
373
380
|
* Returns true if the urlString is localhost
|
|
374
|
-
* @param
|
|
375
|
-
* @returns
|
|
381
|
+
* @param urlString
|
|
382
|
+
* @returns Return true if the urlString is localhost
|
|
376
383
|
*/
|
|
377
|
-
function isLocalHost(urlString) {
|
|
384
|
+
export function isLocalHost(urlString: string): boolean {
|
|
378
385
|
try {
|
|
379
|
-
const hostname =
|
|
386
|
+
const hostname = url.parse(urlString).hostname as string;
|
|
380
387
|
return ['localhost', '127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(hostname);
|
|
381
388
|
} catch {
|
|
382
389
|
log.warn(`'${urlString}' cannot be parsed as a valid URL`);
|
|
@@ -387,11 +394,11 @@ function isLocalHost(urlString) {
|
|
|
387
394
|
/**
|
|
388
395
|
* Normalizes platformVersion to a valid iOS version string
|
|
389
396
|
*
|
|
390
|
-
* @param
|
|
391
|
-
* @return
|
|
392
|
-
* @throws
|
|
397
|
+
* @param originalVersion - Loose version number, that can be parsed by semver
|
|
398
|
+
* @return iOS version number in <major>.<minor> format
|
|
399
|
+
* @throws if the version number cannot be parsed
|
|
393
400
|
*/
|
|
394
|
-
function normalizePlatformVersion(originalVersion) {
|
|
401
|
+
export function normalizePlatformVersion(originalVersion: string): string {
|
|
395
402
|
const normalizedVersion = semver.coerce(originalVersion);
|
|
396
403
|
if (!normalizedVersion) {
|
|
397
404
|
throw new Error(`The platform version '${originalVersion}' should be a valid version number`);
|
|
@@ -402,11 +409,11 @@ function normalizePlatformVersion(originalVersion) {
|
|
|
402
409
|
/**
|
|
403
410
|
* Assert the presence of particular keys in the given object
|
|
404
411
|
*
|
|
405
|
-
* @param
|
|
406
|
-
* @param
|
|
407
|
-
* @returns
|
|
412
|
+
* @param argNames one or more key names
|
|
413
|
+
* @param opts the object to check
|
|
414
|
+
* @returns the same given object
|
|
408
415
|
*/
|
|
409
|
-
function requireArgs(argNames, opts = {}) {
|
|
416
|
+
export function requireArgs(argNames: string | string[], opts: Record<string, any> = {}): Record<string, any> {
|
|
410
417
|
for (const argName of _.isArray(argNames) ? argNames : [argNames]) {
|
|
411
418
|
if (!_.has(opts, argName)) {
|
|
412
419
|
throw new errors.InvalidArgumentError(`'${argName}' argument must be provided`);
|
|
@@ -419,82 +426,38 @@ function requireArgs(argNames, opts = {}) {
|
|
|
419
426
|
* Asserts that the given driver is running on a Simulator and return
|
|
420
427
|
* the simlator instance.
|
|
421
428
|
*
|
|
422
|
-
* @param
|
|
423
|
-
* @param {import('./driver').XCUITestDriver} driver
|
|
424
|
-
* @returns {Simulator}
|
|
429
|
+
* @param action - Description of action
|
|
425
430
|
*/
|
|
426
|
-
export function assertSimulator(
|
|
427
|
-
if (!
|
|
431
|
+
export function assertSimulator(this: XCUITestDriver, action: string): Simulator {
|
|
432
|
+
if (!this.isSimulator()) {
|
|
428
433
|
throw new Error(`${_.upperFirst(action)} can only be performed on Simulator`);
|
|
429
434
|
}
|
|
430
|
-
return
|
|
435
|
+
return this.device as Simulator;
|
|
431
436
|
}
|
|
432
437
|
|
|
433
438
|
/**
|
|
434
439
|
* Check if platform name is the TV OS one.
|
|
435
|
-
*
|
|
436
|
-
* @param {string|null|undefined} platformName
|
|
437
|
-
* @returns {boolean}
|
|
438
440
|
*/
|
|
439
|
-
export function isTvOs(platformName) {
|
|
441
|
+
export function isTvOs(platformName: string | null | undefined): boolean {
|
|
440
442
|
return _.toLower(platformName ?? '') === _.toLower(PLATFORM_NAME_TVOS);
|
|
441
443
|
}
|
|
442
444
|
|
|
443
445
|
/**
|
|
444
446
|
* Return normalized platform name.
|
|
445
|
-
*
|
|
446
|
-
* @param {string|null|undefined} platformName
|
|
447
|
-
* @returns {string}
|
|
448
447
|
*/
|
|
449
|
-
export function normalizePlatformName(platformName) {
|
|
448
|
+
export function normalizePlatformName(platformName: string | null | undefined): string {
|
|
450
449
|
return isTvOs(platformName) ? PLATFORM_NAME_TVOS : PLATFORM_NAME_IOS;
|
|
451
450
|
}
|
|
452
451
|
|
|
453
|
-
|
|
454
|
-
* @param {import('./driver').XCUITestDriverOpts} opts
|
|
455
|
-
* @returns {boolean}
|
|
456
|
-
*/
|
|
457
|
-
export function shouldSetInitialSafariUrl(opts) {
|
|
452
|
+
export function shouldSetInitialSafariUrl(opts: XCUITestDriverOpts): boolean {
|
|
458
453
|
return !(opts.safariInitialUrl === '' || (opts.noReset && _.isNil(opts.safariInitialUrl)))
|
|
459
454
|
&& !opts.initialDeeplinkUrl;
|
|
460
455
|
}
|
|
461
456
|
|
|
462
|
-
|
|
463
|
-
* @param {import('./driver').XCUITestDriverOpts} opts
|
|
464
|
-
* @returns {boolean}
|
|
465
|
-
*/
|
|
466
|
-
export function isIos17OrNewer(opts) {
|
|
457
|
+
export function isIos17OrNewer(opts: XCUITestDriverOpts): boolean {
|
|
467
458
|
return !!opts.platformVersion && util.compareVersions(opts.platformVersion, '>=', '17.0');
|
|
468
459
|
}
|
|
469
460
|
|
|
470
|
-
|
|
471
|
-
* @param {import('./driver').XCUITestDriverOpts} opts
|
|
472
|
-
* @returns {boolean}
|
|
473
|
-
*/
|
|
474
|
-
export function isIos18OrNewer(opts) {
|
|
461
|
+
export function isIos18OrNewer(opts: XCUITestDriverOpts): boolean {
|
|
475
462
|
return !!opts.platformVersion && util.compareVersions(opts.platformVersion, '>=', '18.0');
|
|
476
463
|
}
|
|
477
|
-
|
|
478
|
-
export {
|
|
479
|
-
getAndCheckXcodeVersion,
|
|
480
|
-
getAndCheckIosSdkVersion,
|
|
481
|
-
checkAppPresent,
|
|
482
|
-
getDriverInfo,
|
|
483
|
-
clearSystemFiles,
|
|
484
|
-
normalizeCommandTimeouts,
|
|
485
|
-
DEFAULT_TIMEOUT_KEY,
|
|
486
|
-
markSystemFilesForCleanup,
|
|
487
|
-
printUser,
|
|
488
|
-
getPIDsListeningOnPort,
|
|
489
|
-
encodeBase64OrUpload,
|
|
490
|
-
isLocalHost,
|
|
491
|
-
normalizePlatformVersion,
|
|
492
|
-
clearLogs,
|
|
493
|
-
requireArgs,
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* @typedef {import('appium-xcode').XcodeVersion} XcodeVersion
|
|
498
|
-
* @typedef {import('appium-ios-simulator').Simulator} Simulator
|
|
499
|
-
* @typedef {import('./driver').XCUITestDriver} XCUITestDriver
|
|
500
|
-
*/
|