iOS uitests added - #2157
iOS uitests added#2157vinotestlio wants to merge 157 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an iOS XCUITest smoke-test setup to the BitPay app, introducing a Page Object Model (POM) layer, Allure-compatible test metadata, and a GitHub Actions workflow intended to run UI tests on macOS CI and publish results (artifacts + Testlio).
Changes:
- Introduces new UI test target wiring in the Xcode project/scheme and adds an
.xctestplan. - Adds POM-style page objects and initial UI test cases (plus additional placeholder tests currently checked in as fully commented-out Swift files).
- Adds CI workflow to build/run XCUITests, convert
.xcresultto Allure artifacts, and upload results to Testlio using committed CLI config.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
testlio-cli/test-config.json |
Testlio CLI test run naming configuration. |
testlio-cli/project-config.json |
Testlio CLI project/workspace GUID configuration. |
ios/UITests/tests/test591_OnboardingCreateWallet.swift |
Active XCUITest covering onboarding wallet creation flow. |
ios/UITests/tests/test592_ImportWalletRecoveryPhrase.swift |
Active XCUITest covering wallet import via recovery phrase. |
ios/UITests/tests/test593_BTCConfirmPaymentScreen.swift |
Placeholder UI test file (currently fully commented out). |
ios/UITests/tests/test594_BasicSwapBTC_.swift |
Placeholder UI test file (currently fully commented out). |
ios/UITests/tests/test595_BasicSellBTC_.swift |
Placeholder UI test file (currently fully commented out). |
ios/UITests/tests/test596_BasicBuyBTC_.swift |
Placeholder UI test file (currently fully commented out). |
ios/UITests/pages/AddCryptoOptionPage.swift |
POM for “Select an Option” wallet/key options screen. |
ios/UITests/pages/BuyPage.swift |
POM for Buy flow entry screen. |
ios/UITests/pages/ConfirmPaymentPage.swift |
POM for confirm payment screen assertions. |
ios/UITests/pages/EnterAmountPage.swift |
POM for entering amount and continuing. |
ios/UITests/pages/HomePage.swift |
POM for onboarding/home-related controls (includes tracking prompt handler). |
ios/UITests/pages/ImportRecoveryPhrasePage.swift |
POM for import by recovery phrase. |
ios/UITests/pages/MykeyPage.swift |
POM for My Key screen validations. |
ios/UITests/pages/NewRecoveryPhrasePage.swift |
POM helper logic to parse required word indexes and fill recovery phrase fields. |
ios/UITests/pages/OnboardingPage.swift |
POM for onboarding steps (continue/skip/create key/accept terms). |
ios/UITests/pages/PortfolioBalancePage.swift |
POM for portfolio balance screen navigation actions (buy/sell/send/swap/add crypto). |
ios/UITests/pages/SelectCurrencyPage.swift |
POM for selecting currency and entering recipient address. |
ios/UITests/pages/SelectKeyToDepositPage.swift |
POM for key selection modal during buy/swap flows. |
ios/UITests/pages/SellPage.swift |
POM for Sell flow entry screen. |
ios/UITests/pages/SwapPage.swift |
POM for Swap flow entry and selections. |
ios/UITests/pages/VerifyYourPhrasePage.swift |
POM for recovery phrase verification (file/class naming mismatch). |
ios/UITests/AllureReport/AllureXCTestSupport.swift |
Allure metadata helpers and screenshot attachment helpers for XCTest. |
ios/UITests/BitPayApp.xctestplan |
UI test plan (currently references a stale/nonexistent target identifier). |
ios/BitPayAppUITests/tests/test594_BasicSwapBTC_.swift |
Placeholder UI test file (currently fully commented out). |
ios/BitPayAppUITests/tests/test595_BasicSellBTC_.swift |
Placeholder UI test file (currently fully commented out). |
ios/BitPayAppUITests/tests/test596_BasicBuyBTC_.swift |
Placeholder UI test file (currently fully commented out). |
ios/BitPayApp.xcodeproj/xcshareddata/xcschemes/BitPayApp.xcscheme |
Adds BitPayAppUITests as a testable reference in the shared scheme. |
ios/BitPayApp.xcodeproj/project.pbxproj |
Adds a new UI test target and updates project format settings. |
.github/workflows/ios-xcuitest.yml |
CI workflow to run XCUITests, generate Allure artifacts, and upload to Testlio. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…estlio/ui-tests * 'develop' of https://github.com/bitpay/bitpay-app: (78 commits) fix: use live wallet fiat balances in asset list item aggregate balance fix: better handle malformed balances ref: run portfolio math in worklet fix: preserve extrema when downsampling rate data fix: normalize PnL of first point in 'All' series ref: include hours and minutes in 'All' timeframe timestamps if shorter than 3M ref: stop truncating trailing 0s fix: do not show balance chart in wallet details if balance is 0 fix: use more granular rates for the 'All' timeframe ref: split balance history and price chart screens fix: hide gain timeframe selector when app goes to background fix: omit coin query param from rates fetches and fix pol tokens and only fetch rates for chartable assets feat: display asset balance history charts fix: fix misc ts errors ref: make 1D timeframe the default fix: prevent duplicate wallets in asset list fix: hide balance charts for testnet wallets and use smaller font size for large balances feat: add balance charts TSS: Enhancement - simplify TSS session ID format to txpId:input Braze: Fix - Ensure new users start with email notifications subscribed ... # Conflicts: # android/app/build.gradle # ios/BitPayApp.xcodeproj/project.pbxproj # ios/BitPayApp/Info.plist # package.json # src/components/checkbox/Checkbox.tsx # src/navigation/onboarding/screens/CreateKey.tsx # src/navigation/onboarding/screens/TermsOfUse.tsx # src/navigation/services/swap-crypto/components/BottomAmount.tsx # src/navigation/tabs/home/components/AssetRow.tsx # src/navigation/tabs/home/components/LinkingButtons.tsx # src/navigation/tabs/home/components/PortfolioBalance.tsx # src/navigation/tabs/home/hooks/usePortfolioAssetRows.ts # src/navigation/tabs/settings/about/screens/PortfolioWalletDebug.tsx # src/navigation/wallet/screens/WalletDetails.tsx # src/store/wallet/effects/tss-send/tss-send.ts
…estlio/ui-tests * 'develop' of https://github.com/bitpay/bitpay-app: TSS: Fix - Cancel ceremony when unmounting mid-join (new-join path) TSS: Fix - Prevent keygen endpoint spam from leaked polling intervals
…estlio/ui-tests * 'develop' of https://github.com/bitpay/bitpay-app: fix: hide balance charts and asset lists if no non-zero balance wallets fix: use correct bwc version for tx history requests
- Cache iOS Pods dependencies using Podfile.lock to reduce network requests - Add retry mechanism (3 attempts with 30s backoff) to handle 429 rate limit errors from Sumsub Maven repository - Improves reliability and speeds up pod installation on subsequent runs
73fa342 to
86ed6ab
Compare
There was a problem hiding this comment.
The branch merged master while targeting develop, so GitHub's "Files changed" tab is computed against a stale merge base and does not show all of the production changes — src/navigation/wallet/screens/send/SendTo.tsx is missing from it entirely. Diff against the real merge base (git diff $(git merge-base upstream/develop <branch>) <branch>) to see them: 66 files, not 205.
Blocking
1. SendTo.tsx — the new email regex is a catastrophic-backtracking hang in the Send flow
src/navigation/wallet/screens/send/SendTo.tsx:157
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(text);
+ const reg = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w\w+)+$/;
+ return reg.test(text);The replacement has nested quantifiers ((\w+)* twice). Measured on Node 22:
| input | new regex | old regex |
|---|---|---|
"a"*18 + "@" + "a"*18 + "!" |
77,724 ms | < 0.01 ms |
"a"*20 + "@" + "a"*20 + "!" |
did not finish in 2 min | < 0.01 ms |
It's reachable on the hot path. isEmailAddress is called from validateAndNavigateToConfirm, which is wired to:
SendTo.tsx:629—SearchInputonChangeText, i.e. every keystroke in "Search contact or enter address"SendTo.tsx:647—onScanComplete, i.e. whatever a scanned QR code contains
So a signed-in user typing or pasting any <word chars>@<word chars><non-word> string into the Send recipient field freezes the JS thread, and a hostile QR code does it without the user typing anything. The old pattern has no nested quantifier and cannot backtrack this way.
It's also a behaviour regression independent of the hang — measured, user+tag@example.com returns true under the old regex and false under the new one, so plus-addressed recipients stop being recognised.
I can't find anything in this PR that needs this change. Please revert the hunk. Worth flagging: this file merges into develop cleanly — no conflict — so it would land silently.
2. Generated yarn set:dev output was committed
Three separate production-reaching defects share one root cause. yarn set:dev runs yarn set-all (which rewrites the pbxproj) and then scripts/dev-overrides.js, and the resulting working-tree changes are in the commit.
a. android/app/src/main/res/xml/network_security_config.xml:3-4 — cleartextTrafficPermitted flipped false → true on both base-config and domain-config. scripts/dev-overrides.js:12-15 does exactly this replaceAll. The file is referenced from src/main, so this ships: it disables Android's HTTPS enforcement app-wide, in a cryptocurrency wallet, in release builds.
b. ios/BitPayApp.xcodeproj/project.pbxproj, both app configs — ALLOWED_URL_PREFIXES = "ALLOWED-URL-PREFIXES-REPLACE-ME" has been overwritten with a generated literal list in both Debug and Release. develop has 2 occurrences of that sentinel; this branch has 0. scripts/allowed-url-prefixes.js works by replacing the sentinel, so yarn set:prod is now a silent no-op and the allowlist is frozen at whatever your local set:dev produced. That list is missing the Sentry ingest domain (the script derives it from SENTRY_DSN at build time), so AllowedUrlPrefixProtocol will block Sentry in production.
c. Same file, the app target's "Bundle React Native code and images" phase — export SENTRY_DISABLE_AUTO_UPLOAD=true has been prepended, unconditionally, for every configuration. Every release archive stops uploading JS bundles and source maps, so production JS crashes arrive unsymbolicated. The workflow already sets this via $GITHUB_ENV; it doesn't need to be in the project file.
(b) and (c) independently blind production crash reporting, which is a bad thing to ship quietly.
Fix: git checkout origin/develop -- ios/BitPayApp.xcodeproj/project.pbxproj android/app/src/main/res/xml/network_security_config.xml, then re-apply only the deliberate Xcode changes (the new BitPayAppUITests target and its scheme entry). Please double-check git status before committing after any yarn set:dev.
3. android/build.gradle:56-97 — gradle.afterProject rewrites packaging for the release APK
The minSdkVersion guard is fine (:app is 30, so it never fires). The packagingOptions block has no such guard and applies to every subproject including :app, so it reaches the release APK:
pickFirstonlibhermes.so,libjsi.so,libreactnative.so,libc++_shared.so,libfbjni.so— silences duplicate-native-library errors by picking an arbitrary copy. That error is the guard against an ABI mismatch between a vendored module's copy andreact-android's; silencing it globally converts a build failure into a runtime crash that only shows up on user devices.excludes += ['META-INF/LICENSE', 'META-INF/NOTICE', 'META-INF/LICENSE.md', ...]— strips third-party licence and notice files from the shipping APK. Apache-2.0 requires NOTICE redistribution, so this is a compliance problem, not just tidiness.excludes += 'META-INF/*.kotlin_module'— can break Kotlin top-level function resolution and reflection at runtime.compileSdkVersion 36forced onto any subproject declaring < 34, compiling third-party modules against an SDK they never declared.
If this is only needed to build assembleDebugAndroidTest, please scope it — if (proj.name == 'app') plus a variant filter, or move it into the androidTest configuration. A global afterProject hook that silently rewrites every module's packaging is a lot of blast radius for a test PR, and it's also one of the 14 merge conflicts (below).
4. A real BIP39 mnemonic is committed in plaintext
hobby short divert lady spare quit act settle body town license alone — a valid mainnet BIP39 phrase, in 5 Android test files and 1 iOS test file, in a public repo.
I checked: BIP44, BIP49 and BIP84 BTC addresses and the first three m/44'/60' ETH addresses are all empty right now, so nothing is at immediate risk — but:
- The wallet is permanently burned. If anyone funds it later (and
Test596BuyBTCstep 9 literally says "tap My Key with funds available", so the suite expects it to be funded), those funds are spendable by anyone who reads this PR. - It leaves a second way:
Test592ImportWalletRecoveryPhrase.kttakesallureScreenshot("Recovery phrase entered")with the phrase on screen, and that screenshot is uploaded to Testlio and as a CI artifact. - And a third:
android-espresso.ymluploads the fulladb logcatas thedevice-logcatartifact. The workflow's own comment at line 95 says RN dev logging serialises "every dispatched action" and that "a recovery-phrase import fires hundreds of actions".DISABLE_DEVELOPMENT_LOGGING=trueis the only thing between the phrase and that artifact, on a debug build. - It will trip secret scanners, and it can't be removed by a later commit.
Please treat it as compromised, generate a fresh fixture, and inject it via a GitHub secret rather than committing it. Same for bc1q0effzahtsn685tyjppgukpvfhv37hrlm4g67ws, the hardcoded send destination — that's a live mainnet address with 5 transactions and 181,650 sat received, now publicly linked to BitPay's test infrastructure.
5. The branch doesn't merge into develop
14 conflicts: android/app/build.gradle, android/build.gradle, ios/BitPayApp/Info.plist, ios/Podfile.lock, package.json, src/lib/Braze/index.ts, src/navigation/wallet/screens/WalletDetails.tsx, AssetBalanceHistoryScreen.spec.tsx, portfolioChartVisibility.spec.tsx, app.effects.spec.ts, bitpay-id.effects.spec.ts, bitpay-id.effects.ts, wallet.spec.ts, wallet.reducer.spec.ts.
The cause is c75df96 / 7d5d0e9, which merged master into a branch targeting develop. Relative to the merge base this branch reverts test coverage that is current on develop:
src/store/wallet/utils/wallet.spec.ts— the wholebuildWalletObjblock (4 tests coveringtssKeyId/tssMetadatapropagation and thereadonlykeyId fallback)src/store/bitpay-id/bitpay-id.effects.spec.ts— 5 Cloudflare-challenge tests plus thestartLogindescribe, and the Braze merge-failure test
Those all conflict, so they can't land silently — but whoever resolves needs to take develop's side on every one of them. Please merge develop (not master) into the branch and resolve before this is reviewable.
Non-blocking, but please address
Tests that can't fail
ios/.../Test596_BasicBuyBTC_.swift:67-74— steps 10, 11 and 12 have empty bodies. The test's own description is "Best Offer → Continue With Opens Browser" and none of that is exercised or asserted. As written it passes whether or not offers load.ios/.../Test593_BTCConfirmPaymentScreen.swift:56— step "(7) Wait until the Send To screen is displayed" callsisSendToTitleDisplayed()and discards the result. No assertion.android/.../Test596BuyBTC.kt:90—verifySelectCryptoTitleDisplayed()result discarded. (Every other Androidverify*call is correctly wrapped inassertTrue— this is the one exception.)android/.../Test596BuyBTC.kt:95-105— an entireallureStepblock is commented out, so the buy test never selects a deposit wallet. Same atTest594SwapBTC.kt:128.android/.../pages/OnboardingPage.kt:194-224—verifyIUnderstandCheckbox1Displayed()returnstruewhen post-onboarding state is visible, andclickIUnderstandCheckbox1/2/3andclickAgreeAndContinueall early-return before their assertions in the same state. If a regression causes the app to skip the mandatory terms-consent screen entirely, this suite goes green. The recovery behaviour is reasonable — it just needs to live in a separately named helper that can't satisfy an assertion.ios/.../Test595_BasicSellBTC_.swift— one assertion across six steps; step "(6) Enter $30 as the sell amount" enters0.007; the described outcome ("Continue With Opens Browser") is never asserted.
ios/BitPayAppUITests/flows/AppFlows.swift:78-82 — blind coordinate taps before money flows
When goToHomeScreen can't find the portfolio button, a Home tab, or a back control, it falls through to tapping absolute screen coordinate (0.12, 0.11) and dragging from the left edge — up to 15 times, with no knowledge of what screen it's on. This runs in setUp() for the send, swap, sell and buy tests, i.e. immediately before the flows that move money. (The element-relative element.coordinate(...) calls elsewhere in the page objects are fine — this is the only absolute one.)
It also never fails: after attempts it returns silently, so the test proceeds from an unknown screen and the eventual failure points at the wrong step. An XCTFail at the end would make these much easier to debug.
iOS tests aren't isolated (Android's are)
scripts/run-tests.sh does adb shell pm clear before each Android class, and each Android money-flow test re-imports the fixture itself. The iOS side does neither: only Test592 imports the phrase, and Test593–596 call completeOnboardingIfRequired, which on clean state creates a brand-new empty random wallet rather than importing the fixture. So the iOS money-flow tests either inherit whatever Test592 left behind or run against an empty wallet, and none of them can be run individually. Given the PR is specifically about the iOS suite, this is worth fixing before merge.
Workflows
- Duplicate workflow names.
ios-xcuitest.ymlandios-xcuitest-sandbox.ymlare bothname: iOS XCUITest; both Android files are bothname: Android Espresso E2E.android-espresso.ymlthen triggers onworkflow_run: workflows: ["iOS XCUITest"], which matches either — so a manual sandbox run kicks off the Android job using the production Testlio token and project. - No success guard. That same
workflow_runhastypes: [completed]with nogithub.event.workflow_run.conclusion == 'success'check, so the Android suite runs after a failed or cancelled iOS run. workflow_runchecks out the default branch.android-espresso.yml:21is a bareactions/checkout@v4; underworkflow_runthat'smaster, not the ref the triggering run tested. Relatedly,schedule:only fires on the default branch, so the nightly won't run at all until this reachesmaster.- Colliding concurrency groups. Both iOS workflows use
e2e-ios-xcui-${{ github.ref }}and both Android ones usee2e-android-espresso-${{ github.ref }}, withcancel-in-progress: true— a manual run cancels the nightly. - "Sandbox" doesn't sandbox anything. The only difference between the two variants is which Testlio workspace receives the report. Both build identically (
cp .env.template .env.development+yarn set:dev), andsrc/constants/config.ts:41hardcodesAPP_NETWORK = Network.mainnetwith no env override, so both run on mainnet againsthttps://bitpay.comandhttps://bws.bitpay.comand hit live Changelly/Moonpay endpoints nightly. The naming implies an isolation that doesn't exist — please either rename it or wire the input through to the app config. (The send test does stop at the Confirm Payment summary and never slides to send, which is the right call.) - Broken logcat pid capture.
android-espresso.yml:167-172:android-emulator-runnersplitsscript:per line and runs each as a separatesh -c, soadb logcat ... &andecho $! > /tmp/logcat.pidare in different shells,$!is unset, andkill $(cat /tmp/logcat.pid) || trueis a silent no-op. (Metro's pid capture is fine — it's inside onerun: |block. And test failures do propagate correctly; I checked the action's source.) - Secrets inline in
run:bodies.echo "${{ secrets.SENTRY_PROPERTIES }}" > sentry.propertiesandexport RUN_API_TOKEN="${{ secrets.TESTLIO_RUN_TOKEN }}"splice secret values into the script text. Please pass them viaenv:instead. Also: Android writes real Sentry properties, iOS justtouches empty files — one of the two is wrong. - No
permissions:block on any of the four new workflows. - Empty results upload cleanly.
run-tests.shadb pull ... || true, thencp ... || true, then a "Check Allure results" step that emits::warning::and exits 0 — so total loss of results is a green step that uploads an empty archive to Testlio. - ~540 lines of near-duplicate YAML across each sandbox/scheduled pair; one workflow with an input would be much easier to keep in sync.
Timeouts and retries
RetryRulenever retries.BaseTest.kt:37documents "Defaults to 3";BaseTest.kt:50isretryCount: Int = 1;RetryRule.kt:8doesrepeat(retryCount), so1means one attempt. The rule, the ordering comment, and the screenshot-on-final-failure design are all inert as configured. Either fix the default or drop the machinery.- Very long single-element waits.
MyKeyPage.kt:25is 900,000 ms (15 min);OnboardingPage.kt:93,104,162are 600,000 ms;:199is 420,000 ms.WaitUtils.waitForViewcatchesThrowable, so if the app has crashed it retries for the full window instead of failing fast — a couple of those and the 75-minute emulator step is gone before anything reports.
Xcode project
RCTCrashTestremoved from the app target.develophas 6 references in the pbxproj; this branch has 0, whileios/RCTCrashTest.mmis still in the tree.src/lib/crash-test/index.tswill fail with "native module unavailable". Looks unintentional — probably the same pbxproj regeneration as §2.ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"deleted from both app configs (2 occurrences ondevelop, 0 here). Also looks unintentional.PRODUCT_BUNDLE_IDENTIFIER = com.test.appium.BitPayAppUITests— template leftover; should be under a BitPay identifier.IPHONEOS_DEPLOYMENT_TARGET = 26.0on the test target is what pins CI to Xcode 26.2 and iPhone 17 only.TestPlan.xctestplanis dead config — the scheme has noTestPlanReference, neither workflow passes-testPlan, and the file is in Copy Bundle Resources (project.pbxproj:423), so it ships inside the.xctestbundle as a resource rather than configuring anything.parallelizable = "YES"on the newTestableReferencewhile the suite is order-dependent and CI passes-parallel-testing-enabled NO. Anyone running the scheme from Xcode gets a broken suite.systemAttachmentLifetime/userAttachmentLifetime = "keepAlways"in the shared scheme makes every developer's local test run keep all attachments forever.
Smaller things
MainActivity.kt:51— gatingFLAG_SECUREon!BuildConfig.DEBUGis scoped to debug and doesn't affect release, so I'm fine with it in principle, but it does mean debug builds can screenshot the recovery-phrase screen. Worth a deliberate nod from someone rather than arriving inside a test PR.README.md:26-31— thenetwork_security_configexample got mangled into invalid XML (<domain-config></domain>,<trust-anchors>merged into the closing tag, the<certificates>line lost). There's also a stray# TestsH1 at the top of the file.- Android tests carry no
testlioManualTestID— all 6 iOS tests set it, 0 of 6 Android tests do, so the Android results won't link to their manual cases in Testlio. - Android and iOS aren't testing the same artifact — Android builds
assembleDebugand serves JS from a live Metro bundler overadb reverse(__DEV__true, unminified); iOS builds-configuration Releaseagainst a pre-generated--dev falsebundle. VerifyYourPhrasePage.swiftandNewRecoveryPhrasePage.swiftare dead — not referenced by any test or flow. If they're kept:extractNumbersmatches\d+against instructions that repeat each index ("2nd (2)"), yielding six indexes for three fields and then indexing past the end oftextFields; there's also a force-unwrappedRange(...)!and a hardcoded.prefix(12).SwapPage.swift:13/SellPage.swift:13wait on the global "Swap"/"Sell" static texts, whichLinkingButtons.tsxalready renders on Home — so a failed navigation satisfies the wait immediately and the test fails later in a misleading place.scripts/run-tests.shhardcodes/home/runner/work/_temp/allure-results, so it can't run locally despite living inscripts/. It's also mode100644(fine as long as it's always invoked viabash).- Missing trailing newlines on
android/build.gradle,scripts/run-tests.sh, all four workflows andandroidTest/AndroidManifest.xml. AppFlows.swift:5carries a personal name in the file header.
Relayed, not verified by me
androidTestImplementation "io.qameta.allure:allure-kotlin-*:2.4.0" (android/app/build.gradle:181) — flagged as having a path where an uncaught app RuntimeException is recorded as a passing result (allure-kotlin#81). I haven't reproduced it on an emulator, so treat it as a lead. If it holds, a crash of the app under test could be reported to Testlio as green, which would be worth pinning around.
| <!-- Set cleartextTrafficPermitted = true for development --> | ||
| <base-config cleartextTrafficPermitted="false" /> | ||
| <domain-config cleartextTrafficPermitted="false"> | ||
| <base-config cleartextTrafficPermitted="true" /> |
There was a problem hiding this comment.
Blocking. This is scripts/dev-overrides.js:12-15 output — it does exactly this replaceAll on cleartextTrafficPermitted. The file is referenced from src/main, so false -> true on base-config disables Android's HTTPS enforcement app-wide in release builds of a cryptocurrency wallet.
Please git checkout origin/develop -- android/app/src/main/res/xml/network_security_config.xml and check git status after any yarn set:dev.
| WindowManager.LayoutParams.FLAG_SECURE, | ||
| WindowManager.LayoutParams.FLAG_SECURE | ||
| ) | ||
| if (!BuildConfig.DEBUG) { |
There was a problem hiding this comment.
Non-blocking — this is correctly scoped to debug and release is unaffected, so I'm fine with it in principle.
It does mean debug builds can screenshot the recovery-phrase screen, which is a deliberate loosening of a security control arriving inside a test PR. Could you get an explicit nod from someone on the app side rather than having it ride along here?
There was a problem hiding this comment.
This change is intentionally limited to debug builds to support Espresso/Appium automation and Layout Inspector screenshots. Release builds will retain FLAG_SECURE.
Could you please direct me to the appropriate Android/app security owner for explicit approval? I’ll wait for their confirmation before proceeding.
| } | ||
| } | ||
|
|
||
| gradle.afterProject { proj -> |
There was a problem hiding this comment.
Blocking. The minSdkVersion guard is fine (:app is 30, so it never fires). The packagingOptions block below has no guard and applies to every subproject including :app, so it reaches the release APK:
pickFirstonlibhermes.so/libjsi.so/libreactnative.so/libc++_shared.so/libfbjni.sosilences the duplicate-native-library error. That error is the guard against an ABI mismatch between a vendored module's copy andreact-android's — silencing it globally turns a build failure into a runtime crash that only appears on user devices.excludes += ['META-INF/LICENSE', 'META-INF/NOTICE', ...]strips third-party licence and notice files from the shipping APK. Apache-2.0 requires NOTICE redistribution, so that's a compliance issue.excludes += 'META-INF/*.kotlin_module'can break Kotlin top-level function resolution and reflection at runtime.compileSdkVersion 36is forced onto any subproject declaring < 34, compiling third-party modules against an SDK they never declared.
If this is only needed for assembleDebugAndroidTest, please scope it — if (proj.name == 'app') plus a variant filter, or move it into the androidTest configuration. This file is also one of the 14 merge conflicts against develop.
| } | ||
|
|
||
| allureStep("Enter recovery phrase and import wallet") { | ||
| importWalletPage.enterRecoveryPhrase("hobby short divert lady spare quit act settle body town license alone") |
There was a problem hiding this comment.
Blocking. This is a valid mainnet BIP39 mnemonic committed in plaintext to a public repo — here and in 4 other Android tests and 1 iOS test.
I checked: the BIP44/49/84 BTC addresses and the first three m/44'/60' ETH addresses are all empty today, so nothing is at immediate risk. But the wallet is permanently burned, and Test596BuyBTC step 9 says "tap My Key with funds available" — so the suite expects it to be funded, and once it is, anyone who reads this PR can sweep it.
It also leaves two other ways:
- the
allureScreenshot("Recovery phrase entered")on the next line captures it on screen, and that image is uploaded to Testlio and as a CI artifact; android-espresso.ymluploads the fulladb logcatas thedevice-logcatartifact, and that workflow's own comment says RN dev logging serialises "every dispatched action" and "a recovery-phrase import fires hundreds of actions".
Please treat this phrase as compromised, generate a fresh fixture, and inject it from a GitHub secret. A secret in git history can't be removed by a later commit.
| import org.junit.runner.Description | ||
| import org.junit.runners.model.Statement | ||
|
|
||
| class RetryRule(private val retryCount: Int = 1) : TestRule { |
There was a problem hiding this comment.
repeat(retryCount) with retryCount = 1 means one attempt — so RetryRule never actually retries.
BaseTest.kt:37 documents "Defaults to 3" but BaseTest.kt:50 is retryCount: Int = 1, so the rule, the @Rule(order = ...) ordering comment, and the screenshot-on-final-failure design are all inert as configured. Either make the default match the doc or drop the machinery — right now it reads as working retry logic that isn't.
| # so a timeout or crash on a later test doesn't lose earlier results | ||
| echo "=== Pulling allure results after $TEST_CLASS ===" | ||
| mkdir -p /home/runner/work/_temp/allure-results | ||
| adb pull /sdcard/googletest/test_outputfiles/allure-results/. /home/runner/work/_temp/allure-results/ || true |
There was a problem hiding this comment.
Two things here:
/home/runner/work/_temp/...is hardcoded, so this script can't run outside a GitHub runner despite living inscripts/. Please take the output directory from an env var with a local default.- Combined with the
|| truehere, thecp ... || truein the workflow, and the "Check Allure results" step that emits::warning::and exits 0, total loss of results is a green step that then uploads an empty archive to Testlio. That last check should fail the job when no result JSON exists.
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: ["iOS XCUITest"] |
There was a problem hiding this comment.
Blocking-ish. Three problems in this trigger:
ios-xcuitest.ymlandios-xcuitest-sandbox.ymlare bothname: iOS XCUITest, so this matches either. A manual sandbox run kicks off this job using the production Testlio token and project. (Both Android files likewise sharename: Android Espresso E2E.)types: [completed]with nogithub.event.workflow_run.conclusion == 'success'guard — the Android suite runs after a failed or cancelled iOS run.- Under
workflow_run, the bareactions/checkout@v4below checks out the default branch (master), not the ref the triggering run tested. Relatedly,schedule:also only fires on the default branch, so the nightly won't run at all until this reachesmaster.
Please give the sandbox workflows distinct names, add the conclusion == 'success' guard, and check out github.event.workflow_run.head_sha explicitly.
| TESTLIO_DEVICE_ID: 363a5ce7-6cef-436c-8531-6c07195c8fe8 | ||
| run: | | ||
| if [ "${{ inputs.environment }}" = "Sandbox" ]; then | ||
| export RUN_API_TOKEN="${{ secrets.TESTLIO_RUN_TOKEN }}" |
There was a problem hiding this comment.
Two notes:
- Interpolating
${{ secrets.* }}into the body of arun:script splices the value into the script text. Please pass them viaenv:instead and reference$RUN_API_TOKEN. - The
environmentinput only picks which Testlio workspace receives the report — the app build is identical (cp .env.template .env.development+yarn set:dev), andsrc/constants/config.ts:41hardcodesAPP_NETWORK = Network.mainnetwith no env override. So "Sandbox" still runs on mainnet againsthttps://bitpay.comandhttps://bws.bitpay.comand hits live Changelly/Moonpay endpoints. Either rename it so it doesn't imply isolation, or wire the input through to the app config.
| } | ||
| } | ||
| ], | ||
| "version" : 1 |
There was a problem hiding this comment.
This test plan is never used: the scheme has no TestPlanReference/<TestPlans> and neither workflow passes -testPlan, so testTimeoutsEnabled and the attachment lifetimes here do nothing.
It's also wired into Copy Bundle Resources (project.pbxproj:423), so it ships inside the .xctest bundle as a resource rather than configuring anything. Either reference it from the scheme and pass -testPlan in CI, or drop it — and remove it from the Resources phase either way.
|
|
||
| func extractNumbers(from text: String) -> [String] { | ||
| do { | ||
| let regex = try NSRegularExpression(pattern: "\\d+") |
There was a problem hiding this comment.
This page object and NewRecoveryPhrasePage.swift aren't referenced by any test or flow, so this is currently dead code — happy for it to be dropped from the PR.
If it's kept: VerifyPhrase.tsx renders each index twice ("2nd (2)"), so \d+ yields [2,2,11,11,9,9] for three fields, and the fourth loop iteration indexes past the end of textFields. Capture only the parenthesised numbers and bounds-check both subscripts. There's also a force-unwrapped Range(...)! just below and a hardcoded .prefix(12).
Uh oh!
There was an error while loading. Please reload this page.