iOS 26 compatibility (#4894)
@@ -71,9 +71,6 @@ describe('Device', () => {
|
||||
};
|
||||
|
||||
await device.launchApp({newInstance: true, languageAndLocale});
|
||||
// iOS toast is hiding the element
|
||||
await waitFor(element(by.text('Language'))).toBeVisible().withTimeout(1000);
|
||||
|
||||
await element(by.text('Language')).tap();
|
||||
await expect(element(by.text(`Current locale: ${languageAndLocale.locale}`))).toBeVisible();
|
||||
await expect(element(by.text(`Current language: ${languageAndLocale.language}`))).toBeVisible();
|
||||
@@ -84,7 +81,6 @@ describe('Device', () => {
|
||||
};
|
||||
|
||||
await device.launchApp({newInstance: true, languageAndLocale});
|
||||
await waitFor(element(by.text('Language'))).toBeVisible().withTimeout(1000);
|
||||
|
||||
await element(by.text('Language')).tap();
|
||||
await expect(element(by.text(`Current locale: ${languageAndLocale.locale}`))).toBeVisible();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { RESULTS } = require('react-native-permissions');
|
||||
const { isIOS18OrHigher } = require('./utils/deviceInfo');
|
||||
|
||||
const BASIC_PERMISSIONS_TO_CHECK = [
|
||||
'userTracking',
|
||||
@@ -183,7 +184,8 @@ describe(':ios: Permissions', () => {
|
||||
await device.launchApp({ permissions, delete: true });
|
||||
await element(by.text('Permissions')).tap();
|
||||
|
||||
await expect(faceid).toHaveText(RESULTS.BLOCKED);
|
||||
// iOS 18+ changed behavior: FaceID permissions set to NO now return DENIED instead of BLOCKED
|
||||
await expect(faceid).toHaveText(isIOS18OrHigher() ? RESULTS.DENIED : RESULTS.BLOCKED);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('Crash Handling', () => {
|
||||
|
||||
it('Should recover from app crash', async () => {
|
||||
await device.launchApp({ newInstance: false });
|
||||
await expect(element(by.text('Sanity'))).toBeVisible();
|
||||
await waitFor(element(by.text('Sanity'))).toBeVisible();
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
describe(":ios: Background-Foreground Transitions", () => {
|
||||
it("Backgrounding and foregrounding an app should wait for transition to finish", async () => {
|
||||
await device.launchApp({newInstance: true});
|
||||
await device.launchApp({newInstance: true, launchArgs: { demoShowActiveNotification: true }});
|
||||
await device.sendToHome();
|
||||
await expect(element(by.text("Background"))).toExist();
|
||||
await device.launchApp({newInstance: false});
|
||||
await device.launchApp({newInstance: false, launchArgs: { demoShowActiveNotification: true }});
|
||||
await expect(element(by.text("Active"))).toExist();
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 90 KiB |
@@ -98,8 +98,8 @@ const config = {
|
||||
type: 'ios.simulator',
|
||||
headless: Boolean(process.env.CI),
|
||||
device: {
|
||||
type: 'iPhone 16 Pro Max',
|
||||
os: '18.5'
|
||||
type: 'iPhone 17 Pro',
|
||||
os: '26.1'
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Utility to get device OS version information
|
||||
*/
|
||||
|
||||
let cachedIOSVersion = null;
|
||||
|
||||
/**
|
||||
* Gets the iOS major version number
|
||||
* @returns {Promise<number|null>} The iOS major version (e.g., 17, 18, 26) or null if not iOS
|
||||
*/
|
||||
async function getIOSMajorVersion() {
|
||||
if (cachedIOSVersion !== null) {
|
||||
return cachedIOSVersion;
|
||||
}
|
||||
|
||||
try {
|
||||
const { device: deviceHandle } = require('detox');
|
||||
if (deviceHandle && deviceHandle.getPlatform && deviceHandle.getPlatform() !== 'ios') {
|
||||
cachedIOSVersion = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (deviceHandle && deviceHandle._device && deviceHandle._device.deviceConfig) {
|
||||
const osVersion = deviceHandle._device.deviceConfig.device?.os;
|
||||
if (osVersion) {
|
||||
const majorVersion = parseInt(osVersion.split('.')[0], 10);
|
||||
cachedIOSVersion = majorVersion;
|
||||
return majorVersion;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not determine iOS version, assuming iOS 18+');
|
||||
}
|
||||
|
||||
cachedIOSVersion = 18;
|
||||
return cachedIOSVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if iOS version is 18 or higher
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function isIOS18OrHigher() {
|
||||
const majorVersion = await getIOSMajorVersion();
|
||||
if (majorVersion === null) {
|
||||
return false;
|
||||
}
|
||||
return majorVersion >= 18;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getIOSMajorVersion,
|
||||
isIOS18OrHigher,
|
||||
};
|
||||
|
||||
|
||||
@@ -30,13 +30,18 @@
|
||||
@end
|
||||
#endif
|
||||
|
||||
@interface AppDelegate () <UNUserNotificationCenterDelegate>
|
||||
@interface AppDelegate () <UNUserNotificationCenterDelegate> {
|
||||
BOOL demoShowActiveNotification;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
demoShowActiveNotification = [[NSUserDefaults standardUserDefaults] boolForKey:@"demoShowActiveNotification"];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"demoShowActiveNotification"];
|
||||
|
||||
#if REACT_NATIVE_VERSION_MAJOR == 0 && REACT_NATIVE_VERSION_MINOR >= 79
|
||||
self.reactNativeDelegate = [ReactNativeDelegate new];
|
||||
self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self.reactNativeDelegate];
|
||||
@@ -121,8 +126,10 @@
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
if (demoShowActiveNotification) {
|
||||
[self showOverlayMessageWithMessage:@"Active"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(NSNotification *)notification {
|
||||
[self showOverlayMessageWithMessage:@"Inactive"];
|
||||
|
||||