Skip to content

Commit b78edac

Browse files
test: adds iOS flask e2e tests (MetaMask#24447)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR adds iOS Flask runs along side the existing Android ones. It follows the same approach as Android does for the builds, taking advantage of the main build and repacking it with the flask code. The main`ci.yml` now passes in Built type and MetaMask environment as a parameter and the build job now takes it and builds the corresponding artifact. iOS Flask passing run: https://github.com/MetaMask/metamask-mobile/actions/runs/21626290091/job/62330880758 <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MMQA-1099 ## **Manual testing steps** No manual testing steps apply. iOS Flask passing run: [MetaMask/metamask-mobile/actions/runs/21626290091/job/62330880758](https://github.com/MetaMask/metamask-mobile/actions/runs/21626290091/job/62330880758) ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A <!-- [screenshots/recordings] --> ### **After** N/A <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes CI orchestration and artifact naming for iOS builds, plus alters iOS `bundleIdentifier` selection for `flask`, which could break E2E pipelines or repack/signing if misconfigured. > > **Overview** > Adds an **iOS Flask E2E smoke-test lane** to CI, including a new `run-e2e-smoke-tests-ios-flask.yml` workflow that repacks a `main` iOS `.app` into a `flask` build and runs `FlaskBuildTests` shards. > > Makes iOS E2E build/test workflows **parameterized by `build_type` and `metamask_environment`**, updating artifact names and `PREBUILT_IOS_APP_PATH` wiring so multiple iOS build variants can be downloaded and executed in `run-e2e-workflow.yml`. > > Updates app/test behavior to support the new lane: iOS `bundleIdentifier` now switches for `METAMASK_BUILD_TYPE=flask`, and Snap E2E tests include stability tweaks (Detox iOS WebSocket sync disable, improved tap helper, and combined preinstalled-snap test to reuse `mockServer`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f96af0a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 275dfaf commit b78edac

9 files changed

Lines changed: 262 additions & 27 deletions

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@ name: Build iOS E2E Apps
22

33
on:
44
workflow_call:
5+
outputs:
6+
app-uploaded:
7+
description: 'Whether the app was successfully uploaded'
8+
value: ${{ jobs.build-ios-apps.outputs.app-uploaded }}
9+
inputs:
10+
build_type:
11+
description: 'The type of build to perform'
12+
required: false
13+
default: 'main'
14+
type: string
15+
metamask_environment:
16+
description: 'The environment to build for'
17+
required: false
18+
default: 'qa'
19+
type: string
520

621
permissions:
722
contents: read
@@ -20,8 +35,8 @@ jobs:
2035
XCODE_BUILD_SETTINGS: 'COMPILER_INDEX_STORE_ENABLE=NO'
2136
GITHUB_CI: 'true' # This ensures it's available during pod install
2237
PLATFORM: ios
23-
METAMASK_ENVIRONMENT: qa
24-
METAMASK_BUILD_TYPE: main
38+
METAMASK_ENVIRONMENT: ${{ inputs.metamask_environment }}
39+
METAMASK_BUILD_TYPE: ${{ inputs.build_type }}
2540
IS_TEST: true
2641
E2E: 'true'
2742
IGNORE_BOXLOGS_DEVELOPMENT: true
@@ -226,7 +241,7 @@ jobs:
226241
id: upload-app
227242
uses: actions/upload-artifact@v4
228243
with:
229-
name: MetaMask.app
244+
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-MetaMask.app
230245
path: ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
231246
retention-days: 7
232247
if-no-files-found: error
@@ -239,7 +254,7 @@ jobs:
239254
if: ${{ steps.cache-restore.outputs.cache-hit == 'true' || steps.cache-restore-main.outputs.cache-hit == 'true' }}
240255
uses: actions/upload-artifact@v4
241256
with:
242-
name: index.js.map
257+
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-index.js.map
243258
path: sourcemaps/ios/index.js.map
244259
retention-days: 7
245260
if-no-files-found: error

.github/workflows/ci.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,23 @@ jobs:
382382
}}
383383
secrets: inherit
384384

