Skip to content

Commit 29afc30

Browse files
authored
e2e: add iOS 26 + XCode 26 tests (#1194)
## 📜 Description Added e2e tests assembled with XCode 26 and tested on iOS 26. ## 💡 Motivation and Context The problem with iOS 26 keyboard is that it has two states: - if app is compiled with XCode 16.4 - it will use default (iOS 18) keyboard even if device is running on iOS 26 - if app is compiled with XCode 26 and app is running on iOS 26 - it'll use new keyboard In this PR I'm covering new keyboard functionality. We want to make keyboard controller stable across all OS versions and this step is crucial in terms of guarantee that lib works in all conditions (i. e. backward compatible mode and new mode). This PR reveals some inconsistencies: - `KeyboardBackgroundView` doesn't match real keyboard background color anymore; - in rotation example yellow circle goes behind header (though I think it's safe area context problem) I also intentionally test new keyboard on iOS 26.1, because iOS 26.0 wasn't really stable (it had animation jumps etc.) I hope new tests will help me to catch bugs earlier rather than later, tough I have feeling like I'm overusing GitHub CI (now I run 6 iOS e2e jobs 🤯). I may revisit the approach later and maybe run only few jobs for PRs and all test cases when merge into main 🤷‍♂️ ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### E2E - adjusted `KeyboardExtender` threshold (after detach I can see rounded corners of keyboard) - generated assets for iPhone 16e - added config for iPhone 16e tests (iOS 26.1) ### CI - run 2 builds in parallel (XCode 16 + Xcode 26) - use separate native cache (ccache, pods) - add additional e2e tests that will cover only XCode 26 + iOS 26 configuration ## 🤔 How Has This Been Tested? Tested via this PR. ## 📸 Screenshots (if appropriate): <img width="851" height="392" alt="image" src="https://github.com/user-attachments/assets/740567e2-b999-48a2-afe2-09314ce05425" /> ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent 0f4c393 commit 29afc30

File tree

64 files changed

+48
-17
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+48
-17
lines changed

.github/workflows/ios-e2e-test.yml

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@ on:
2121
- "e2e/**"
2222
- "src/**"
2323

24+
concurrency:
25+
group: ios-e2e-${{ github.ref }}
26+
cancel-in-progress: true
27+
2428
jobs:
2529
build:
26-
name: 🏗️ Build E2E ipa
27-
runs-on: macos-15
30+
name: 🏗️ Build E2E ipa (Xcode ${{ matrix.config.xcode }})
31+
runs-on: macos-${{ matrix.config.macos }}
2832
timeout-minutes: 60
2933
env:
3034
WORKING_DIRECTORY: example
31-
concurrency:
32-
group: ios-e2e-${{ github.ref }}
33-
cancel-in-progress: true
35+
strategy:
36+
matrix:
37+
config: [{ xcode: "16.4", macos: 15 }, { xcode: "26.1", macos: 26 }]
3438
steps:
3539
- uses: actions/checkout@v4
3640
- uses: actions/setup-node@v4
@@ -39,7 +43,7 @@ jobs:
3943
cache: "yarn"
4044
- uses: maxim-lobanov/setup-xcode@v1
4145
with:
42-
xcode-version: "16.4"
46+
xcode-version: ${{ matrix.config.xcode }}
4347
- name: Get Xcode version
4448
run: xcodebuild -version
4549
- name: Save yarn cache directory path
@@ -64,7 +68,7 @@ jobs:
6468
uses: hendrikmuhs/[email protected]
6569
with:
6670
max-size: 1.5G
67-
key: ${{ runner.os }}-ccache-e2e-ios
71+
key: ${{ runner.os }}-xcode-${{ matrix.config.xcode }}-ccache-e2e-ios
6872
create-symlink: true
6973
- name: Setup ccache behavior
7074
run: |
@@ -79,9 +83,9 @@ jobs:
7983
example/ios/Pods
8084
~/Library/Caches/CocoaPods
8185
~/.cocoapods
82-
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
86+
key: ${{ runner.os }}-xcode-${{ matrix.config.xcode }}-pods-${{ hashFiles('**/Podfile.lock') }}
8387
restore-keys: |
84-
${{ runner.os }}-pods-
88+
${{ runner.os }}-xcode-${{ matrix.config.xcode }}-pods-
8589
- name: Install pods
8690
working-directory: ${{ env.WORKING_DIRECTORY }}/ios
8791
run: export USE_CCACHE=1 && pod install || pod update --repo-update
@@ -90,17 +94,14 @@ jobs:
9094
run: yarn build-example:ios
9195
- uses: actions/upload-artifact@v4
9296
with:
93-
name: ios-e2e-ipa
97+
name: ios-e2e-ipa-xcode${{ matrix.config.xcode }}
9498
path: example/ios/build/Build/Products/Release-iphonesimulator/KeyboardControllerExample.app/**
9599
e2e-test:
96-
name: ⚙️ Automated test cases (iOS-${{ matrix.devices.ios }})
100+
name: ⚙️ Automated test cases (iOS-${{ matrix.devices.ios }}, XCode-${{ matrix.devices.xcode }})
97101
runs-on: macos-${{ matrix.devices.macos }}
98102
timeout-minutes: 90
99103
env:
100104
WORKING_DIRECTORY: example
101-
concurrency:
102-
group: ios-e2e-${{ matrix.devices.ios }}-${{ github.ref }}
103-
cancel-in-progress: true
104105
strategy:
105106
matrix:
106107
devices:
@@ -143,14 +144,21 @@ jobs:
143144
iphone: "iPhone 17 Pro",
144145
os: "26.0",
145146
},
147+
{
148+
ios: "26e",
149+
xcode: "26.1",
150+
macos: 26,
151+
iphone: "iPhone 16e",
152+
os: "26.1",
153+
},
146154
]
147155
needs: build
148156
steps:
149157
- uses: actions/checkout@v4
150158
- name: Download a single artifact
151159
uses: actions/download-artifact@v4
152160
with:
153-
name: ios-e2e-ipa
161+
name: ios-e2e-ipa-xcode${{ matrix.devices.xcode }}
154162
path: example/ios/build/Build/Products/Release-iphonesimulator/KeyboardControllerExample.app/
155163
- uses: maxim-lobanov/setup-xcode@v1
156164
with:

e2e/.detoxrc.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ module.exports = {
7676
os: "iOS 26.0",
7777
},
7878
},
79+
simulator26e: {
80+
type: "ios.simulator",
81+
device: {
82+
type: "iPhone 16e",
83+
os: "iOS 26.1",
84+
},
85+
},
7986
attached: {
8087
type: "android.attached",
8188
device: {
@@ -137,6 +144,14 @@ module.exports = {
137144
device: "simulator26",
138145
app: "example.ios.release",
139146
},
147+
"example.ios.sim-26e.debug": {
148+
device: "simulator26e",
149+
app: "example.ios.debug",
150+
},
151+
"example.ios.sim-26e.release": {
152+
device: "simulator26e",
153+
app: "example.ios.release",
154+
},
140155
"example.android.att.debug": {
141156
device: "attached",
142157
app: "example.android.debug",

e2e/kit/015-keyboard-extender.e2e.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ describe("`KeyboardExtender` specification", () => {
3030
await waitForElementByText("20 dollars");
3131
await tapItemAtIndex("OK");
3232
await waitForExpect(async () => {
33-
await expectBitmapsToBeEqual("KeyboardExtenderIsAttached");
33+
// round corners in the bottom keyboard on iOS 26 when taking second screenshot
34+
await expectBitmapsToBeEqual("KeyboardExtenderIsAttached", 0.35);
3435
});
3536
});
3637

@@ -44,7 +45,8 @@ describe("`KeyboardExtender` specification", () => {
4445
it("should appear again when enabled", async () => {
4546
await waitAndTap("donation_amount");
4647
await waitForExpect(async () => {
47-
await expectBitmapsToBeEqual("KeyboardExtenderIsAttached");
48+
// round corners in the bottom keyboard on iOS 26 when taking second screenshot
49+
await expectBitmapsToBeEqual("KeyboardExtenderIsAttached", 0.35);
4850
});
4951
});
5052
});
108 KB
108 KB
176 KB
107 KB
107 KB
175 KB
139 KB

0 commit comments

Comments
 (0)