From 3768058130042d1211980d1fa3882c5fad05939e Mon Sep 17 00:00:00 2001 From: Rhishi Katoch Date: Tue, 7 Jul 2026 14:42:04 -0400 Subject: [PATCH 01/11] Update Swerkin library to Swift 6 --- .../Features/ButtonSpec.swift | 2 +- .../Features/DropdownSpec.swift | 2 +- .../Features/EndToEndSpec.swift | 2 +- .../Features/InlineEditSpec.swift | 2 +- .../Features/SwipeSpec.swift | 2 +- .../Features/TableViewSpec.swift | 2 +- .../Features/TappableSpec.swift | 2 +- .../Features/TextFieldSpec.swift | 2 +- .../Features/WaitToSeeSpec.swift | 2 +- .../TestCore/ExampleBaseScreen.swift | 7 +- .../TestCore/ExampleScreenProviders.swift | 1 + .../TestCore/ExampleTestCase.swift | 26 +++-- .../Util/UIApplication+Utils.swift | 5 +- Example/Swerkin.xcodeproj/project.pbxproj | 28 ++--- Example/Swerkin/AppDelegate.swift | 2 +- Example/Swerkin/Base.lproj/Main.storyboard | 101 +++++++++--------- .../Assertable/Assertable+ScreenObject.swift | 1 + .../Touchable/Touchable+ScreenObject.swift | 1 + .../Viewable/Viewable+ScreenObject.swift | 1 + .../Common/Actions/WaitStepDefinitions.swift | 1 + .../Common/Setup/SetupStepDefinitions.swift | 2 + .../TestCore/Screens/PresentableScreen.swift | 2 + .../TestCore/Screens/ScreenPresenter.swift | 1 + .../TestCore/Screens/ScreenProtocol.swift | 3 + .../TestCore/Screens/ScreenRenderer.swift | 1 + .../Steps/EndToEnd/StepNavigator.swift | 1 + .../Classes/TestCore/Steps/Steps.swift | 1 + 27 files changed, 115 insertions(+), 88 deletions(-) diff --git a/Example/Swerkin-UITests-Examples/Features/ButtonSpec.swift b/Example/Swerkin-UITests-Examples/Features/ButtonSpec.swift index 1ca79b6..65c0972 100644 --- a/Example/Swerkin-UITests-Examples/Features/ButtonSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/ButtonSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class ButtonSpec: ExampleTestCase { +class ButtonSpec: ExampleTestCase, @unchecked Sendable { private let enableButton = ButtonScreen.View.enableButton.accessibilityIdentifier private let disableButton = ButtonScreen.View.disableButton.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/DropdownSpec.swift b/Example/Swerkin-UITests-Examples/Features/DropdownSpec.swift index 3f6edd9..ad30166 100644 --- a/Example/Swerkin-UITests-Examples/Features/DropdownSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/DropdownSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class Dropdown: ExampleTestCase { +class Dropdown: ExampleTestCase, @unchecked Sendable { private let textField = DropdownScreen.View.textField.accessibilityIdentifier func testVerifySingleItem() { diff --git a/Example/Swerkin-UITests-Examples/Features/EndToEndSpec.swift b/Example/Swerkin-UITests-Examples/Features/EndToEndSpec.swift index 855c9f2..24692f3 100644 --- a/Example/Swerkin-UITests-Examples/Features/EndToEndSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/EndToEndSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class EndToEndSpec: ExampleTestCase { +class EndToEndSpec: ExampleTestCase, @unchecked Sendable { private let startButton = EndToEndScreen.View.startTestButton.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/InlineEditSpec.swift b/Example/Swerkin-UITests-Examples/Features/InlineEditSpec.swift index 730ee74..7850b5b 100644 --- a/Example/Swerkin-UITests-Examples/Features/InlineEditSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/InlineEditSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class InlineEditSpec: ExampleTestCase { +class InlineEditSpec: ExampleTestCase, @unchecked Sendable { private let firstNameTextField = TextFieldScreen.View.firstNameTextField.accessibilityIdentifier private let lastTextField = TextFieldScreen.View.lastNameTextField.accessibilityIdentifier private let infotextView = TextFieldScreen.View.infoTextView.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/SwipeSpec.swift b/Example/Swerkin-UITests-Examples/Features/SwipeSpec.swift index 5fd3f92..9a0cc24 100644 --- a/Example/Swerkin-UITests-Examples/Features/SwipeSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/SwipeSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class SwipeSpec: ExampleTestCase { +class SwipeSpec: ExampleTestCase, @unchecked Sendable { private let scrollView = SwipeScreen.View.scrollView.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/TableViewSpec.swift b/Example/Swerkin-UITests-Examples/Features/TableViewSpec.swift index 2575f1f..3e19c03 100644 --- a/Example/Swerkin-UITests-Examples/Features/TableViewSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/TableViewSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class TableViewSpec: ExampleTestCase { +class TableViewSpec: ExampleTestCase, @unchecked Sendable { private let headerLabel = TableViewScreen.View.headerLabel.accessibilityIdentifier private let firstCell = TableViewScreen.View.firstCell.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/TappableSpec.swift b/Example/Swerkin-UITests-Examples/Features/TappableSpec.swift index e20fc78..83be2b0 100644 --- a/Example/Swerkin-UITests-Examples/Features/TappableSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/TappableSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class TappableSpec: ExampleTestCase { +class TappableSpec: ExampleTestCase, @unchecked Sendable { private let checkBox = TappableScreen.View.checkBox.accessibilityIdentifier private let toggleSwitch = TappableScreen.View.toggleSwitch.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/TextFieldSpec.swift b/Example/Swerkin-UITests-Examples/Features/TextFieldSpec.swift index 570530b..8f10960 100644 --- a/Example/Swerkin-UITests-Examples/Features/TextFieldSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/TextFieldSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class TextFieldSpec: ExampleTestCase { +class TextFieldSpec: ExampleTestCase, @unchecked Sendable { private let firstNameTextField = TextFieldScreen.View.firstNameTextField.accessibilityIdentifier private let lastTextField = TextFieldScreen.View.lastNameTextField.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/Features/WaitToSeeSpec.swift b/Example/Swerkin-UITests-Examples/Features/WaitToSeeSpec.swift index bd322e6..2882f4d 100644 --- a/Example/Swerkin-UITests-Examples/Features/WaitToSeeSpec.swift +++ b/Example/Swerkin-UITests-Examples/Features/WaitToSeeSpec.swift @@ -7,7 +7,7 @@ import Swerkin -class WaitToSeeSpec: ExampleTestCase { +class WaitToSeeSpec: ExampleTestCase, @unchecked Sendable { private let alert = WaitToSeeScreen.View.alert.accessibilityIdentifier private let alertButton = WaitToSeeScreen.View.alertButton.accessibilityIdentifier diff --git a/Example/Swerkin-UITests-Examples/TestCore/ExampleBaseScreen.swift b/Example/Swerkin-UITests-Examples/TestCore/ExampleBaseScreen.swift index ae73e1f..f56f381 100644 --- a/Example/Swerkin-UITests-Examples/TestCore/ExampleBaseScreen.swift +++ b/Example/Swerkin-UITests-Examples/TestCore/ExampleBaseScreen.swift @@ -7,7 +7,8 @@ import Swerkin -class ExampleBaseScreen: Screen, Navigable { +@MainActor +class ExampleBaseScreen: @MainActor Screen, Navigable { final var test: BaseTestCase final let renderer: ScreenRenderer = ExampleScreenRenderer() @@ -20,8 +21,8 @@ class ExampleBaseScreen: Screen, Navigable { var trait: String { return "" } var name: String { return "" } - func create() -> UIViewController { UIViewController() } - func renderScreen() {} + @MainActor func create() -> UIViewController { UIViewController() } + @MainActor func renderScreen() {} func entryPathSegments() -> [PathSegment] { return [] } diff --git a/Example/Swerkin-UITests-Examples/TestCore/ExampleScreenProviders.swift b/Example/Swerkin-UITests-Examples/TestCore/ExampleScreenProviders.swift index a3fe0c7..74e65c6 100644 --- a/Example/Swerkin-UITests-Examples/TestCore/ExampleScreenProviders.swift +++ b/Example/Swerkin-UITests-Examples/TestCore/ExampleScreenProviders.swift @@ -7,6 +7,7 @@ import Swerkin +@MainActor public class ExampleScreenProvider: ScreenProvider { public var testReference: BaseTestCase! = nil diff --git a/Example/Swerkin-UITests-Examples/TestCore/ExampleTestCase.swift b/Example/Swerkin-UITests-Examples/TestCore/ExampleTestCase.swift index 31869ec..042e3e1 100644 --- a/Example/Swerkin-UITests-Examples/TestCore/ExampleTestCase.swift +++ b/Example/Swerkin-UITests-Examples/TestCore/ExampleTestCase.swift @@ -10,21 +10,28 @@ import Swerkin @testable import Swerkin_Example -open class ExampleTestCase: BaseTestCase { +@MainActor +open class ExampleTestCase: BaseTestCase, @unchecked Sendable { open override func setUp() { super.setUp() - - self.screenPresenter.registerScreenProvider(ExampleScreenProvider(testCase: self), for: ExamplePresentableScreen.self) + MainActor.assumeIsolated { + self.screenPresenter.registerScreenProvider(ExampleScreenProvider(testCase: self), for: ExamplePresentableScreen.self) + } + + + addTeardownBlock { @MainActor [weak self] in + guard let self else { return } + self.cleanupNavigation() + } } - - open override func tearDown() { + + @MainActor + private func cleanupNavigation() { resetNavigation { self.navigateHome() self.waitForAnimationsToFinish() } - - super.tearDown() } open override class func setUp() { @@ -35,7 +42,8 @@ open class ExampleTestCase: BaseTestCase { super.tearDown() } - private func resetNavigation(navigate: @escaping () -> Void) { + @MainActor + private func resetNavigation(navigate: @escaping @MainActor () -> Void) { if let alert = UIApplication.shared.topNavigationController()?.presentedViewController { alert.dismiss(animated: false) { navigate() } } else { @@ -43,7 +51,7 @@ open class ExampleTestCase: BaseTestCase { } } - private func navigateHome() { + @MainActor private func navigateHome() { guard let rootNavController = UIApplication.shared.rootNavigationController() else { fatalError("Failed to get rootViewController") } diff --git a/Example/Swerkin-UITests-Examples/Util/UIApplication+Utils.swift b/Example/Swerkin-UITests-Examples/Util/UIApplication+Utils.swift index da47362..e0ee6a5 100644 --- a/Example/Swerkin-UITests-Examples/Util/UIApplication+Utils.swift +++ b/Example/Swerkin-UITests-Examples/Util/UIApplication+Utils.swift @@ -9,7 +9,10 @@ import UIKit public extension UIApplication { func rootNavigationController() -> UINavigationController? { - guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { + guard let keyWindow = UIApplication.shared.connectedScenes + .compactMap ({ $0 as? UIWindowScene }) + .flatMap ({ $0.windows }) + .first (where: { $0.isKeyWindow }) else { return nil } return keyWindow.rootViewController as? UINavigationController diff --git a/Example/Swerkin.xcodeproj/project.pbxproj b/Example/Swerkin.xcodeproj/project.pbxproj index 2c6c926..bb967cf 100644 --- a/Example/Swerkin.xcodeproj/project.pbxproj +++ b/Example/Swerkin.xcodeproj/project.pbxproj @@ -717,7 +717,7 @@ SDKROOT = iphoneos; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 6.0; }; name = Debug; }; @@ -768,7 +768,7 @@ SDKROOT = iphoneos; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 6.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -780,7 +780,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 75R8QKK66M; INFOPLIST_FILE = Swerkin/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; OTHER_LDFLAGS = ( @@ -799,7 +799,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; }; name = Debug; }; @@ -810,7 +810,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 75R8QKK66M; INFOPLIST_FILE = Swerkin/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; OTHER_LDFLAGS = ( @@ -829,7 +829,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; }; name = Release; }; @@ -849,14 +849,14 @@ DEBUG_INFORMATION_FORMAT = dwarf; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Swerkin-UnitTests/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.progressive.Swerkin-UnitTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -876,12 +876,12 @@ CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Swerkin-UnitTests/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.progressive.Swerkin-UnitTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -904,7 +904,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Swerkin-UITests-Examples/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -912,7 +912,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Swerkin_Example.app/Swerkin_Example"; }; @@ -935,12 +935,12 @@ CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Swerkin-UITests-Examples/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.progressive.Swerkin-UITests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Swerkin_Example.app/Swerkin_Example"; }; diff --git a/Example/Swerkin/AppDelegate.swift b/Example/Swerkin/AppDelegate.swift index ca5ffe1..c9c7500 100644 --- a/Example/Swerkin/AppDelegate.swift +++ b/Example/Swerkin/AppDelegate.swift @@ -7,7 +7,7 @@ import UIKit -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? diff --git a/Example/Swerkin/Base.lproj/Main.storyboard b/Example/Swerkin/Base.lproj/Main.storyboard index 4e8ab92..79d00e7 100644 --- a/Example/Swerkin/Base.lproj/Main.storyboard +++ b/Example/Swerkin/Base.lproj/Main.storyboard @@ -1,9 +1,8 @@ - + - - + @@ -22,7 +21,7 @@ - - + + -