From bdbbd877e62c28c33c4f31b1fd1b98470373c370 Mon Sep 17 00:00:00 2001 From: Mounil Kanakhara Date: Sun, 31 May 2026 12:41:50 +0530 Subject: [PATCH] feat: Add XCUITest suite and CI workflow for issue #326 - Register ScribeUITests UI testing target in Scribe.xcodeproj by directly editing project.pbxproj (no Mac available for Xcode GUI) - Add ScribeUITests to the Scribe scheme TestAction - Add Tests/UITests/ with four XCTestCase files covering app launch, Installation tab (header, download card navigation, back nav, pop-to-root on tab retap), Settings tab, and About tab - Add .github/workflows/ci_uitest.yaml running UI tests on iPhone 16 / iOS 18.5 simulator, separate from the unit test workflow Resolves #326 Signed-off-by: Mounil Kanakhara --- .github/workflows/ci_uitest.yaml | 56 ++++++++ Scribe.xcodeproj/project.pbxproj | 130 ++++++++++++++++++ .../xcshareddata/xcschemes/Scribe.xcscheme | 10 ++ Tests/UITests/AboutTabUITests.swift | 56 ++++++++ Tests/UITests/AppLaunchUITests.swift | 59 ++++++++ Tests/UITests/InstallationTabUITests.swift | 73 ++++++++++ Tests/UITests/SettingsTabUITests.swift | 44 ++++++ 7 files changed, 428 insertions(+) create mode 100644 .github/workflows/ci_uitest.yaml create mode 100644 Tests/UITests/AboutTabUITests.swift create mode 100644 Tests/UITests/AppLaunchUITests.swift create mode 100644 Tests/UITests/InstallationTabUITests.swift create mode 100644 Tests/UITests/SettingsTabUITests.swift diff --git a/.github/workflows/ci_uitest.yaml b/.github/workflows/ci_uitest.yaml new file mode 100644 index 00000000..7c95ecfc --- /dev/null +++ b/.github/workflows/ci_uitest.yaml @@ -0,0 +1,56 @@ +name: ci_uitest + +on: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + push: + branches: + - main + +jobs: + ui-test: + runs-on: macos-latest + + name: Run UI Tests + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up Xcode + run: sudo xcode-select -switch /Applications/Xcode.app + + - name: Install xcpretty + run: gem install xcpretty + + - name: Cache DerivedData + uses: actions/cache@v3 + with: + path: ~/Library/Developer/Xcode/DerivedData + key: ${{ runner.os }}-xcode-uitest-${{ hashFiles('**/project.pbxproj') }} + restore-keys: | + ${{ runner.os }}-xcode-uitest- + + - name: Build for Testing + run: | + xcodebuild build-for-testing \ + -scheme Scribe \ + -derivedDataPath Build/ \ + -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.5' \ + CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty + + - name: Run UI Tests + run: | + xcodebuild test-without-building \ + -scheme Scribe \ + -derivedDataPath Build/ \ + -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.5' \ + -only-testing:ScribeUITests \ + CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty diff --git a/Scribe.xcodeproj/project.pbxproj b/Scribe.xcodeproj/project.pbxproj index 6980936d..129f498f 100644 --- a/Scribe.xcodeproj/project.pbxproj +++ b/Scribe.xcodeproj/project.pbxproj @@ -213,6 +213,10 @@ D12EB9C52C81C10900181765 /* HEInterfaceVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12EB9B92C81C0E700181765 /* HEInterfaceVariables.swift */; }; D1362A39274C106A00C00E48 /* ColorVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B240274056D400705659 /* ColorVariables.swift */; }; D13E0DC92C86530E007F00AF /* TestExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13E0DC82C86530E007F00AF /* TestExtensions.swift */; }; + AA1B00010000000000BB0001 /* AppLaunchUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1B00010000000000AA0001 /* AppLaunchUITests.swift */; }; + AA1B00010000000000BB0002 /* InstallationTabUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1B00010000000000AA0002 /* InstallationTabUITests.swift */; }; + AA1B00010000000000BB0003 /* SettingsTabUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1B00010000000000AA0003 /* SettingsTabUITests.swift */; }; + AA1B00010000000000BB0004 /* AboutTabUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1B00010000000000AA0004 /* AboutTabUITests.swift */; }; D1608668270B6D3C00134D48 /* ESKeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1608667270B6D3C00134D48 /* ESKeyboardViewController.swift */; }; D160866C270B6D3C00134D48 /* Spanish.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D1608665270B6D3C00134D48 /* Spanish.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D16150FC2E9DBDC500131732 /* IDLanguageData.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = D16150FB2E9DBDC500131732 /* IDLanguageData.sqlite */; }; @@ -833,6 +837,13 @@ remoteGlobalIDString = 38BD212F22D5907E00C6795D; remoteInfo = Scribe; }; + AA1B00010000000000DD0001 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 38BD212822D5907E00C6795D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 38BD212F22D5907E00C6795D; + remoteInfo = Scribe; + }; D160866A270B6D3C00134D48 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 38BD212822D5907E00C6795D /* Project object */; @@ -1071,6 +1082,11 @@ D1362A37274C040F00C00E48 /* PRIVACY.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PRIVACY.txt; sourceTree = ""; }; D13E0DC62C86530E007F00AF /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D13E0DC82C86530E007F00AF /* TestExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestExtensions.swift; sourceTree = ""; }; + AA1B00010000000000AA0001 /* AppLaunchUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLaunchUITests.swift; sourceTree = ""; }; + AA1B00010000000000AA0002 /* InstallationTabUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationTabUITests.swift; sourceTree = ""; }; + AA1B00010000000000AA0003 /* SettingsTabUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTabUITests.swift; sourceTree = ""; }; + AA1B00010000000000AA0004 /* AboutTabUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutTabUITests.swift; sourceTree = ""; }; + AA1B00010000000000AA0005 /* ScribeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScribeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D155AD282BDC6CC20075B18C /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; D1608665270B6D3C00134D48 /* Spanish.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Spanish.appex; sourceTree = BUILT_PRODUCTS_DIR; }; D1608667270B6D3C00134D48 /* ESKeyboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ESKeyboardViewController.swift; sourceTree = ""; }; @@ -1427,6 +1443,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AA1B00010000000000CC0002 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D1608662270B6D3C00134D48 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1644,6 +1667,7 @@ D1AFDFBA29CA66F40033BF27 /* Danish.appex */, D1AFE01029CA6E900033BF27 /* Hebrew.appex */, D13E0DC62C86530E007F00AF /* Tests.xctest */, + AA1B00010000000000AA0005 /* ScribeUITests.xctest */, E9FAC3932E989712008E00AC /* Indonesian.appex */, F786BB3F2F1E8F70003F7505 /* Conjugate.app */, ); @@ -1773,10 +1797,22 @@ children = ( 693150442C881DAB005F99E8 /* Scribe */, D13E0DD02C86531C007F00AF /* Keyboards */, + AA1B00010000000000FF0001 /* UITests */, ); path = Tests; sourceTree = ""; }; + AA1B00010000000000FF0001 /* UITests */ = { + isa = PBXGroup; + children = ( + AA1B00010000000000AA0001 /* AppLaunchUITests.swift */, + AA1B00010000000000AA0002 /* InstallationTabUITests.swift */, + AA1B00010000000000AA0003 /* SettingsTabUITests.swift */, + AA1B00010000000000AA0004 /* AboutTabUITests.swift */, + ); + path = UITests; + sourceTree = ""; + }; D13E0DD02C86531C007F00AF /* Keyboards */ = { isa = PBXGroup; children = ( @@ -2312,6 +2348,24 @@ productReference = D13E0DC62C86530E007F00AF /* Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + AA1B00010000000000EE0001 /* ScribeUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = AA1B000100000000001100C1 /* Build configuration list for PBXNativeTarget "ScribeUITests" */; + buildPhases = ( + AA1B00010000000000CC0001 /* Sources */, + AA1B00010000000000CC0002 /* Frameworks */, + AA1B00010000000000CC0003 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + AA1B00010000000000DD0002 /* PBXTargetDependency */, + ); + name = ScribeUITests; + productName = ScribeUITests; + productReference = AA1B00010000000000AA0005 /* ScribeUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; D1608664270B6D3C00134D48 /* Spanish */ = { isa = PBXNativeTarget; buildConfigurationList = D160866D270B6D3C00134D48 /* Build configuration list for PBXNativeTarget "Spanish" */; @@ -2657,6 +2711,7 @@ D1608664270B6D3C00134D48 /* Spanish */, D18EA8982760D4A6001E1358 /* Swedish */, D13E0DC52C86530E007F00AF /* Tests */, + AA1B00010000000000EE0001 /* ScribeUITests */, F786BAB22F1E8F70003F7505 /* Conjugate */, ); }; @@ -2719,6 +2774,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AA1B00010000000000CC0003 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D1608663270B6D3C00134D48 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -3136,6 +3198,17 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AA1B00010000000000CC0001 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AA1B00010000000000BB0001 /* AppLaunchUITests.swift in Sources */, + AA1B00010000000000BB0002 /* InstallationTabUITests.swift in Sources */, + AA1B00010000000000BB0003 /* SettingsTabUITests.swift in Sources */, + AA1B00010000000000BB0004 /* AboutTabUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D1608661270B6D3C00134D48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3695,6 +3768,11 @@ target = 38BD212F22D5907E00C6795D /* Scribe */; targetProxy = D13E0DCA2C86530E007F00AF /* PBXContainerItemProxy */; }; + AA1B00010000000000DD0002 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 38BD212F22D5907E00C6795D /* Scribe */; + targetProxy = AA1B00010000000000DD0001 /* PBXContainerItemProxy */; + }; D160866B270B6D3C00134D48 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D1608664270B6D3C00134D48 /* Spanish */; @@ -4222,6 +4300,49 @@ }; name = Release; }; + AA1B000100000000001100D1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ATJ9U3WZ27; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = be.scri.ScribeUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Scribe; + }; + name = Debug; + }; + AA1B000100000000001100D2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ATJ9U3WZ27; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = be.scri.ScribeUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Scribe; + }; + name = Release; + }; D160866E270B6D3C00134D48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4861,6 +4982,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + AA1B000100000000001100C1 /* Build configuration list for PBXNativeTarget "ScribeUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AA1B000100000000001100D1 /* Debug */, + AA1B000100000000001100D2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D160866D270B6D3C00134D48 /* Build configuration list for PBXNativeTarget "Spanish" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Scribe.xcodeproj/xcshareddata/xcschemes/Scribe.xcscheme b/Scribe.xcodeproj/xcshareddata/xcschemes/Scribe.xcscheme index 30904a80..b90a3d87 100644 --- a/Scribe.xcodeproj/xcshareddata/xcschemes/Scribe.xcscheme +++ b/Scribe.xcodeproj/xcshareddata/xcschemes/Scribe.xcscheme @@ -38,6 +38,16 @@ ReferencedContainer = "container:Scribe.xcodeproj"> + + + +