appium-ios-simulator 8.0.13 → 8.1.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 +6 -0
- package/build/lib/defaults-utils.d.ts +24 -24
- package/build/lib/defaults-utils.d.ts.map +1 -1
- package/build/lib/defaults-utils.js +61 -65
- package/build/lib/defaults-utils.js.map +1 -1
- package/build/lib/extensions/applications.d.ts.map +1 -1
- package/build/lib/extensions/applications.js +6 -7
- package/build/lib/extensions/applications.js.map +1 -1
- package/build/lib/extensions/biometric.d.ts.map +1 -1
- package/build/lib/extensions/biometric.js +3 -6
- package/build/lib/extensions/biometric.js.map +1 -1
- package/build/lib/extensions/keychain.d.ts.map +1 -1
- package/build/lib/extensions/keychain.js +7 -6
- package/build/lib/extensions/keychain.js.map +1 -1
- package/build/lib/extensions/permissions.d.ts.map +1 -1
- package/build/lib/extensions/permissions.js +16 -18
- package/build/lib/extensions/permissions.js.map +1 -1
- package/build/lib/extensions/safari.d.ts.map +1 -1
- package/build/lib/extensions/safari.js +2 -4
- package/build/lib/extensions/safari.js.map +1 -1
- package/build/lib/extensions/settings.d.ts.map +1 -1
- package/build/lib/extensions/settings.js +52 -50
- package/build/lib/extensions/settings.js.map +1 -1
- package/build/lib/simulator-xcode-14.d.ts +37 -37
- package/build/lib/simulator-xcode-14.d.ts.map +1 -1
- package/build/lib/simulator-xcode-14.js +57 -59
- package/build/lib/simulator-xcode-14.js.map +1 -1
- package/build/lib/simulator-xcode-15.d.ts.map +1 -1
- package/build/lib/simulator-xcode-15.js +3 -5
- package/build/lib/simulator-xcode-15.js.map +1 -1
- package/build/lib/types.d.ts +8 -8
- package/build/lib/types.d.ts.map +1 -1
- package/build/lib/utils.d.ts +11 -3
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +50 -35
- package/build/lib/utils.js.map +1 -1
- package/lib/defaults-utils.ts +69 -68
- package/lib/extensions/applications.ts +6 -7
- package/lib/extensions/biometric.ts +3 -3
- package/lib/extensions/keychain.ts +11 -6
- package/lib/extensions/permissions.ts +17 -19
- package/lib/extensions/safari.ts +2 -4
- package/lib/extensions/settings.ts +71 -62
- package/lib/simulator-xcode-14.ts +70 -71
- package/lib/simulator-xcode-15.ts +3 -5
- package/lib/types.ts +9 -9
- package/lib/utils.ts +52 -37
- package/package.json +1 -5
package/lib/defaults-utils.ts
CHANGED
|
@@ -1,8 +1,64 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {DOMParser, XMLSerializer, type Document, type Element} from '@xmldom/xmldom';
|
|
3
2
|
import {exec} from 'teen_process';
|
|
4
|
-
import B from 'bluebird';
|
|
5
3
|
import {log} from './logger';
|
|
4
|
+
import {isPlainObject} from './utils';
|
|
5
|
+
|
|
6
|
+
export class NSUserDefaults {
|
|
7
|
+
plist: string;
|
|
8
|
+
|
|
9
|
+
constructor(plist: string) {
|
|
10
|
+
this.plist = plist;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Reads the content of the given plist file using plutil command line tool
|
|
15
|
+
* and serializes it to a JSON representation
|
|
16
|
+
*
|
|
17
|
+
* @returns The serialized plist content
|
|
18
|
+
* @throws {Error} If there was an error during serialization
|
|
19
|
+
*/
|
|
20
|
+
async asJson(): Promise<Record<string, any>> {
|
|
21
|
+
try {
|
|
22
|
+
const {stdout} = await exec('plutil', ['-convert', 'json', '-o', '-', this.plist]);
|
|
23
|
+
return JSON.parse(stdout);
|
|
24
|
+
} catch (e: any) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`'${this.plist}' cannot be converted to JSON. Original error: ${e.stderr || e.message}`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Updates the content of the given plist file.
|
|
33
|
+
* If the plist does not exist yet then it is going to be created.
|
|
34
|
+
*
|
|
35
|
+
* @param valuesMap Mapping of preference values to update.
|
|
36
|
+
* If any of item values are of dictionary type then only the first level dictionary gets
|
|
37
|
+
* updated. Everything below this level will be replaced. This is the known limitation
|
|
38
|
+
* of the `defaults` command line tool. A workaround for it would be to read the current
|
|
39
|
+
* preferences mapping first and merge it with this value.
|
|
40
|
+
* @throws {Error} If there was an error while updating the plist
|
|
41
|
+
*/
|
|
42
|
+
async update(valuesMap: Record<string, any>): Promise<void> {
|
|
43
|
+
if (!isPlainObject(valuesMap)) {
|
|
44
|
+
throw new TypeError(`plist values must be a map. '${valuesMap}' is given instead`);
|
|
45
|
+
}
|
|
46
|
+
if (Object.keys(valuesMap).length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const commandArgs = generateDefaultsCommandArgs(valuesMap);
|
|
51
|
+
try {
|
|
52
|
+
await Promise.all(
|
|
53
|
+
commandArgs.map((args) => exec('defaults', ['write', this.plist, ...args])),
|
|
54
|
+
);
|
|
55
|
+
} catch (e: any) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Could not write defaults into '${this.plist}'. Original error: ${e.stderr || e.message}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
6
62
|
|
|
7
63
|
/**
|
|
8
64
|
* Serializes the given value to plist-compatible
|
|
@@ -19,10 +75,10 @@ import {log} from './logger';
|
|
|
19
75
|
export function toXmlArg(value: any, serialize: boolean = true): string | Element {
|
|
20
76
|
let xmlDoc: Document | null = null;
|
|
21
77
|
|
|
22
|
-
if (
|
|
78
|
+
if (isPlainObject(value)) {
|
|
23
79
|
xmlDoc = new DOMParser().parseFromString('<dict></dict>', 'text/xml');
|
|
24
80
|
const documentElement = requireDocumentElement(xmlDoc);
|
|
25
|
-
for (const [subKey, subValue] of
|
|
81
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
26
82
|
const keyEl = xmlDoc.createElement('key');
|
|
27
83
|
const keyTextEl = xmlDoc.createTextNode(subKey);
|
|
28
84
|
keyEl.appendChild(keyTextEl);
|
|
@@ -30,20 +86,20 @@ export function toXmlArg(value: any, serialize: boolean = true): string | Elemen
|
|
|
30
86
|
const subValueEl = xmlDoc.importNode(toXmlArg(subValue, false) as Element, true);
|
|
31
87
|
documentElement.appendChild(subValueEl);
|
|
32
88
|
}
|
|
33
|
-
} else if (
|
|
89
|
+
} else if (Array.isArray(value)) {
|
|
34
90
|
xmlDoc = new DOMParser().parseFromString('<array></array>', 'text/xml');
|
|
35
91
|
const documentElement = requireDocumentElement(xmlDoc);
|
|
36
92
|
for (const subValue of value) {
|
|
37
93
|
const subValueEl = xmlDoc.importNode(toXmlArg(subValue, false) as Element, true);
|
|
38
94
|
documentElement.appendChild(subValueEl);
|
|
39
95
|
}
|
|
40
|
-
} else if (
|
|
96
|
+
} else if (typeof value === 'boolean') {
|
|
41
97
|
xmlDoc = new DOMParser().parseFromString(value ? '<true/>' : '<false/>', 'text/xml');
|
|
42
|
-
} else if (
|
|
98
|
+
} else if (Number.isInteger(value)) {
|
|
43
99
|
xmlDoc = new DOMParser().parseFromString(`<integer>${value}</integer>`, 'text/xml');
|
|
44
|
-
} else if (
|
|
100
|
+
} else if (typeof value === 'number') {
|
|
45
101
|
xmlDoc = new DOMParser().parseFromString(`<real>${value}</real>`, 'text/xml');
|
|
46
|
-
} else if (
|
|
102
|
+
} else if (typeof value === 'string') {
|
|
47
103
|
xmlDoc = new DOMParser().parseFromString(`<string></string>`, 'text/xml');
|
|
48
104
|
const valueTextEl = xmlDoc.createTextNode(value);
|
|
49
105
|
requireDocumentElement(xmlDoc).appendChild(valueTextEl);
|
|
@@ -78,15 +134,15 @@ export function generateDefaultsCommandArgs(
|
|
|
78
134
|
replace: boolean = false,
|
|
79
135
|
): string[][] {
|
|
80
136
|
const resultArgs: string[][] = [];
|
|
81
|
-
for (const [key, value] of
|
|
137
|
+
for (const [key, value] of Object.entries(valuesMap)) {
|
|
82
138
|
try {
|
|
83
|
-
if (!replace &&
|
|
139
|
+
if (!replace && isPlainObject(value)) {
|
|
84
140
|
const dictArgs = [key, '-dict-add'];
|
|
85
|
-
for (const [subKey, subValue] of
|
|
141
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
86
142
|
dictArgs.push(subKey, toXmlArg(subValue) as string);
|
|
87
143
|
}
|
|
88
144
|
resultArgs.push(dictArgs);
|
|
89
|
-
} else if (!replace &&
|
|
145
|
+
} else if (!replace && Array.isArray(value)) {
|
|
90
146
|
const arrayArgs = [key, '-array-add'];
|
|
91
147
|
for (const subValue of value) {
|
|
92
148
|
arrayArgs.push(toXmlArg(subValue) as string);
|
|
@@ -106,61 +162,6 @@ export function generateDefaultsCommandArgs(
|
|
|
106
162
|
return resultArgs;
|
|
107
163
|
}
|
|
108
164
|
|
|
109
|
-
export class NSUserDefaults {
|
|
110
|
-
plist: string;
|
|
111
|
-
|
|
112
|
-
constructor(plist: string) {
|
|
113
|
-
this.plist = plist;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Reads the content of the given plist file using plutil command line tool
|
|
118
|
-
* and serializes it to a JSON representation
|
|
119
|
-
*
|
|
120
|
-
* @returns The serialized plist content
|
|
121
|
-
* @throws {Error} If there was an error during serialization
|
|
122
|
-
*/
|
|
123
|
-
async asJson(): Promise<Record<string, any>> {
|
|
124
|
-
try {
|
|
125
|
-
const {stdout} = await exec('plutil', ['-convert', 'json', '-o', '-', this.plist]);
|
|
126
|
-
return JSON.parse(stdout);
|
|
127
|
-
} catch (e: any) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
`'${this.plist}' cannot be converted to JSON. Original error: ${e.stderr || e.message}`,
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Updates the content of the given plist file.
|
|
136
|
-
* If the plist does not exist yet then it is going to be created.
|
|
137
|
-
*
|
|
138
|
-
* @param valuesMap Mapping of preference values to update.
|
|
139
|
-
* If any of item values are of dictionary type then only the first level dictionary gets
|
|
140
|
-
* updated. Everything below this level will be replaced. This is the known limitation
|
|
141
|
-
* of the `defaults` command line tool. A workaround for it would be to read the current
|
|
142
|
-
* preferences mapping first and merge it with this value.
|
|
143
|
-
* @throws {Error} If there was an error while updating the plist
|
|
144
|
-
*/
|
|
145
|
-
async update(valuesMap: Record<string, any>): Promise<void> {
|
|
146
|
-
if (!_.isPlainObject(valuesMap)) {
|
|
147
|
-
throw new TypeError(`plist values must be a map. '${valuesMap}' is given instead`);
|
|
148
|
-
}
|
|
149
|
-
if (_.isEmpty(valuesMap)) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const commandArgs = generateDefaultsCommandArgs(valuesMap);
|
|
154
|
-
try {
|
|
155
|
-
await B.all(commandArgs.map((args) => exec('defaults', ['write', this.plist, ...args])));
|
|
156
|
-
} catch (e: any) {
|
|
157
|
-
throw new Error(
|
|
158
|
-
`Could not write defaults into '${this.plist}'. Original error: ${e.stderr || e.message}`,
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
165
|
function requireDocumentElement(xmlDoc: Document): Element {
|
|
165
166
|
const {documentElement} = xmlDoc;
|
|
166
167
|
if (!documentElement) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import {fs, plist, util} from '@appium/support';
|
|
4
|
-
import B from 'bluebird';
|
|
5
3
|
import {waitForCondition} from 'asyncbox';
|
|
4
|
+
import {isPlainObject} from '../utils';
|
|
6
5
|
import type {CoreSimulator, InteractsWithApps, LaunchAppOptions} from '../types';
|
|
7
6
|
|
|
8
7
|
type CoreSimulatorWithApps = CoreSimulator & InteractsWithApps;
|
|
@@ -32,7 +31,7 @@ export async function getUserInstalledBundleIdsByBundleName(
|
|
|
32
31
|
cwd: appsRoot,
|
|
33
32
|
absolute: true,
|
|
34
33
|
});
|
|
35
|
-
if (
|
|
34
|
+
if (infoPlists.length === 0) {
|
|
36
35
|
return [];
|
|
37
36
|
}
|
|
38
37
|
|
|
@@ -48,11 +47,11 @@ export async function getUserInstalledBundleIdsByBundleName(
|
|
|
48
47
|
})(),
|
|
49
48
|
);
|
|
50
49
|
}
|
|
51
|
-
const bundleInfos = (await
|
|
50
|
+
const bundleInfos = (await Promise.all(bundleInfoPromises)).filter(isPlainObject);
|
|
52
51
|
const bundleIds = bundleInfos
|
|
53
52
|
.filter(({CFBundleName}) => CFBundleName === bundleName)
|
|
54
53
|
.map(({CFBundleIdentifier}) => CFBundleIdentifier);
|
|
55
|
-
if (
|
|
54
|
+
if (bundleIds.length === 0) {
|
|
56
55
|
return [];
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -166,12 +165,12 @@ export async function scrubApp(this: CoreSimulatorWithApps, bundleId: string): P
|
|
|
166
165
|
this.log.info(
|
|
167
166
|
`Found ${appFiles.length} ${bundleId} app ${util.pluralize('file', appFiles.length, false)} to scrub`,
|
|
168
167
|
);
|
|
169
|
-
if (
|
|
168
|
+
if (appFiles.length === 0) {
|
|
170
169
|
return;
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
try {
|
|
174
173
|
await this.terminateApp(bundleId);
|
|
175
174
|
} catch {}
|
|
176
|
-
await
|
|
175
|
+
await Promise.all(appFiles.map((p) => fs.rimraf(p)));
|
|
177
176
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import type {CoreSimulator, SupportsBiometric} from '../types';
|
|
2
|
+
import {escapeRegExp} from '../utils';
|
|
3
3
|
|
|
4
4
|
type CoreSimulatorWithBiometric = CoreSimulator & SupportsBiometric;
|
|
5
5
|
|
|
@@ -18,7 +18,7 @@ export async function isBiometricEnrolled(this: CoreSimulatorWithBiometric): Pro
|
|
|
18
18
|
'-g',
|
|
19
19
|
ENROLLMENT_NOTIFICATION_RECEIVER,
|
|
20
20
|
]);
|
|
21
|
-
const match = new RegExp(`${
|
|
21
|
+
const match = new RegExp(`${escapeRegExp(ENROLLMENT_NOTIFICATION_RECEIVER)}\\s+([01])`).exec(
|
|
22
22
|
stdout,
|
|
23
23
|
);
|
|
24
24
|
if (!match) {
|
|
@@ -80,7 +80,7 @@ export async function sendBiometricMatch(
|
|
|
80
80
|
export function toBiometricDomainComponent(name: string): string {
|
|
81
81
|
if (!BIOMETRICS[name]) {
|
|
82
82
|
throw new Error(
|
|
83
|
-
`'${name}' is not a valid biometric. Use one of: ${JSON.stringify(
|
|
83
|
+
`'${name}' is not a valid biometric. Use one of: ${JSON.stringify(Object.keys(BIOMETRICS))}`,
|
|
84
84
|
);
|
|
85
85
|
}
|
|
86
86
|
return BIOMETRICS[name];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import {fs, mkdirp, tempDir, util} from '@appium/support';
|
|
4
3
|
import {exec} from 'teen_process';
|
|
@@ -16,13 +15,16 @@ type CoreSimulatorWithKeychain = CoreSimulator & InteractsWithKeychain;
|
|
|
16
15
|
*/
|
|
17
16
|
export async function backupKeychains(this: CoreSimulatorWithKeychain): Promise<boolean> {
|
|
18
17
|
const resetBackupPath = async (newPath: string | null | undefined) => {
|
|
19
|
-
if (
|
|
18
|
+
if (
|
|
19
|
+
typeof this._keychainsBackupPath === 'string' &&
|
|
20
|
+
(await fs.exists(this._keychainsBackupPath))
|
|
21
|
+
) {
|
|
20
22
|
await fs.unlink(this._keychainsBackupPath);
|
|
21
23
|
}
|
|
22
24
|
this._keychainsBackupPath = newPath;
|
|
23
25
|
};
|
|
24
26
|
|
|
25
|
-
if (!(await fs.exists(this.keychainPath)) ||
|
|
27
|
+
if (!(await fs.exists(this.keychainPath)) || (await fs.readdir(this.keychainPath)).length === 0) {
|
|
26
28
|
this.log.info(`There is nothing to backup from '${this.keychainPath}'`);
|
|
27
29
|
await resetBackupPath(null);
|
|
28
30
|
return false;
|
|
@@ -64,14 +66,17 @@ export async function restoreKeychains(
|
|
|
64
66
|
this: CoreSimulatorWithKeychain,
|
|
65
67
|
excludePatterns: string[] | string = [],
|
|
66
68
|
): Promise<boolean> {
|
|
67
|
-
if (
|
|
69
|
+
if (
|
|
70
|
+
typeof this._keychainsBackupPath !== 'string' ||
|
|
71
|
+
!(await fs.exists(this._keychainsBackupPath))
|
|
72
|
+
) {
|
|
68
73
|
throw new Error(
|
|
69
74
|
`The keychains backup archive does not exist. ` + `Are you sure it was created before?`,
|
|
70
75
|
);
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
let patterns: string[] = [];
|
|
74
|
-
if (
|
|
79
|
+
if (typeof excludePatterns === 'string') {
|
|
75
80
|
patterns = excludePatterns.split(',').map((x) => x.trim());
|
|
76
81
|
} else {
|
|
77
82
|
patterns = excludePatterns;
|
|
@@ -95,7 +100,7 @@ export async function restoreKeychains(
|
|
|
95
100
|
const unzipArgs = [
|
|
96
101
|
'-o',
|
|
97
102
|
backupPath,
|
|
98
|
-
...
|
|
103
|
+
...patterns.flatMap((x) => ['-x', x]),
|
|
99
104
|
'-d',
|
|
100
105
|
path.dirname(this.keychainPath),
|
|
101
106
|
];
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {fs, timing, util} from '@appium/support';
|
|
3
2
|
import {exec} from 'teen_process';
|
|
4
3
|
import path from 'node:path';
|
|
5
|
-
import B from 'bluebird';
|
|
6
4
|
import {waitForCondition} from 'asyncbox';
|
|
7
5
|
import type {CoreSimulator, SupportsAppPermissions} from '../types';
|
|
8
6
|
import type {StringRecord} from '@appium/types';
|
|
@@ -99,17 +97,17 @@ export async function getPermission(
|
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
function toInternalServiceName(serviceName: string): string {
|
|
102
|
-
const lowerName =
|
|
103
|
-
if (
|
|
100
|
+
const lowerName = serviceName.toLowerCase();
|
|
101
|
+
if (lowerName in SERVICES) {
|
|
104
102
|
return SERVICES[lowerName as keyof typeof SERVICES] as string;
|
|
105
103
|
}
|
|
106
104
|
throw new Error(
|
|
107
|
-
`'${serviceName}' is unknown. Only the following service names are supported: ${JSON.stringify(
|
|
105
|
+
`'${serviceName}' is unknown. Only the following service names are supported: ${JSON.stringify(Object.keys(SERVICES))}`,
|
|
108
106
|
);
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
function formatStatus(status: string): string {
|
|
112
|
-
return status === STATUS.UNSET || status === STATUS.NO ?
|
|
110
|
+
return status === STATUS.UNSET || status === STATUS.NO ? status.toUpperCase() : status;
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
/**
|
|
@@ -190,7 +188,7 @@ async function setAccess(
|
|
|
190
188
|
} else {
|
|
191
189
|
// xcrun simctl privacy expects to be lower case while AppleSimulatorUtils is upper case.
|
|
192
190
|
// To keep the compatibility, we should convert here to lower case explicitly.
|
|
193
|
-
switch (
|
|
191
|
+
switch (permissionsMapping[serviceName]?.toLowerCase()) {
|
|
194
192
|
case STATUS.YES:
|
|
195
193
|
grantPermissions.push(serviceName);
|
|
196
194
|
break;
|
|
@@ -210,7 +208,7 @@ async function setAccess(
|
|
|
210
208
|
|
|
211
209
|
const permissionPromises: Promise<any>[] = [];
|
|
212
210
|
|
|
213
|
-
if (
|
|
211
|
+
if (grantPermissions.length > 0) {
|
|
214
212
|
this.log.debug(
|
|
215
213
|
`Granting ${util.pluralize('permission', grantPermissions.length, false)} for ${bundleId}: ${grantPermissions}`,
|
|
216
214
|
);
|
|
@@ -219,7 +217,7 @@ async function setAccess(
|
|
|
219
217
|
}
|
|
220
218
|
}
|
|
221
219
|
|
|
222
|
-
if (
|
|
220
|
+
if (revokePermissions.length > 0) {
|
|
223
221
|
this.log.debug(
|
|
224
222
|
`Revoking ${util.pluralize('permission', revokePermissions.length, false)} for ${bundleId}: ${revokePermissions}`,
|
|
225
223
|
);
|
|
@@ -228,7 +226,7 @@ async function setAccess(
|
|
|
228
226
|
}
|
|
229
227
|
}
|
|
230
228
|
|
|
231
|
-
if (
|
|
229
|
+
if (resetPermissions.length > 0) {
|
|
232
230
|
this.log.debug(
|
|
233
231
|
`Resetting ${util.pluralize('permission', resetPermissions.length, false)} for ${bundleId}: ${resetPermissions}`,
|
|
234
232
|
);
|
|
@@ -237,16 +235,16 @@ async function setAccess(
|
|
|
237
235
|
}
|
|
238
236
|
}
|
|
239
237
|
|
|
240
|
-
if (
|
|
241
|
-
await
|
|
238
|
+
if (permissionPromises.length > 0) {
|
|
239
|
+
await Promise.all(permissionPromises);
|
|
242
240
|
}
|
|
243
241
|
|
|
244
|
-
if (
|
|
242
|
+
if (Object.keys(wixPermissions).length > 0) {
|
|
245
243
|
this.log.debug(
|
|
246
244
|
`Setting permissions for ${bundleId} wit ${WIX_SIM_UTILS} as ${JSON.stringify(wixPermissions)}`,
|
|
247
245
|
);
|
|
248
|
-
const permissionsArg =
|
|
249
|
-
.map((
|
|
246
|
+
const permissionsArg = Object.entries(wixPermissions)
|
|
247
|
+
.map(([name, status]) => `${name}=${formatStatus(status)}`)
|
|
250
248
|
.join(',');
|
|
251
249
|
const execWixFn = async () =>
|
|
252
250
|
await execWix.bind(this)([
|
|
@@ -257,8 +255,8 @@ async function setAccess(
|
|
|
257
255
|
'--setPermissions',
|
|
258
256
|
permissionsArg,
|
|
259
257
|
]);
|
|
260
|
-
const shouldWaitForSystemReadiness =
|
|
261
|
-
|
|
258
|
+
const shouldWaitForSystemReadiness = SERVICES_NEED_SPRINGBOARD_RESTART.some(
|
|
259
|
+
(service) => service in wixPermissions,
|
|
262
260
|
);
|
|
263
261
|
if (shouldWaitForSystemReadiness) {
|
|
264
262
|
const [didTimeout] = await runAndWaitForSystemReadiness.bind(this)(
|
|
@@ -302,7 +300,7 @@ async function runAndWaitForSystemReadiness<T>(
|
|
|
302
300
|
async () => {
|
|
303
301
|
try {
|
|
304
302
|
const pid = (await this.ps()).find(({name}) => bundleId === name)?.pid;
|
|
305
|
-
return
|
|
303
|
+
return Number.isInteger(pid) && initialPid !== pid;
|
|
306
304
|
} catch {
|
|
307
305
|
return false;
|
|
308
306
|
}
|
|
@@ -322,7 +320,7 @@ async function runAndWaitForSystemReadiness<T>(
|
|
|
322
320
|
].map((bundleId) => initialProcesses.find(({name}) => bundleId === name)?.pid);
|
|
323
321
|
|
|
324
322
|
const result = await fn();
|
|
325
|
-
if (!
|
|
323
|
+
if (!Number.isInteger(initialSpringboardPid) || !Number.isInteger(initialSpotlightPid)) {
|
|
326
324
|
// there is no point to wait if relevant processes were not running before
|
|
327
325
|
return [false, result];
|
|
328
326
|
}
|
package/lib/extensions/safari.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import {fs, timing} from '@appium/support';
|
|
4
|
-
import B from 'bluebird';
|
|
5
3
|
import {MOBILE_SAFARI_BUNDLE_ID, SAFARI_STARTUP_TIMEOUT_MS} from '../utils';
|
|
6
4
|
import {waitForCondition} from 'asyncbox';
|
|
7
5
|
import {exec} from 'teen_process';
|
|
@@ -103,7 +101,7 @@ export async function scrubSafari(
|
|
|
103
101
|
if (!keepPrefs) {
|
|
104
102
|
deletePromises.push(fs.rimraf(path.join(libraryDir, 'Preferences', '*.plist')));
|
|
105
103
|
}
|
|
106
|
-
await
|
|
104
|
+
await Promise.all(deletePromises);
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
/**
|
|
@@ -126,7 +124,7 @@ export async function updateSafariSettings(
|
|
|
126
124
|
this: CoreSimulatorWithSafariBrowser,
|
|
127
125
|
updates: StringRecord,
|
|
128
126
|
): Promise<boolean> {
|
|
129
|
-
if (
|
|
127
|
+
if (Object.keys(updates).length === 0) {
|
|
130
128
|
return false;
|
|
131
129
|
}
|
|
132
130
|
|