Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 3f3b32f

Browse files
authored
Add upgrade test (#1788)
* Add upgrade tests workflow and UI test Add a GitHub Actions workflow (upgrade_tests.yml) to run upgrade verification on a self-hosted macOS runner: it creates a simulator, installs/builds an old tagged release to create a wallet, then checks out the current SHA and verifies the wallet survives the upgrade. Add a new UITest (UpgradeVerificationTests.swift) that asserts onboarding is skipped and the Bitcoin receive flow still shows the expected address. Update Gem.xcodeproj to include the new test file and extend the justfile to add test-upgrade-setup and test-upgrade-verify targets and allow running _test-ui for a specific test target. * Temporarily enable pull_request trigger for testing Add a pull_request trigger scoped to the main branch to exercise the upgrade_tests workflow on this branch. A TODO notes that the pull_request trigger should be removed before merging; workflow_dispatch inputs are unchanged. * Use xcodebuild in upgrade_tests; bump default Update the upgrade_tests GitHub Actions workflow to use explicit xcodebuild commands for resolving packages, building UI tests, and running a targeted test, replacing several just tasks. Bump the default old_version input (and related env/job name) from 1.3.327 to 1.3.335 and clarify the input description (must be >= 1.3.328). Reorganize and rename steps to separate Phase 1 (build/run old version to create wallet) and Phase 2 (build/run current version to verify), and pipe xcodebuild output through xcbeautify for cleaner CI logs. * Add waitForExistence checks to UI upgrade test Improve stability of UpgradeVerificationTests by waiting for UI elements before interacting with them. Store buttons in local variables and assert their existence with timeouts (10s for asset and action buttons, 5s for the address) to reduce flakiness when tapping elements after an app upgrade. * Adjust UI test message and wallet service mock Refines tests to improve clarity and stability. In UpgradeVerificationTests the Bitcoin asset assertion message was updated to mention 'after upgrade' and a subsequent bitcoin address existence assertion was removed (to avoid a brittle check). In WalletServiceTests the WalletService.mock is now created with an injected walletStore backed by a mocked DB pre-populated with the Ethereum chain so the test has the expected initial state for deleteLastWalletNotifiesObservers. * Update upgrade verification UI test flow Replace the old Receive->SelectAsset->Copy flow with a Wallet-detail based verification. The test now navigates to the Wallets screen, opens wallet settings (gearshape), taps Show Secret Phrase, proceeds through the security reminder, and verifies the displayed secret phrase words against UITestKitConstants. This adapts the test to the updated UI and ensures the wallet keys were not corrupted after upgrade. * Replace CI upgrade test with local script Remove GitHub Actions workflow and consolidate upgrade test into a single `just test-upgrade <commit>` command that uses git worktree for isolation. * Remove SPM cache Update build-system/scripts/upgrade-test.sh to remove explicit SPM cache and parallel build settings. Deleted OLD_SPM_CACHE and SPM_CACHE variables and removed BUILD_THREADS. Also removed -clonedSourcePackagesDirPath, -parallelizeTargets and -jobs from xcodebuild invocations, simplifying the script's build/test commands.
1 parent c13ec8e commit 3f3b32f

4 files changed

Lines changed: 124 additions & 0 deletions

File tree

Gem.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
B6B86A102D702E7C00D31D65 /* SwapNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B86A0F2D702E7C00D31D65 /* SwapNavigationView.swift */; };
6868
B6C8F2AF2EDE2691005915E4 /* UITestKitConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C8F2AD2EDE2691005915E4 /* UITestKitConstants.swift */; };
6969
B6CBBC552ED9A80B0043443B /* CreateWalletUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CBBC542ED9A80B0043443B /* CreateWalletUITests.swift */; };
70+
B6D1A0012EE3000000UPGRADE /* UpgradeVerificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D1A0002EE3000000UPGRADE /* UpgradeVerificationTests.swift */; };
7071
B6STREAM02F5000000000001 /* StreamService in Frameworks */ = {isa = PBXBuildFile; productRef = B6STREAM02F5000000000002 /* StreamService */; };
7172
C30952B4299C39D70004C0F9 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C30952B3299C39D70004C0F9 /* App.swift */; };
7273
C34C7CF829FDE942009EEC21 /* unit_frameworks.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = C34C7CF729FDE942009EEC21 /* unit_frameworks.xctestplan */; };
@@ -226,6 +227,7 @@
226227
B6B86A0F2D702E7C00D31D65 /* SwapNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapNavigationView.swift; sourceTree = "<group>"; };
227228
B6C8F2AD2EDE2691005915E4 /* UITestKitConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestKitConstants.swift; sourceTree = "<group>"; };
228229
B6CBBC542ED9A80B0043443B /* CreateWalletUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateWalletUITests.swift; sourceTree = "<group>"; };
230+
B6D1A0002EE3000000UPGRADE /* UpgradeVerificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradeVerificationTests.swift; sourceTree = "<group>"; };
229231
B6EA21D42E27E21700F1C849 /* Support */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Support; sourceTree = "<group>"; };
230232
C30952B0299C39D70004C0F9 /* Gem.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gem.app; sourceTree = BUILT_PRODUCTS_DIR; };
231233
C30952B3299C39D70004C0F9 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
@@ -567,6 +569,7 @@
567569
B68058302ED9C6F7001273D6 /* Extensions */,
568570
B69D9C852ED85EA000A04F7F /* ImportWalletReceiveBitcoinUITests.swift */,
569571
B6CBBC542ED9A80B0043443B /* CreateWalletUITests.swift */,
572+
B6D1A0002EE3000000UPGRADE /* UpgradeVerificationTests.swift */,
570573
);
571574
path = GemUITestsAppTests;
572575
sourceTree = "<group>";
@@ -1169,6 +1172,7 @@
11691172
files = (
11701173
B69D9C872ED85EA000A04F7F /* ImportWalletReceiveBitcoinUITests.swift in Sources */,
11711174
B6CBBC552ED9A80B0043443B /* CreateWalletUITests.swift in Sources */,
1175+
B6D1A0012EE3000000UPGRADE /* UpgradeVerificationTests.swift in Sources */,
11721176
B68058312ED9C6F7001273D6 /* XCTestCase+GemUITestsAppTests.swift in Sources */,
11731177
B6C8F2AF2EDE2691005915E4 /* UITestKitConstants.swift in Sources */,
11741178
B68058322ED9C6F7001273D6 /* XCUIApplication+GemUITestsAppTests.swift in Sources */,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c). Gem Wallet. All rights reserved.
2+
3+
import XCTest
4+
5+
@MainActor
6+
final class UpgradeVerificationTests: XCTestCase {
7+
8+
override func setUpWithError() throws {
9+
try super.setUpWithError()
10+
continueAfterFailure = false
11+
}
12+
13+
func testWalletSurvivedUpgrade() throws {
14+
let app = XCUIApplication()
15+
setupPermissionHandler()
16+
app.launch()
17+
18+
XCTAssertFalse(app.isOnboarding, "App should not show onboarding after upgrade — wallet data was lost")
19+
20+
// Navigate to wallet detail
21+
app.buttons["Wallet"].firstMatch.tap()
22+
app.tapWalletBar()
23+
24+
// WalletsScene
25+
let gearButton = app.buttons["gearshape"].firstMatch
26+
XCTAssertTrue(gearButton.waitForExistence(timeout: 10), "No wallets found after upgrade")
27+
gearButton.tap()
28+
29+
// WalletDetailScene
30+
let showPhraseButton = app.buttons["Show Secret Phrase"].firstMatch
31+
XCTAssertTrue(showPhraseButton.waitForExistence(timeout: 10), "Show Secret Phrase not found")
32+
showPhraseButton.tap()
33+
34+
// SecurityReminderScene
35+
app.tapContinue()
36+
37+
// ShowSecretDataScene
38+
let expectedWords = UITestKitConstants.words.components(separatedBy: " ")
39+
let displayedWords = app.getWords()
40+
XCTAssertEqual(displayedWords, expectedWords, "Secret phrase mismatch after upgrade — keys were corrupted")
41+
}
42+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
COMMIT="${1:?Usage: just upgrade-test <commit-or-tag>}"
5+
REPO_ROOT="$(git rev-parse --show-toplevel)"
6+
WORKTREE_DIR="/tmp/gem-upgrade-test-$$"
7+
SIMULATOR_NAME="${SIMULATOR_NAME:-iPhone 17}"
8+
SIMULATOR_DEST="platform=iOS Simulator,name=$SIMULATOR_NAME"
9+
OLD_DERIVED_DATA="$WORKTREE_DIR/build/DerivedData"
10+
11+
cleanup() {
12+
echo "==> Cleaning up worktree"
13+
cd "$REPO_ROOT"
14+
git worktree remove --force "$WORKTREE_DIR" 2>/dev/null || true
15+
}
16+
trap cleanup EXIT
17+
18+
echo "==> Phase 1: Build old version ($COMMIT)"
19+
20+
git worktree add "$WORKTREE_DIR" "$COMMIT"
21+
cd "$WORKTREE_DIR"
22+
git submodule update --init
23+
24+
echo "==> Generating stone (old)"
25+
just generate-stone
26+
27+
echo "==> Building old version for UI testing"
28+
set -o pipefail && xcodebuild -project Gem.xcodeproj \
29+
-scheme GemUITests \
30+
-testPlan ui_tests \
31+
ONLY_ACTIVE_ARCH=YES \
32+
-destination "$SIMULATOR_DEST" \
33+
-derivedDataPath "$OLD_DERIVED_DATA" \
34+
-allowProvisioningUpdates \
35+
-allowProvisioningDeviceRegistration \
36+
build-for-testing | xcbeautify --quieter --is-ci
37+
38+
echo "==> Resetting simulator"
39+
cd "$REPO_ROOT"
40+
just reset-simulator
41+
42+
echo "==> Running ImportWalletReceiveBitcoinUITests (old version)"
43+
cd "$WORKTREE_DIR"
44+
set -o pipefail && xcodebuild -project Gem.xcodeproj \
45+
-scheme GemUITests \
46+
-testPlan ui_tests \
47+
ONLY_ACTIVE_ARCH=YES \
48+
-destination "$SIMULATOR_DEST" \
49+
-derivedDataPath "$OLD_DERIVED_DATA" \
50+
-allowProvisioningUpdates \
51+
-allowProvisioningDeviceRegistration \
52+
-only-testing GemUITests/ImportWalletReceiveBitcoinUITests \
53+
test-without-building | xcbeautify --quieter --is-ci
54+
55+
echo "==> Phase 2: Build current version"
56+
cd "$REPO_ROOT"
57+
58+
just build-for-testing-ui
59+
60+
DERIVED_DATA="build/DerivedData"
61+
62+
echo "==> Running UpgradeVerificationTests (current version)"
63+
set -o pipefail && xcodebuild -project Gem.xcodeproj \
64+
-scheme GemUITests \
65+
-testPlan ui_tests \
66+
ONLY_ACTIVE_ARCH=YES \
67+
-destination "$SIMULATOR_DEST" \
68+
-derivedDataPath "$DERIVED_DATA" \
69+
-allowProvisioningUpdates \
70+
-allowProvisioningDeviceRegistration \
71+
-only-testing GemUITests/UpgradeVerificationTests \
72+
test-without-building | xcbeautify --quieter --is-ci
73+
74+
echo "==> Upgrade test passed!"

justfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ build-for-testing-ui: (_test-ui "build-for-testing")
138138

139139
test-ui-without-building: reset-simulator (_test-ui "test-without-building")
140140

141+
# Run full upgrade test: build old version, create wallet, build current, verify wallet survives
142+
test-upgrade COMMIT:
143+
@bash build-system/scripts/upgrade-test.sh {{COMMIT}}
144+
141145
reset-simulator NAME=SIMULATOR_NAME:
142146
@echo "==> Resetting {{NAME}} simulator to clean state"
143147
@xcrun simctl shutdown "{{NAME}}" 2>/dev/null || true

0 commit comments

Comments
 (0)