diff --git a/.xcoderc b/.xcoderc index c32b0ec5ab..dfa88c8ebb 100644 --- a/.xcoderc +++ b/.xcoderc @@ -1 +1 @@ -16.1 +26.1 diff --git a/detox/test/e2e/06.device.test.js b/detox/test/e2e/06.device.test.js index d10a7bfb54..03f9ee3cd5 100644 --- a/detox/test/e2e/06.device.test.js +++ b/detox/test/e2e/06.device.test.js @@ -54,7 +54,7 @@ describe('Device', () => { }); it('launchApp({newInstance: true}) + sendToHome() + launchApp() - should bring up previous instance', async () => { - await device.launchApp({newInstance: true}); + await device.launchApp({newInstance: true }); await element(by.text('Sanity')).tap(); await element(by.text('Say Hello')).tap(); await device.sendToHome(); @@ -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,8 +81,7 @@ 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(); await expect(element(by.text(`Current language: ${languageAndLocale.language}`))).toBeVisible(); diff --git a/detox/test/e2e/13.permissions.test.js b/detox/test/e2e/13.permissions.test.js index f2b443e21c..f7162d2f67 100644 --- a/detox/test/e2e/13.permissions.test.js +++ b/detox/test/e2e/13.permissions.test.js @@ -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); }); }); }); diff --git a/detox/test/e2e/19.crash-handling.test.js b/detox/test/e2e/19.crash-handling.test.js index 844099001b..afb93b9572 100644 --- a/detox/test/e2e/19.crash-handling.test.js +++ b/detox/test/e2e/19.crash-handling.test.js @@ -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(); }); /** diff --git a/detox/test/e2e/20.background-foreground.transitions.test.js b/detox/test/e2e/20.background-foreground.transitions.test.js index 8ffa037114..05c3c7ed4e 100644 --- a/detox/test/e2e/20.background-foreground.transitions.test.js +++ b/detox/test/e2e/20.background-foreground.transitions.test.js @@ -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(); }); }); diff --git a/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.new-arch.png b/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.new-arch.png index 690d24648c..1916139c48 100644 Binary files a/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.new-arch.png and b/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.png b/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.png index 690d24648c..a28eb828a7 100644 Binary files a/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.png and b/detox/test/e2e/assets/cross-origin-frame.clear-text.ios.png differ diff --git a/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.new-arch.png b/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.new-arch.png index 67fd49f4ba..86a3364c1d 100644 Binary files a/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.new-arch.png and b/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.png b/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.png index 67fd49f4ba..629a9f6fb1 100644 Binary files a/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.png and b/detox/test/e2e/assets/cross-origin-frame.replace-text.ios.png differ diff --git a/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.new-arch.png b/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.new-arch.png index ea5a912cb0..60494bc976 100644 Binary files a/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.new-arch.png and b/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.png b/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.png index ae785f5183..60494bc976 100644 Binary files a/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.png and b/detox/test/e2e/assets/cross-origin-frame.type-text-in.ios.png differ diff --git a/detox/test/e2e/assets/elementScreenshot.horiz.ios.new-arch.png b/detox/test/e2e/assets/elementScreenshot.horiz.ios.new-arch.png index a717ab9131..17fadc9ebb 100644 Binary files a/detox/test/e2e/assets/elementScreenshot.horiz.ios.new-arch.png and b/detox/test/e2e/assets/elementScreenshot.horiz.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/elementScreenshot.horiz.ios.png b/detox/test/e2e/assets/elementScreenshot.horiz.ios.png index a717ab9131..17fadc9ebb 100644 Binary files a/detox/test/e2e/assets/elementScreenshot.horiz.ios.png and b/detox/test/e2e/assets/elementScreenshot.horiz.ios.png differ diff --git a/detox/test/e2e/assets/elementScreenshot.vert.ios.new-arch.png b/detox/test/e2e/assets/elementScreenshot.vert.ios.new-arch.png index 4a0f483de2..01e25b13af 100644 Binary files a/detox/test/e2e/assets/elementScreenshot.vert.ios.new-arch.png and b/detox/test/e2e/assets/elementScreenshot.vert.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/elementScreenshot.vert.ios.png b/detox/test/e2e/assets/elementScreenshot.vert.ios.png index 4a0f483de2..01e25b13af 100644 Binary files a/detox/test/e2e/assets/elementScreenshot.vert.ios.png and b/detox/test/e2e/assets/elementScreenshot.vert.ios.png differ diff --git a/detox/test/e2e/assets/focus-on-content-editable-webview.ios.new-arch.png b/detox/test/e2e/assets/focus-on-content-editable-webview.ios.new-arch.png index 594ae98f83..062d9fdaee 100644 Binary files a/detox/test/e2e/assets/focus-on-content-editable-webview.ios.new-arch.png and b/detox/test/e2e/assets/focus-on-content-editable-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/focus-on-content-editable-webview.ios.png b/detox/test/e2e/assets/focus-on-content-editable-webview.ios.png index 594ae98f83..062d9fdaee 100644 Binary files a/detox/test/e2e/assets/focus-on-content-editable-webview.ios.png and b/detox/test/e2e/assets/focus-on-content-editable-webview.ios.png differ diff --git a/detox/test/e2e/assets/focus-on-input-webview.ios.new-arch.png b/detox/test/e2e/assets/focus-on-input-webview.ios.new-arch.png index 72d57fb59d..457df1f2fe 100644 Binary files a/detox/test/e2e/assets/focus-on-input-webview.ios.new-arch.png and b/detox/test/e2e/assets/focus-on-input-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/focus-on-input-webview.ios.png b/detox/test/e2e/assets/focus-on-input-webview.ios.png index 72d57fb59d..457df1f2fe 100644 Binary files a/detox/test/e2e/assets/focus-on-input-webview.ios.png and b/detox/test/e2e/assets/focus-on-input-webview.ios.png differ diff --git a/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.new-arch.png b/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.new-arch.png index 411c871412..aee58662d4 100644 Binary files a/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.new-arch.png and b/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.png b/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.png index 411c871412..aee58662d4 100644 Binary files a/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.png and b/detox/test/e2e/assets/move-cursor-to-end-content-editable-webview.ios.png differ diff --git a/detox/test/e2e/assets/move-cursor-to-end-webview.ios.new-arch.png b/detox/test/e2e/assets/move-cursor-to-end-webview.ios.new-arch.png index df61f35ba7..9cb6ca6e7e 100644 Binary files a/detox/test/e2e/assets/move-cursor-to-end-webview.ios.new-arch.png and b/detox/test/e2e/assets/move-cursor-to-end-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/move-cursor-to-end-webview.ios.png b/detox/test/e2e/assets/move-cursor-to-end-webview.ios.png index df61f35ba7..9cb6ca6e7e 100644 Binary files a/detox/test/e2e/assets/move-cursor-to-end-webview.ios.png and b/detox/test/e2e/assets/move-cursor-to-end-webview.ios.png differ diff --git a/detox/test/e2e/assets/scroll-to-view-webview.ios.new-arch.png b/detox/test/e2e/assets/scroll-to-view-webview.ios.new-arch.png index 0c132be4a2..3bc2f60b09 100644 Binary files a/detox/test/e2e/assets/scroll-to-view-webview.ios.new-arch.png and b/detox/test/e2e/assets/scroll-to-view-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/scroll-to-view-webview.ios.png b/detox/test/e2e/assets/scroll-to-view-webview.ios.png index 0c132be4a2..3bc2f60b09 100644 Binary files a/detox/test/e2e/assets/scroll-to-view-webview.ios.png and b/detox/test/e2e/assets/scroll-to-view-webview.ios.png differ diff --git a/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.new-arch.png b/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.new-arch.png index 0cf715b5ed..b651921655 100644 Binary files a/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.new-arch.png and b/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.png b/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.png index 0cf715b5ed..b651921655 100644 Binary files a/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.png and b/detox/test/e2e/assets/select-all-text-in-content-editable-webview.ios.png differ diff --git a/detox/test/e2e/assets/select-all-text-in-webview.ios.new-arch.png b/detox/test/e2e/assets/select-all-text-in-webview.ios.new-arch.png index ac8854c8b5..dd0af4d9fe 100644 Binary files a/detox/test/e2e/assets/select-all-text-in-webview.ios.new-arch.png and b/detox/test/e2e/assets/select-all-text-in-webview.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/select-all-text-in-webview.ios.png b/detox/test/e2e/assets/select-all-text-in-webview.ios.png index ac8854c8b5..dd0af4d9fe 100644 Binary files a/detox/test/e2e/assets/select-all-text-in-webview.ios.png and b/detox/test/e2e/assets/select-all-text-in-webview.ios.png differ diff --git a/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.new-arch.png b/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.new-arch.png index 15faacb276..7b50e9577c 100644 Binary files a/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.new-arch.png and b/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.new-arch.png differ diff --git a/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.png b/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.png index 15faacb276..7b50e9577c 100644 Binary files a/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.png and b/detox/test/e2e/assets/tap-on-cross-origin-frame-element.ios.png differ diff --git a/detox/test/e2e/detox.config.js b/detox/test/e2e/detox.config.js index 8864e58000..a436b1441a 100644 --- a/detox/test/e2e/detox.config.js +++ b/detox/test/e2e/detox.config.js @@ -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' }, }, diff --git a/detox/test/e2e/utils/deviceInfo.js b/detox/test/e2e/utils/deviceInfo.js new file mode 100644 index 0000000000..de6ac903a2 --- /dev/null +++ b/detox/test/e2e/utils/deviceInfo.js @@ -0,0 +1,56 @@ +/** + * Utility to get device OS version information + */ + +let cachedIOSVersion = null; + +/** + * Gets the iOS major version number + * @returns {Promise} 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} + */ +async function isIOS18OrHigher() { + const majorVersion = await getIOSMajorVersion(); + if (majorVersion === null) { + return false; + } + return majorVersion >= 18; +} + +module.exports = { + getIOSMajorVersion, + isIOS18OrHigher, +}; + + diff --git a/detox/test/ios/AppDelegate.m b/detox/test/ios/AppDelegate.m index 91877fd992..da23faaff5 100644 --- a/detox/test/ios/AppDelegate.m +++ b/detox/test/ios/AppDelegate.m @@ -30,13 +30,18 @@ - (NSURL *) bundleURL { @end #endif -@interface AppDelegate () +@interface AppDelegate () { + 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,7 +126,9 @@ - (void)handleChangeScreen:(NSNotification *)notification { } - (void)applicationDidBecomeActive:(NSNotification *)notification { - [self showOverlayMessageWithMessage:@"Active"]; + if (demoShowActiveNotification) { + [self showOverlayMessageWithMessage:@"Active"]; + } } - (void)applicationWillResignActive:(NSNotification *)notification {