From e87b63fe04772bb4d3938de2ce17bd757cabfeb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20G=C3=B6rtzen?= <40467337+AlexanderG2207@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:48:16 +0100 Subject: [PATCH] Improve Snapshot Tests for Fastlane (#17) --- Apollon.xcodeproj/project.pbxproj | 28 ++-- Apollon/ApollonApp.swift | 15 +++ .../ApollonSnapshotUITests.swift | 123 +++++------------- fastlane/Snapfile | 10 +- 4 files changed, 78 insertions(+), 98 deletions(-) diff --git a/Apollon.xcodeproj/project.pbxproj b/Apollon.xcodeproj/project.pbxproj index 609f64c..fed74ff 100644 --- a/Apollon.xcodeproj/project.pbxproj +++ b/Apollon.xcodeproj/project.pbxproj @@ -421,7 +421,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -478,7 +478,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -502,7 +502,7 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Apollon/Common/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Apollon; - INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -511,7 +511,7 @@ INFOPLIST_KEY_UIStatusBarStyle = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -519,6 +519,9 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = de.tum.cit.apollon; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -539,7 +542,7 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Apollon/Common/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Apollon; - INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -548,7 +551,7 @@ INFOPLIST_KEY_UIStatusBarStyle = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -556,6 +559,9 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = de.tum.cit.apollon; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -568,10 +574,13 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = de.tum.cit.ase.apollon.ApollonSnapshotUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -585,10 +594,13 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = de.tum.cit.ase.apollon.ApollonSnapshotUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Apollon/ApollonApp.swift b/Apollon/ApollonApp.swift index b5b4fea..953f31b 100644 --- a/Apollon/ApollonApp.swift +++ b/Apollon/ApollonApp.swift @@ -4,12 +4,15 @@ import ApollonShared @main struct ApollonApp: App { + @State var snapshotColorScheme: ColorScheme? = nil + var body: some Scene { WindowGroup { DiagramListView() .onAppear { setupApp() } + .preferredColorScheme(snapshotColorScheme) } .modelContainer(checkIfMockingDiagrams()) } @@ -19,6 +22,18 @@ struct ApollonApp: App { UserDefaults.standard.set(version, forKey: "version_number") let build: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String UserDefaults.standard.set(build, forKey: "build_number") +#if DEBUG + // Sets the ColorScheme based on the "-ColorScheme" flag set during screenshot tests + // https://stackoverflow.com/questions/75745926/force-app-appearance-in-xcode-ui-tests-to-be-light-or-dark + if let flagIndex = ProcessInfo.processInfo.arguments.firstIndex(where: { $0 == "-ColorScheme" }) { + let colorScheme = ProcessInfo.processInfo.arguments[flagIndex + 1] + if colorScheme == "Light" { + self.snapshotColorScheme = ColorScheme.light + } else if colorScheme == "Dark" { + self.snapshotColorScheme = ColorScheme.dark + } + } +#endif } private func checkIfMockingDiagrams() -> ModelContainer { diff --git a/ApollonSnapshotUITests/ApollonSnapshotUITests.swift b/ApollonSnapshotUITests/ApollonSnapshotUITests.swift index ec84260..e3a7757 100644 --- a/ApollonSnapshotUITests/ApollonSnapshotUITests.swift +++ b/ApollonSnapshotUITests/ApollonSnapshotUITests.swift @@ -1,80 +1,54 @@ import XCTest -import SwiftData -@MainActor class ApollonSnapshotUITests: XCTestCase { var app: XCUIApplication! + @MainActor override func setUp() { app = XCUIApplication() setupSnapshot(app) app.launchArguments += ["-Screenshots"] } - func testTakeDarkModePortraitScreenshots() { - app.launchArguments += ["-dark_mode", "YES"] - XCUIDevice.shared.orientation = .portrait - app.launch() - - // Tap Diagram - app.buttons["DiagramNavigationButton_1"].tap() - - // Sleep - sleep(2) - - // Snapshot - snapshot("DiagramDisplayViewPortraitDarkMode") - } - - func testTakeDarkModeLandscapeScreenshots() { - app.launchArguments += ["-dark_mode", "YES"] - XCUIDevice.shared.orientation = .landscapeRight - app.launch() - - // Tap Diagram - app.buttons["DiagramNavigationButton_1"].tap() - - // Sleep - sleep(2) - - // Snapshot - snapshot("DiagramDisplayViewLandscapeDarkMode") - } - - func testTakePortraitScreenshots() { - app.launchArguments += ["-dark_mode", "NO"] - XCUIDevice.shared.orientation = .portrait + @MainActor + func testTakeScreenshots() { + if UIDevice.current.userInterfaceIdiom == .phone { + XCUIDevice.shared.orientation = .portrait + } else if UIDevice.current.userInterfaceIdiom == .pad { + XCUIDevice.shared.orientation = .landscapeRight + } + app.launchArguments += ["-ColorScheme", "Light"] app.launch() - // Snapshot - snapshot("DiagramListViewPortrait") + // Snapshot 01 + snapshot("01DiagramListView") // Tap diagram app.buttons["DiagramNavigationButton_1"].tap() // Sleep - sleep(2) + sleep(1) // Tap random location on screen to select element app.images["UMLGridBackground"].tap() - // Snapshot - snapshot("SelectElementViewPortrait") + // Snapshot 02 + snapshot("02SelectElementView") // Tap edit element button to open edit sheet app.buttons["EditElementButton"].tap() - // Snapshot - snapshot("EditElementViewPortrait") + // Snapshot 03 + snapshot("03EditElementView") // Close element edit sheet app.buttons["Done"].tap() // Tap add element button app.buttons["AddElementButton"].tap() - - // Snapshot - snapshot("DiagramDisplayViewPortrait") + + // Snapshot 04 + snapshot("04DiagramDisplayView") // Tap add element button to close menu app.buttons["AddElementButton"].forceTapElement() @@ -85,62 +59,33 @@ class ApollonSnapshotUITests: XCTestCase { // Tap export diagram button app.buttons["DiagramExportButton"].forceTapElement() - // Snapshot - snapshot("DiagramExportButtonPortrait") + // Snapshot 05 + snapshot("05DiagramExportButton") } - func testTakeLandscapeScreenshots() { - app.launchArguments += ["-dark_mode", "NO"] - XCUIDevice.shared.orientation = .landscapeRight + @MainActor + func testTakeDarkModeScreenshots() { + if UIDevice.current.userInterfaceIdiom == .phone { + XCUIDevice.shared.orientation = .portrait + } else if UIDevice.current.userInterfaceIdiom == .pad { + XCUIDevice.shared.orientation = .landscapeRight + } + app.launchArguments += ["-ColorScheme", "Dark"] app.launch() - // Snapshot - snapshot("DiagramListViewLandscape") - - // Tap diagram + // Tap Diagram app.buttons["DiagramNavigationButton_1"].tap() // Sleep - sleep(3) + sleep(1) - // Tap random location on screen to select element - app.images["UMLGridBackground"].tap() - - // Snapshot - snapshot("SelectElementViewLandscape") - - // Tap edit element button to open edit sheet - app.buttons["EditElementButton"].tap() - - // Snapshot - snapshot("EditElementViewLandscape") - - // Close element edit sheet - app.buttons["Done"].tap() - - // Tap add element button - app.buttons["AddElementButton"].tap() - - // Snapshot - snapshot("DiagramDisplayViewLandscape") - - // Tap add element button to close menu - app.buttons["AddElementButton"].forceTapElement() - - // Tap diagram menu - app.buttons["DiagramMenuButton"].forceTapElement() - - // Tap export diagram button - app.buttons["DiagramExportButton"].forceTapElement() - - // Snapshot - snapshot("DiagramExportButtonLandscape") + // Snapshot 06 + snapshot("06DiagramDisplayViewDarkMode") } } - +// Sends a tap event to a unhittable element // https://stackoverflow.com/questions/33422681/xcode-ui-test-ui-testing-failure-failed-to-scroll-to-visible-by-ax-action -// Sends a tap event to a hittable/unhittable element extension XCUIElement { func forceTapElement() { if self.isHittable { diff --git a/fastlane/Snapfile b/fastlane/Snapfile index c4d45f8..81f87e2 100644 --- a/fastlane/Snapfile +++ b/fastlane/Snapfile @@ -2,7 +2,9 @@ devices([ "iPhone 15 Pro Max", - "iPad Pro (12.9-inch) (6th generation)" + "iPhone 14 Plus", + "iPad Pro (12.9-inch) (6th generation)", + "iPad Pro (12.9-inch) (2nd generation)" ]) languages([ @@ -13,6 +15,12 @@ scheme("ApollonSnapshotUITests") output_directory("./screenshots") +ios_version '17.2' + clear_previous_screenshots(true) override_status_bar(true) + +number_of_retries(2) + +skip_open_summary(true) \ No newline at end of file