385+
e2e-smoke-tests-ios-flask:
386+
name: 'iOS Flask E2E Smoke Tests'
387+
if: ${{ github.event_name != 'merge_group' && needs.needs_e2e_build.outputs.ios_changed == 'true' }}
388+
permissions:
389+
contents: read
390+
id-token: write
391+
needs: [needs_e2e_build, ios-tests-ready, smart-e2e-selection]
392+
uses: ./.github/workflows/run-e2e-smoke-tests-ios-flask.yml
393+
with:
394+
changed_files: ${{ needs.needs_e2e_build.outputs.changed_files }}
395+
selected_tags: >-
396+
${{
397+
(needs.smart-e2e-selection.outputs.ai_confidence >= 80 && needs.smart-e2e-selection.outputs.ai_e2e_test_tags) ||
398+
'["ALL"]'
399+
}}
400+
secrets: inherit
401+
385402
js-bundle-size-check:
386403
runs-on: ubuntu-latest
387404
steps:
@@ -604,6 +621,7 @@ jobs:
604621
- e2e-smoke-tests-android
605622
- e2e-smoke-tests-ios
606623
- e2e-smoke-tests-android-flask
624+
- e2e-smoke-tests-ios-flask
607625
steps:
608626
- run: |
609627
# Check if all non-E2E jobs passed
@@ -629,9 +647,15 @@ jobs:
629647
exit 1
630648
fi
631649
632-
FLASK_RESULT="${{ needs.e2e-smoke-tests-android-flask.result }}"
633-
if [[ "$FLASK_RESULT" == "failure" ]] || [[ "$FLASK_RESULT" == "cancelled" ]]; then
634-
echo "Android Flask E2E tests failed (result: $FLASK_RESULT)"
650+
ANDROID_FLASK_RESULT="${{ needs.e2e-smoke-tests-android-flask.result }}"
651+
if [[ "$ANDROID_FLASK_RESULT" == "failure" ]] || [[ "$ANDROID_FLASK_RESULT" == "cancelled" ]]; then
652+
echo "Android Flask E2E tests failed (result: $ANDROID_FLASK_RESULT)"
653+
exit 1
654+
fi
655+
656+
IOS_FLASK_RESULT="${{ needs.e2e-smoke-tests-ios-flask.result }}"
657+
if [[ "$IOS_FLASK_RESULT" == "failure" ]] || [[ "$IOS_FLASK_RESULT" == "cancelled" ]]; then
658+
echo "iOS Flask E2E tests failed (result: $IOS_FLASK_RESULT)"
635659
exit 1
636660
fi
637661
fi
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
name: iOS Flask E2E Smoke Tests
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
selected_tags:
7+
description: 'JSON array of selected tags from Smart E2E selection'
8+
required: false
9+
type: string
10+
default: '["ALL"]'
11+
changed_files:
12+
description: 'Changed files'
13+
required: false
14+
type: string
15+
default: ''
16+
17+
permissions:
18+
contents: read
19+
id-token: write
20+
21+
jobs:
22+
repack-ios-flask-apps:
23+
if: contains(fromJson(inputs.selected_tags), 'ALL') || contains(fromJson(inputs.selected_tags), 'FlaskBuildTests')
24+
name: 'Repack iOS Flask Apps'
25+
runs-on: ghcr.io/cirruslabs/macos-runner:sequoia
26+
permissions:
27+
contents: read
28+
id-token: write
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@v4
32+
33+
- name: Setup iOS Environment
34+
timeout-minutes: 15
35+
uses: MetaMask/github-tools/.github/actions/setup-e2e-env@v1
36+
with:
37+
platform: ios
38+
setup-simulator: false
39+
40+
- name: Install dependencies
41+
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2
42+
with:
43+
timeout_minutes: 10
44+
max_attempts: 3
45+
retry_wait_seconds: 30
46+
command: yarn install --immutable
47+
48+
- name: Setup project
49+
run: yarn setup:github-ci --no-build-android
50+
51+
- name: Download Main iOS App artifacts
52+
uses: actions/download-artifact@v4
53+
with:
54+
path: artifacts/
55+
pattern: main-*-MetaMask.app
56+
57+
- name: Setup Main iOS App artifacts
58+
run: |
59+
mkdir -p ios/build/Build/Products/Release-iphonesimulator/
60+
cp -R artifacts/main-qa-MetaMask.app ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
61+
62+
- name: Repack Main iOS App
63+
run: node scripts/repack.js
64+
env:
65+
PLATFORM: ios
66+
METAMASK_ENVIRONMENT: e2e
67+
METAMASK_BUILD_TYPE: flask
68+
IS_TEST: 'true'
69+
E2E: 'true'
70+
IGNORE_BOXLOGS_DEVELOPMENT: 'true'
71+
GITHUB_CI: 'true'
72+
CI: 'true'
73+
NODE_OPTIONS: '--max-old-space-size=8192'
74+
BRIDGE_USE_DEV_APIS: 'true'
75+
RAMP_INTERNAL_BUILD: 'true'
76+
SEEDLESS_ONBOARDING_ENABLED: 'true'
77+
MM_NOTIFICATIONS_UI_ENABLED: 'true'
78+
MM_SECURITY_ALERTS_API_ENABLED: 'true'
79+
FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN: ${{ secrets.FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN }}
80+
FEATURES_ANNOUNCEMENTS_SPACE_ID: ${{ secrets.FEATURES_ANNOUNCEMENTS_SPACE_ID }}
81+
SEGMENT_WRITE_KEY_QA: ${{ secrets.SEGMENT_WRITE_KEY_QA }}
82+
SEGMENT_WRITE_KEY_FLASK: ${{ secrets.SEGMENT_WRITE_KEY_FLASK }}
83+
SEGMENT_PROXY_URL_QA: ${{ secrets.SEGMENT_PROXY_URL_QA }}
84+
SEGMENT_PROXY_URL_FLASK: ${{ secrets.SEGMENT_PROXY_URL_FLASK }}
85+
SEGMENT_DELETE_API_SOURCE_ID_QA: ${{ secrets.SEGMENT_DELETE_API_SOURCE_ID_QA }}
86+
SEGMENT_DELETE_API_SOURCE_ID_FLASK: ${{ secrets.SEGMENT_DELETE_API_SOURCE_ID_FLASK }}
87+
SEGMENT_REGULATIONS_ENDPOINT_QA: ${{ secrets.SEGMENT_REGULATIONS_ENDPOINT_QA }}
88+
SEGMENT_REGULATIONS_ENDPOINT_FLASK: ${{ secrets.SEGMENT_REGULATIONS_ENDPOINT_FLASK }}
89+
MM_SENTRY_DSN_TEST: ${{ secrets.MM_SENTRY_DSN_TEST }}
90+
MM_SENTRY_AUTH_TOKEN: ${{ secrets.MM_SENTRY_AUTH_TOKEN }}
91+
MAIN_IOS_GOOGLE_CLIENT_ID_UAT: ${{ secrets.MAIN_IOS_GOOGLE_CLIENT_ID_UAT }}
92+
FLASK_IOS_GOOGLE_CLIENT_ID_PROD: ${{ secrets.FLASK_IOS_GOOGLE_CLIENT_ID_PROD }}
93+
MAIN_IOS_GOOGLE_REDIRECT_URI_UAT: ${{ secrets.MAIN_IOS_GOOGLE_REDIRECT_URI_UAT }}
94+
FLASK_IOS_GOOGLE_REDIRECT_URI_PROD: ${{ secrets.FLASK_IOS_GOOGLE_REDIRECT_URI_PROD }}
95+
MAIN_ANDROID_APPLE_CLIENT_ID_UAT: ${{ secrets.MAIN_ANDROID_APPLE_CLIENT_ID_UAT }}
96+
FLASK_ANDROID_APPLE_CLIENT_ID_PROD: ${{ secrets.FLASK_ANDROID_APPLE_CLIENT_ID_PROD }}
97+
MAIN_ANDROID_GOOGLE_CLIENT_ID_UAT: ${{ secrets.MAIN_ANDROID_GOOGLE_CLIENT_ID_UAT }}
98+
FLASK_ANDROID_GOOGLE_CLIENT_ID_PROD: ${{ secrets.FLASK_ANDROID_GOOGLE_CLIENT_ID_PROD }}
99+
MAIN_ANDROID_GOOGLE_SERVER_CLIENT_ID_UAT: ${{ secrets.MAIN_ANDROID_GOOGLE_SERVER_CLIENT_ID_UAT }}
100+
FLASK_ANDROID_GOOGLE_SERVER_CLIENT_ID_PROD: ${{ secrets.FLASK_ANDROID_GOOGLE_SERVER_CLIENT_ID_PROD }}
101+
GOOGLE_SERVICES_B64_IOS: ${{ secrets.GOOGLE_SERVICES_B64_IOS }}
102+
GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }}
103+
MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }}
104+
105+
- name: Upload Repacked iOS Flask App
106+
uses: actions/upload-artifact@v4
107+
with:
108+
name: flask-e2e-MetaMask.app
109+
path: ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
110+
retention-days: 1
111+
112+
flask-ios-smoke:
113+
if: contains(fromJson(inputs.selected_tags), 'ALL') || contains(fromJson(inputs.selected_tags), 'FlaskBuildTests')
114+
needs: [repack-ios-flask-apps]
115+
strategy:
116+
matrix:
117+
split: [1, 2, 3]
118+
fail-fast: false
119+
uses: ./.github/workflows/run-e2e-workflow.yml
120+
with:
121+
test-suite-name: flask-ios-smoke-${{ matrix.split }}
122+
platform: ios
123+
test_suite_tag: 'FlaskBuildTests'
124+
split_number: ${{ matrix.split }}
125+
total_splits: 3
126+
changed_files: ${{ inputs.changed_files }}
127+
build_type: 'flask'
128+
metamask_environment: 'e2e'
129+
secrets: inherit
130+
131+
report-ios-smoke-tests:
132+
name: Report iOS Flask Smoke Tests
133+
runs-on: ubuntu-latest
134+
if: ${{ !cancelled() && (contains(fromJson(inputs.selected_tags), 'ALL') || contains(fromJson(inputs.selected_tags), 'FlaskBuildTests')) }}
135+
needs:
136+
- flask-ios-smoke
137+
steps:
138+
- name: Checkout
139+
uses: actions/checkout@v4
140+
141+
- name: Setup Node.js
142+
uses: actions/setup-node@v4
143+
with:
144+
node-version-file: '.nvmrc'
145+
146+
- name: Download shards test artifacts (XMLs + Screenshots)
147+
uses: actions/download-artifact@v4
148+
continue-on-error: true
149+
with:
150+
path: all-test-artifacts/
151+
pattern: 'test-e2e-*-ios-*'
152+
153+
- name: Post Test Report
154+
uses: dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3
155+
with:
156+
name: 'iOS Flask E2E Smoke Test Results'
157+
path: 'all-test-artifacts/**/junit.xml'
158+
reporter: 'jest-junit'
159+
fail-on-error: false
160+
list-suites: 'failed'
161+
list-tests: 'failed'
162+
163+
- name: Upload all test artifacts (XMLs + Screenshots)
164+
uses: actions/upload-artifact@v4
165+
with:
166+
name: e2e-smoke-ios-flask-all-test-artifacts
167+
path: all-test-artifacts/

