Skip to content

Commit 6ecf4f3

Browse files
committed
explicitely grant IOS Camera Permission
1 parent 1baa873 commit 6ecf4f3

3 files changed

Lines changed: 52 additions & 0 deletions

File tree

test/helpers/setup.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,44 @@ import path from 'node:path';
44
import { sleep } from './actions';
55
import { getAppId, getAppPath } from './constants';
66

7+
function getIosSimulatorUdidForSimctl(): string {
8+
try {
9+
let udid =
10+
(driver.capabilities as Record<string, unknown>)['appium:udid']?.toString() ??
11+
(driver.capabilities as Record<string, unknown>).udid?.toString() ??
12+
(driver.capabilities as Record<string, unknown>).deviceUDID?.toString() ??
13+
process.env.SIMULATOR_UDID ??
14+
'';
15+
if (udid && udid !== 'auto') return udid;
16+
} catch {
17+
/* ignore */
18+
}
19+
try {
20+
const line = execSync('xcrun simctl list devices booted', { encoding: 'utf8' });
21+
const match = line.match(/\(([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})\)/i);
22+
if (match) return match[1] ?? '';
23+
} catch {
24+
/* ignore */
25+
}
26+
return '';
27+
}
28+
29+
export function grantIOSCameraPermission(appIdParam?: string) {
30+
if (typeof driver === 'undefined' || !driver.isIOS) return;
31+
const appId = appIdParam ?? getAppId();
32+
const udid = getIosSimulatorUdidForSimctl();
33+
if (!udid) {
34+
console.warn('⚠ grantIOSCameraPermission: could not resolve simulator UDID');
35+
return;
36+
}
37+
try {
38+
execSync(`xcrun simctl privacy "${udid}" grant camera "${appId}"`, { stdio: 'ignore' });
39+
console.info(`→ Granted iOS camera permission for '${appId}' (simulator ${udid})`);
40+
} catch (error) {
41+
console.warn('⚠ grantIOSCameraPermission failed', error);
42+
}
43+
}
44+
745
export async function launchFreshApp() {
846
const appId = getAppId();
947

@@ -23,6 +61,7 @@ export async function reinstallApp() {
2361
await driver.removeApp(appId);
2462
resetBootedIOSKeychain();
2563
await driver.installApp(appPath);
64+
grantIOSCameraPermission(appId);
2665
await driver.activateApp(appId);
2766
}
2867

@@ -52,6 +91,7 @@ export async function reinstallAppFromPath(appPath: string, appId: string = getA
5291
await driver.removeApp(appId);
5392
resetBootedIOSKeychain();
5493
await driver.installApp(appPath);
94+
grantIOSCameraPermission(appId);
5595
await driver.activateApp(appId);
5696
}
5797

test/specs/migration.e2e.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { ciIt } from '../helpers/suite';
2626
import {
2727
getNativeAppPath,
2828
getRnAppPath,
29+
grantIOSCameraPermission,
2930
reinstallAppFromPath,
3031
resetBootedIOSKeychain,
3132
} from '../helpers/setup';
@@ -170,6 +171,7 @@ describe('@migration - Migration from legacy RN app to native app', () => {
170171
// Install native app
171172
console.info(`→ Installing native app from: ${getNativeAppPath()}`);
172173
await driver.installApp(getNativeAppPath());
174+
grantIOSCameraPermission();
173175
await driver.activateApp(getAppId());
174176

175177
// Restore wallet with mnemonic (uses custom flow to handle backup sheet)
@@ -194,6 +196,7 @@ describe('@migration - Migration from legacy RN app to native app', () => {
194196
// Install native app ON TOP of RN (upgrade)
195197
console.info(`→ Installing native app on top of RN: ${getNativeAppPath()}`);
196198
await driver.installApp(getNativeAppPath());
199+
grantIOSCameraPermission();
197200
await driver.activateApp(getAppId());
198201

199202
// Handle migration flow
@@ -213,6 +216,7 @@ describe('@migration - Migration from legacy RN app to native app', () => {
213216
// Install native app ON TOP of RN (upgrade)
214217
console.info(`→ Installing native app on top of RN: ${getNativeAppPath()}`);
215218
await driver.installApp(getNativeAppPath());
219+
grantIOSCameraPermission();
216220
await driver.activateApp(getAppId());
217221

218222
// Handle migration flow
@@ -234,6 +238,7 @@ describe('@migration - Migration from legacy RN app to native app', () => {
234238
// Install native app ON TOP of RN (upgrade)
235239
console.info(`→ Installing native app on top of RN: ${getNativeAppPath()}`);
236240
await driver.installApp(getNativeAppPath());
241+
grantIOSCameraPermission();
237242
await driver.activateApp(getAppId());
238243

239244
// Handle migration flow

wdio.conf.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import path from 'node:path';
22
import fs from 'node:fs';
33

4+
import { grantIOSCameraPermission } from './test/helpers/setup';
5+
46
const isAndroid = process.env.PLATFORM === 'android';
57
const iosDeviceName = process.env.SIMULATOR_NAME || 'iPhone 17';
68
const iosPlatformVersion = process.env.SIMULATOR_OS_VERSION || '26.0.1';
@@ -334,6 +336,11 @@ export const config: WebdriverIO.Config = {
334336
*/
335337
// afterAssertion: function(params) {
336338
// }
339+
before: async function () {
340+
if (!isAndroid) {
341+
grantIOSCameraPermission();
342+
}
343+
},
337344
beforeTest: async function (test) {
338345
if (process.env.RECORD_VIDEO === 'true') {
339346
const recordingOptions = isAndroid

0 commit comments

Comments
 (0)