diff --git a/Gem.xcodeproj/project.pbxproj b/Gem.xcodeproj/project.pbxproj index a1948d50f..7601a7520 100644 --- a/Gem.xcodeproj/project.pbxproj +++ b/Gem.xcodeproj/project.pbxproj @@ -67,6 +67,7 @@ B6B86A102D702E7C00D31D65 /* SwapNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B86A0F2D702E7C00D31D65 /* SwapNavigationView.swift */; }; B6C8F2AF2EDE2691005915E4 /* UITestKitConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C8F2AD2EDE2691005915E4 /* UITestKitConstants.swift */; }; B6CBBC552ED9A80B0043443B /* CreateWalletUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CBBC542ED9A80B0043443B /* CreateWalletUITests.swift */; }; + B6D1A0012EE3000000UPGRADE /* UpgradeVerificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D1A0002EE3000000UPGRADE /* UpgradeVerificationTests.swift */; }; B6STREAM02F5000000000001 /* StreamService in Frameworks */ = {isa = PBXBuildFile; productRef = B6STREAM02F5000000000002 /* StreamService */; }; C30952B4299C39D70004C0F9 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C30952B3299C39D70004C0F9 /* App.swift */; }; C34C7CF829FDE942009EEC21 /* unit_frameworks.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = C34C7CF729FDE942009EEC21 /* unit_frameworks.xctestplan */; }; @@ -226,6 +227,7 @@ B6B86A0F2D702E7C00D31D65 /* SwapNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapNavigationView.swift; sourceTree = ""; }; B6C8F2AD2EDE2691005915E4 /* UITestKitConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestKitConstants.swift; sourceTree = ""; }; B6CBBC542ED9A80B0043443B /* CreateWalletUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateWalletUITests.swift; sourceTree = ""; }; + B6D1A0002EE3000000UPGRADE /* UpgradeVerificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradeVerificationTests.swift; sourceTree = ""; }; B6EA21D42E27E21700F1C849 /* Support */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Support; sourceTree = ""; }; C30952B0299C39D70004C0F9 /* Gem.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gem.app; sourceTree = BUILT_PRODUCTS_DIR; }; C30952B3299C39D70004C0F9 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; @@ -567,6 +569,7 @@ B68058302ED9C6F7001273D6 /* Extensions */, B69D9C852ED85EA000A04F7F /* ImportWalletReceiveBitcoinUITests.swift */, B6CBBC542ED9A80B0043443B /* CreateWalletUITests.swift */, + B6D1A0002EE3000000UPGRADE /* UpgradeVerificationTests.swift */, ); path = GemUITestsAppTests; sourceTree = ""; @@ -1169,6 +1172,7 @@ files = ( B69D9C872ED85EA000A04F7F /* ImportWalletReceiveBitcoinUITests.swift in Sources */, B6CBBC552ED9A80B0043443B /* CreateWalletUITests.swift in Sources */, + B6D1A0012EE3000000UPGRADE /* UpgradeVerificationTests.swift in Sources */, B68058312ED9C6F7001273D6 /* XCTestCase+GemUITestsAppTests.swift in Sources */, B6C8F2AF2EDE2691005915E4 /* UITestKitConstants.swift in Sources */, B68058322ED9C6F7001273D6 /* XCUIApplication+GemUITestsAppTests.swift in Sources */, diff --git a/GemUITestsAppTests/UpgradeVerificationTests.swift b/GemUITestsAppTests/UpgradeVerificationTests.swift new file mode 100644 index 000000000..640f8010c --- /dev/null +++ b/GemUITestsAppTests/UpgradeVerificationTests.swift @@ -0,0 +1,42 @@ +// Copyright (c). Gem Wallet. All rights reserved. + +import XCTest + +@MainActor +final class UpgradeVerificationTests: XCTestCase { + + override func setUpWithError() throws { + try super.setUpWithError() + continueAfterFailure = false + } + + func testWalletSurvivedUpgrade() throws { + let app = XCUIApplication() + setupPermissionHandler() + app.launch() + + XCTAssertFalse(app.isOnboarding, "App should not show onboarding after upgrade — wallet data was lost") + + // Navigate to wallet detail + app.buttons["Wallet"].firstMatch.tap() + app.tapWalletBar() + + // WalletsScene + let gearButton = app.buttons["gearshape"].firstMatch + XCTAssertTrue(gearButton.waitForExistence(timeout: 10), "No wallets found after upgrade") + gearButton.tap() + + // WalletDetailScene + let showPhraseButton = app.buttons["Show Secret Phrase"].firstMatch + XCTAssertTrue(showPhraseButton.waitForExistence(timeout: 10), "Show Secret Phrase not found") + showPhraseButton.tap() + + // SecurityReminderScene + app.tapContinue() + + // ShowSecretDataScene + let expectedWords = UITestKitConstants.words.components(separatedBy: " ") + let displayedWords = app.getWords() + XCTAssertEqual(displayedWords, expectedWords, "Secret phrase mismatch after upgrade — keys were corrupted") + } +} diff --git a/build-system/scripts/upgrade-test.sh b/build-system/scripts/upgrade-test.sh new file mode 100755 index 000000000..f58cb38a0 --- /dev/null +++ b/build-system/scripts/upgrade-test.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -euo pipefail + +COMMIT="${1:?Usage: just upgrade-test }" +REPO_ROOT="$(git rev-parse --show-toplevel)" +WORKTREE_DIR="/tmp/gem-upgrade-test-$$" +SIMULATOR_NAME="${SIMULATOR_NAME:-iPhone 17}" +SIMULATOR_DEST="platform=iOS Simulator,name=$SIMULATOR_NAME" +OLD_DERIVED_DATA="$WORKTREE_DIR/build/DerivedData" + +cleanup() { + echo "==> Cleaning up worktree" + cd "$REPO_ROOT" + git worktree remove --force "$WORKTREE_DIR" 2>/dev/null || true +} +trap cleanup EXIT + +echo "==> Phase 1: Build old version ($COMMIT)" + +git worktree add "$WORKTREE_DIR" "$COMMIT" +cd "$WORKTREE_DIR" +git submodule update --init + +echo "==> Generating stone (old)" +just generate-stone + +echo "==> Building old version for UI testing" +set -o pipefail && xcodebuild -project Gem.xcodeproj \ + -scheme GemUITests \ + -testPlan ui_tests \ + ONLY_ACTIVE_ARCH=YES \ + -destination "$SIMULATOR_DEST" \ + -derivedDataPath "$OLD_DERIVED_DATA" \ + -allowProvisioningUpdates \ + -allowProvisioningDeviceRegistration \ + build-for-testing | xcbeautify --quieter --is-ci + +echo "==> Resetting simulator" +cd "$REPO_ROOT" +just reset-simulator + +echo "==> Running ImportWalletReceiveBitcoinUITests (old version)" +cd "$WORKTREE_DIR" +set -o pipefail && xcodebuild -project Gem.xcodeproj \ + -scheme GemUITests \ + -testPlan ui_tests \ + ONLY_ACTIVE_ARCH=YES \ + -destination "$SIMULATOR_DEST" \ + -derivedDataPath "$OLD_DERIVED_DATA" \ + -allowProvisioningUpdates \ + -allowProvisioningDeviceRegistration \ + -only-testing GemUITests/ImportWalletReceiveBitcoinUITests \ + test-without-building | xcbeautify --quieter --is-ci + +echo "==> Phase 2: Build current version" +cd "$REPO_ROOT" + +just build-for-testing-ui + +DERIVED_DATA="build/DerivedData" + +echo "==> Running UpgradeVerificationTests (current version)" +set -o pipefail && xcodebuild -project Gem.xcodeproj \ + -scheme GemUITests \ + -testPlan ui_tests \ + ONLY_ACTIVE_ARCH=YES \ + -destination "$SIMULATOR_DEST" \ + -derivedDataPath "$DERIVED_DATA" \ + -allowProvisioningUpdates \ + -allowProvisioningDeviceRegistration \ + -only-testing GemUITests/UpgradeVerificationTests \ + test-without-building | xcbeautify --quieter --is-ci + +echo "==> Upgrade test passed!" diff --git a/justfile b/justfile index 118b9046a..17bcd462e 100644 --- a/justfile +++ b/justfile @@ -138,6 +138,10 @@ build-for-testing-ui: (_test-ui "build-for-testing") test-ui-without-building: reset-simulator (_test-ui "test-without-building") +# Run full upgrade test: build old version, create wallet, build current, verify wallet survives +test-upgrade COMMIT: + @bash build-system/scripts/upgrade-test.sh {{COMMIT}} + reset-simulator NAME=SIMULATOR_NAME: @echo "==> Resetting {{NAME}} simulator to clean state" @xcrun simctl shutdown "{{NAME}}" 2>/dev/null || true