.github/workflows/run-e2e-smoke-tests-ios.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ jobs:
3333
split_number: ${{ matrix.split }}
3434
total_splits: 4
3535
changed_files: ${{ inputs.changed_files }}
36+
build_type: 'main'
37+
metamask_environment: 'qa'
3638
secrets: inherit
3739

3840
trade-ios-smoke:
@@ -49,6 +51,8 @@ jobs:
4951
split_number: ${{ matrix.split }}
5052
total_splits: 1
5153
changed_files: ${{ inputs.changed_files }}
54+
build_type: 'main'
55+
metamask_environment: 'qa'
5256
secrets: inherit
5357

5458
perps-ios-smoke:
@@ -65,6 +69,8 @@ jobs:
6569
split_number: ${{ matrix.split }}
6670
total_splits: 1
6771
changed_files: ${{ inputs.changed_files }}
72+
build_type: 'main'
73+
metamask_environment: 'qa'
6874
secrets: inherit
6975

7076
wallet-platform-ios-smoke:
@@ -81,6 +87,8 @@ jobs:
8187
split_number: ${{ matrix.split }}
8288
total_splits: 2
8389
changed_files: ${{ inputs.changed_files }}
90+
build_type: 'main'
91+
metamask_environment: 'qa'
8492
secrets: inherit
8593

8694
identity-ios-smoke:
@@ -97,6 +105,8 @@ jobs:
97105
split_number: ${{ matrix.split }}
98106
total_splits: 2
99107
changed_files: ${{ inputs.changed_files }}
108+
build_type: 'main'
109+
metamask_environment: 'qa'
100110
secrets: inherit
101111

102112
accounts-ios-smoke:
@@ -113,6 +123,8 @@ jobs:
113123
split_number: ${{ matrix.split }}
114124
total_splits: 1
115125
changed_files: ${{ inputs.changed_files }}
126+
build_type: 'main'
127+
metamask_environment: 'qa'
116128
secrets: inherit
117129

118130
network-abstraction-ios-smoke:
@@ -129,6 +141,8 @@ jobs:
129141
split_number: ${{ matrix.split }}
130142
total_splits: 2
131143
changed_files: ${{ inputs.changed_files }}
144+
build_type: 'main'
145+
metamask_environment: 'qa'
132146
secrets: inherit
133147

134148
network-expansion-ios-smoke:
@@ -145,6 +159,8 @@ jobs:
145159
split_number: ${{ matrix.split }}
146160
total_splits: 2
147161
changed_files: ${{ inputs.changed_files }}
162+
build_type: 'main'
163+
metamask_environment: 'qa'
148164
secrets: inherit
149165

150166
prediction-market-ios-smoke:
@@ -161,6 +177,8 @@ jobs:
161177
split_number: ${{ matrix.split }}
162178
total_splits: 1
163179
changed_files: ${{ inputs.changed_files }}
180+
build_type: 'main'
181+
metamask_environment: 'qa'
164182
secrets: inherit
165183

166184
card-ios-smoke:
@@ -177,6 +195,8 @@ jobs:
177195
split_number: ${{ matrix.split }}
178196
total_splits: 1
179197
changed_files: ${{ inputs.changed_files }}
198+
build_type: 'main'
199+
metamask_environment: 'qa'
180200
secrets: inherit
181201

182202
ramps-ios-smoke:
@@ -193,6 +213,8 @@ jobs:
193213
split_number: ${{ matrix.split }}
194214
total_splits: 1
195215
changed_files: ${{ inputs.changed_files }}
216+
build_type: 'main'
217+
metamask_environment: 'qa'
196218
secrets: inherit
197219

198220
multichain-api-ios-smoke:
@@ -209,6 +231,8 @@ jobs:
209231
split_number: ${{ matrix.split }}
210232
total_splits: 1
211233
changed_files: ${{ inputs.changed_files }}
234+
build_type: 'main'
235+
metamask_environment: 'qa'
212236
secrets: inherit
213237

214238
report-ios-smoke-tests:

.github/workflows/run-e2e-workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
test-apk-target-path: ${{ steps.determine-target-paths.outputs.test-apk-target-path }}
5959

6060
env:
61-
PREBUILT_IOS_APP_PATH: artifacts/MetaMask.app
61+
PREBUILT_IOS_APP_PATH: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-MetaMask.app
6262
METAMASK_ENVIRONMENT: ${{ inputs.metamask_environment }}
6363
METAMASK_BUILD_TYPE: ${{ inputs.build_type }}
6464
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

app.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ module.exports = {
8989
: 'io.metamask', // Required for @expo/repack-app Android repacking
9090
},
9191
ios: {
92-
bundleIdentifier: 'io.metamask.MetaMask',
92+
bundleIdentifier:
93+
process.env.METAMASK_BUILD_TYPE === 'flask'
94+
? 'io.metamask.MetaMask-Flask'
95+
: 'io.metamask.MetaMask', // Required for @expo/repack-app iOS repacking
9396
usesAppleSignIn: true,
9497
jsEngine: 'hermes',
9598
},

0 commit comments

Comments
 (0)