diff --git a/.github/workflows/record-screenshots.yml b/.github/workflows/record-screenshots.yml index b44bd83d..32fc4854 100644 --- a/.github/workflows/record-screenshots.yml +++ b/.github/workflows/record-screenshots.yml @@ -36,7 +36,7 @@ jobs: - name: Enable screenshots recording run: | - find . -type f -name "*.swift" -exec sed -i '' 's/isRecording = false/isRecording = true/' {} + + find . -type f -name "*.swift" -exec sed -i '' 's/record: .never/record: .failed/' {} + - name: Launch tests and record screenshots run: make test @@ -44,7 +44,7 @@ jobs: - name: Disable screenshots recording run: | - find . -type f -name "*.swift" -exec sed -i '' 's/isRecording = true/isRecording = false/' {} + + find . -type f -name "*.swift" -exec sed -i '' 's/record: .failed/record: .never/' {} + - name: Commit Changes uses: stefanzweifel/git-auto-commit-action@v5 diff --git a/MisticaCatalog/Source/MisticaCatalogApp.swift b/MisticaCatalog/Source/MisticaCatalogApp.swift index 747d9087..48f425e5 100644 --- a/MisticaCatalog/Source/MisticaCatalogApp.swift +++ b/MisticaCatalog/Source/MisticaCatalogApp.swift @@ -106,15 +106,15 @@ struct MisticaCatalogApp: App { func configureFontStyle(for brandStyle: BrandStyle) { if let mapping = brandStyle.fontMapping { - FontStyle.fontNameForWeight = { weight in + FontManager.shared.fontNameForWeight = { weight in mapping.fontName(for: weight) } - FontStyle.uiFontNameForWeight = { weight in + FontManager.shared.uiFontNameForWeight = { weight in mapping.UIfontName(for: weight) } } else { - FontStyle.fontNameForWeight = nil - FontStyle.uiFontNameForWeight = nil + FontManager.shared.fontNameForWeight = nil + FontManager.shared.uiFontNameForWeight = nil } } } diff --git a/Package.swift b/Package.swift index 56c3f56d..9c0ce522 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.9 +// swift-tools-version:6.0 import PackageDescription @@ -15,7 +15,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/airbnb/lottie-spm.git", exact: "4.5.0"), - .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", exact: "1.8.2"), + .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", exact: "1.17.6"), .package(url: "https://github.com/SDWebImage/SDWebImage.git", exact: "5.19.1"), .package(url: "https://github.com/SDWebImage/SDWebImageSVGCoder.git", exact: "1.7.0") ], diff --git a/Sources/Mistica/Components/Badge/NovumBarButtonItem.swift b/Sources/Mistica/Components/Badge/NovumBarButtonItem.swift index c458e3f4..fce7f1b6 100644 --- a/Sources/Mistica/Components/Badge/NovumBarButtonItem.swift +++ b/Sources/Mistica/Components/Badge/NovumBarButtonItem.swift @@ -11,6 +11,7 @@ import UIKit /// Creates a UITabBarItem with the Badge style of Novum /// - Parameters: /// - badgeValue: The number to show in the badge or 0 for do not display it. +@MainActor public func createNovumTabBarItem(badgeValue: UInt = 0) -> UITabBarItem { let item = UITabBarItem() item.badgeColor = .badge diff --git a/Sources/Mistica/Components/Button/ButtonStyle+Toolkit.swift b/Sources/Mistica/Components/Button/ButtonStyle+Toolkit.swift index fa562d3c..3d5b3905 100644 --- a/Sources/Mistica/Components/Button/ButtonStyle+Toolkit.swift +++ b/Sources/Mistica/Components/Button/ButtonStyle+Toolkit.swift @@ -17,9 +17,9 @@ public extension Button.Style { private static var smallFont: UIFont { .textPreset2(weight: .button) } private static var linkFont: UIFont { .textPreset2(weight: .button) } - private static var regularMinimumWidth: CGFloat = 156 - private static var smallMinimumWidth: CGFloat = 104 - private static var linkMinimumWidth: CGFloat = 0 + private static let regularMinimumWidth: CGFloat = 156 + private static let smallMinimumWidth: CGFloat = 104 + private static let linkMinimumWidth: CGFloat = 0 private enum ImageHeight { static let regular: CGFloat = 24 diff --git a/Sources/Mistica/Components/Callout/Callout.swift b/Sources/Mistica/Components/Callout/Callout.swift index 11c95695..9a695611 100644 --- a/Sources/Mistica/Components/Callout/Callout.swift +++ b/Sources/Mistica/Components/Callout/Callout.swift @@ -31,7 +31,7 @@ public class Callout: UIView { if let contentConfiguration = contentConfiguration { configure(withConfiguration: contentConfiguration) } else { - configure(withConfiguration: .emptyConfiguration) + configure(withConfiguration: .emptyConfiguration()) } } } diff --git a/Sources/Mistica/Components/Callout/CalloutConfiguration.swift b/Sources/Mistica/Components/Callout/CalloutConfiguration.swift index a31fb4b9..549da86e 100644 --- a/Sources/Mistica/Components/Callout/CalloutConfiguration.swift +++ b/Sources/Mistica/Components/Callout/CalloutConfiguration.swift @@ -10,7 +10,9 @@ import Foundation import UIKit public struct CalloutConfiguration { - static let emptyConfiguration = CalloutConfiguration(asset: .none, title: nil, description: "Empty configuration", actions: nil, canClose: true) + public static func emptyConfiguration() -> CalloutConfiguration { + CalloutConfiguration(asset: .none, title: nil, description: "Empty configuration", actions: nil, canClose: true) + } public enum CalloutActions { case primary(CalloutButton) diff --git a/Sources/Mistica/Components/Callout/Internals/CalloutContentBase.swift b/Sources/Mistica/Components/Callout/Internals/CalloutContentBase.swift index 15ceb452..69170971 100644 --- a/Sources/Mistica/Components/Callout/Internals/CalloutContentBase.swift +++ b/Sources/Mistica/Components/Callout/Internals/CalloutContentBase.swift @@ -51,10 +51,10 @@ extension CalloutContentBase { var descriptionTitle: String { get { - calloutBaseView.messagesView.description + calloutBaseView.messagesView.calloutDescription } set { - calloutBaseView.messagesView.description = newValue + calloutBaseView.messagesView.calloutDescription = newValue } } @@ -107,7 +107,7 @@ extension CalloutContentBase { } calloutBaseView.title = configuration.title - calloutBaseView.description = configuration.description + calloutBaseView.calloutTitleDescription = configuration.description switch configuration.actions { case let .primary(primaryButton): diff --git a/Sources/Mistica/Components/Callout/Internals/CalloutMessagesContent.swift b/Sources/Mistica/Components/Callout/Internals/CalloutMessagesContent.swift index 24468023..70b464bc 100644 --- a/Sources/Mistica/Components/Callout/Internals/CalloutMessagesContent.swift +++ b/Sources/Mistica/Components/Callout/Internals/CalloutMessagesContent.swift @@ -42,7 +42,7 @@ extension CalloutMessagesContent { } } - override var description: String { + var calloutDescription: String { get { descriptionLabel.text! } diff --git a/Sources/Mistica/Components/Callout/Internals/CalloutTitleActions.swift b/Sources/Mistica/Components/Callout/Internals/CalloutTitleActions.swift index 239e35cd..1e19a732 100644 --- a/Sources/Mistica/Components/Callout/Internals/CalloutTitleActions.swift +++ b/Sources/Mistica/Components/Callout/Internals/CalloutTitleActions.swift @@ -38,12 +38,12 @@ extension CalloutTitleActions { } } - override var description: String { + var calloutTitleDescription: String { get { - messagesView.description + messagesView.calloutDescription } set { - messagesView.description = newValue + messagesView.calloutDescription = newValue } } diff --git a/Sources/Mistica/Components/Callout/Model/CalloutButton.swift b/Sources/Mistica/Components/Callout/Model/CalloutButton.swift index 7f23a25b..0467dd7b 100644 --- a/Sources/Mistica/Components/Callout/Model/CalloutButton.swift +++ b/Sources/Mistica/Components/Callout/Model/CalloutButton.swift @@ -8,16 +8,16 @@ import Foundation -public struct CalloutButton { +public struct CalloutButton: Sendable { public let title: String public let loadingTitle: String? public let accessibilityIdentifier: String? - public let tapHandler: (() -> Void)? + public let tapHandler: (@Sendable() -> Void)? public init(title: String, loadingTitle: String?, accessibilityIdentifier: String? = nil, - tapHandler: (() -> Void)?) { + tapHandler: (@Sendable() -> Void)?) { self.title = title self.loadingTitle = loadingTitle self.accessibilityIdentifier = accessibilityIdentifier @@ -25,14 +25,14 @@ public struct CalloutButton { } } -public struct CalloutLinkButton { +public struct CalloutLinkButton: Sendable { public let title: String public let accessibilityIdentifier: String? - public let tapHandler: (() -> Void)? + public let tapHandler: (@Sendable() -> Void)? public init(title: String, accessibilityIdentifier: String? = nil, - tapHandler: (() -> Void)?) { + tapHandler: (@Sendable() -> Void)?) { self.title = title self.accessibilityIdentifier = accessibilityIdentifier self.tapHandler = tapHandler diff --git a/Sources/Mistica/Components/Cards/DataCard.swift b/Sources/Mistica/Components/Cards/DataCard.swift index f3dfbcec..77ac50c6 100644 --- a/Sources/Mistica/Components/Cards/DataCard.swift +++ b/Sources/Mistica/Components/Cards/DataCard.swift @@ -79,7 +79,7 @@ public class DataCard: UIView { if let contentConfiguration = contentConfiguration { configure(with: contentConfiguration) } else { - configure(with: .emptyConfiguration) + configure(with: .emptyConfiguration()) } } } @@ -294,11 +294,13 @@ private extension DataCard { } private extension DataCardConfiguration { - static let emptyConfiguration = DataCardConfiguration( - title: "", - descriptionTitle: "", - buttons: .link( - CardLinkButton(title: "", accessibilityIdentifier: nil, tapHandler: nil) + static func emptyConfiguration() -> DataCardConfiguration { + DataCardConfiguration( + title: "", + descriptionTitle: "", + buttons: .link( + CardLinkButton(title: "", accessibilityIdentifier: nil, tapHandler: nil) + ) ) - ) + } } diff --git a/Sources/Mistica/Components/Cards/MediaCard.swift b/Sources/Mistica/Components/Cards/MediaCard.swift index ec22d6c2..df18abb4 100644 --- a/Sources/Mistica/Components/Cards/MediaCard.swift +++ b/Sources/Mistica/Components/Cards/MediaCard.swift @@ -75,7 +75,7 @@ public class MediaCard: UIView { if let contentConfiguration = contentConfiguration { configure(with: contentConfiguration) } else { - configure(with: .emptyConfiguration) + configure(with: .emptyConfiguration()) } } } @@ -201,5 +201,8 @@ private extension MediaCard { } private extension MediaCardConfiguration { - static let emptyConfiguration = MediaCardConfiguration(richMedia: UIView(), descriptionTitle: "") + @MainActor + static func emptyConfiguration() -> MediaCardConfiguration { + MediaCardConfiguration(richMedia: UIView(), descriptionTitle: "") + } } diff --git a/Sources/Mistica/Components/Cards/Model/CardButton.swift b/Sources/Mistica/Components/Cards/Model/CardButton.swift index ec15e550..d538ddf9 100644 --- a/Sources/Mistica/Components/Cards/Model/CardButton.swift +++ b/Sources/Mistica/Components/Cards/Model/CardButton.swift @@ -8,16 +8,16 @@ import Foundation -public struct CardButton { +public struct CardButton: Sendable { public let title: String public let accessibilityIdentifier: String? public let loadingTitle: String? - public let tapHandler: (() -> Void)? + public let tapHandler: (@Sendable() -> Void)? public init(title: String, loadingTitle: String?, accessibilityIdentifier: String? = nil, - tapHandler: (() -> Void)?) { + tapHandler: (@Sendable() -> Void)?) { self.title = title self.loadingTitle = loadingTitle self.accessibilityIdentifier = accessibilityIdentifier @@ -25,14 +25,14 @@ public struct CardButton { } } -public struct CardLinkButton { +public struct CardLinkButton: Sendable { public let title: String public let accessibilityIdentifier: String? - public let tapHandler: (() -> Void)? + public let tapHandler: (@Sendable() -> Void)? public init(title: String, accessibilityIdentifier: String? = nil, - tapHandler: (() -> Void)?) { + tapHandler: (@Sendable() -> Void)?) { self.title = title self.accessibilityIdentifier = accessibilityIdentifier self.tapHandler = tapHandler diff --git a/Sources/Mistica/Components/Checkbox/Checkbox.swift b/Sources/Mistica/Components/Checkbox/Checkbox.swift index 4273e7af..4c3b5c68 100644 --- a/Sources/Mistica/Components/Checkbox/Checkbox.swift +++ b/Sources/Mistica/Components/Checkbox/Checkbox.swift @@ -14,7 +14,7 @@ public class Checkbox: UIControl { private enum Constants { static let viewWidth = CGFloat(18) static let animationDuration = Double(0.4) - static let timingFunction = CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) + nonisolated(unsafe) static let timingFunction = CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) } private let imageView = UIImageView(image: .checkmarkIcon) diff --git a/Sources/Mistica/Components/Crouton/Presentation/CroutonController.swift b/Sources/Mistica/Components/Crouton/Presentation/CroutonController.swift index 333f878d..660a884c 100644 --- a/Sources/Mistica/Components/Crouton/Presentation/CroutonController.swift +++ b/Sources/Mistica/Components/Crouton/Presentation/CroutonController.swift @@ -8,10 +8,12 @@ import UIKit +@MainActor public class CroutonController: NSObject { public enum RootViewController { public typealias Closure = () -> UIViewController? - public static let `default`: Closure = { UIApplication.shared.windows.filter(\.isKeyWindow).first?.rootViewController } + @MainActor public static let `default`: Closure = { UIApplication.shared.windows.filter(\.isKeyWindow).first?.rootViewController + } } public typealias Token = UUID diff --git a/Sources/Mistica/Components/Crouton/Presentation/OngoingCrouton.swift b/Sources/Mistica/Components/Crouton/Presentation/OngoingCrouton.swift index e630c64a..bd1cb778 100644 --- a/Sources/Mistica/Components/Crouton/Presentation/OngoingCrouton.swift +++ b/Sources/Mistica/Components/Crouton/Presentation/OngoingCrouton.swift @@ -9,6 +9,7 @@ import UIKit extension CroutonController { + @MainActor struct OngoingCrouton { let token: Token let croutonView: CroutonView diff --git a/Sources/Mistica/Components/EmptyState/EmptyState.swift b/Sources/Mistica/Components/EmptyState/EmptyState.swift index 2aef57d2..2674905f 100644 --- a/Sources/Mistica/Components/EmptyState/EmptyState.swift +++ b/Sources/Mistica/Components/EmptyState/EmptyState.swift @@ -23,7 +23,7 @@ public class EmptyState: UIView { if let contentConfiguration = contentConfiguration { configure(withConfiguration: contentConfiguration) } else { - configure(withConfiguration: .empty) + configure(withConfiguration: .emptyConfiguration()) } } } diff --git a/Sources/Mistica/Components/EmptyState/EmptyStateConfiguration.swift b/Sources/Mistica/Components/EmptyState/EmptyStateConfiguration.swift index 6645f2f8..8d87411c 100644 --- a/Sources/Mistica/Components/EmptyState/EmptyStateConfiguration.swift +++ b/Sources/Mistica/Components/EmptyState/EmptyStateConfiguration.swift @@ -10,7 +10,14 @@ import Foundation import UIKit public struct EmptyStateConfiguration { - static let empty = EmptyStateConfiguration(type: .default(.icon(UIImage())), title: "Basic configuration", description: "This is a basic configuration for the empty state", actions: nil) + static func emptyConfiguration() -> EmptyStateConfiguration { + EmptyStateConfiguration( + type: .default(.icon(UIImage())), + title: "Basic configuration", + description: "This is a basic configuration for the empty state", + actions: nil + ) + } public enum EmptyStateActions { case primary(EmptyStateButton) diff --git a/Sources/Mistica/Components/EmptyState/Model/EmptyStateButton.swift b/Sources/Mistica/Components/EmptyState/Model/EmptyStateButton.swift index 520ba5ee..f5875b15 100644 --- a/Sources/Mistica/Components/EmptyState/Model/EmptyStateButton.swift +++ b/Sources/Mistica/Components/EmptyState/Model/EmptyStateButton.swift @@ -8,26 +8,26 @@ import Foundation -public struct EmptyStateButton { +public struct EmptyStateButton: Sendable { public let title: String public let loadingTitle: String? - public let tapHandler: (() -> Void)? + public let tapHandler: (@Sendable() -> Void)? public init(title: String, loadingTitle: String?, - tapHandler: (() -> Void)?) { + tapHandler: (@Sendable() -> Void)?) { self.title = title self.loadingTitle = loadingTitle self.tapHandler = tapHandler } } -public struct EmptyStateLinkButton { +public struct EmptyStateLinkButton: Sendable { public let title: String - public let tapHandler: (() -> Void)? + public let tapHandler: (@Sendable() -> Void)? public init(title: String, - tapHandler: (() -> Void)?) { + tapHandler: (@Sendable() -> Void)?) { self.title = title self.tapHandler = tapHandler } diff --git a/Sources/Mistica/Components/Feedback/FeedbackView.swift b/Sources/Mistica/Components/Feedback/FeedbackView.swift index f523ad7b..151711a5 100644 --- a/Sources/Mistica/Components/Feedback/FeedbackView.swift +++ b/Sources/Mistica/Components/Feedback/FeedbackView.swift @@ -208,8 +208,10 @@ public class FeedbackView: UIView { private lazy var buttonsView: UIView = { let buttonsView = UIStackView(arrangedSubviews: []) - [primaryButton, secondaryButton].compactMap { $0 } - .forEach(buttonsView.addArrangedSubview(_:)) + Task { @MainActor in + try [primaryButton, secondaryButton].compactMap { $0 } + .forEach(buttonsView.addArrangedSubview(_:)) + } buttonsView.alignment = .fill buttonsView.axis = .vertical @@ -365,7 +367,7 @@ private extension FeedbackView { } // Prepare - views.forEach(prepare(view:)) + try? views.forEach(prepare(view:)) // Generate animators animators = views.map(animation).map { animation in let animator = animator @@ -410,8 +412,10 @@ private extension FeedbackView { let hapticFeedbackDelay = style.hapticFeedbackDelay else { return } Timer.scheduledTimer(withTimeInterval: hapticFeedbackDelay, repeats: false) { [weak self] _ in guard let self = self else { return } - self.feedbackGenerator?.notificationOccurred(hapticFeedbackStyle) - self.feedbackGenerator = nil + Task { @MainActor in + self.feedbackGenerator?.notificationOccurred(hapticFeedbackStyle) + self.feedbackGenerator = nil + } } } diff --git a/Sources/Mistica/Components/Form/FormView.swift b/Sources/Mistica/Components/Form/FormView.swift index 91ce2cf1..fd03d18c 100644 --- a/Sources/Mistica/Components/Form/FormView.swift +++ b/Sources/Mistica/Components/Form/FormView.swift @@ -95,21 +95,21 @@ public extension FormView { } func addInputFields(_ inputFields: [InputField]) { - inputFields.forEach(addInputField) + try? inputFields.forEach(addInputField) arrangeViews() } func removeInputFields(_ inputFields: [InputField]) { - inputFields.forEach(removeInputField) + try? inputFields.forEach(removeInputField) } func addValidatableViews(_ views: [ValidatableView]) { - views.forEach(addValidatableView) + try? views.forEach(addValidatableView) arrangeViews() } func removeValidatableViews(_ views: [ValidatableView]) { - views.forEach(removeValidatableView) + try? views.forEach(removeValidatableView) } func addHeaderView(_ headerView: UIView) { diff --git a/Sources/Mistica/Components/Form/ValidatableView.swift b/Sources/Mistica/Components/Form/ValidatableView.swift index adb99b48..01738139 100644 --- a/Sources/Mistica/Components/Form/ValidatableView.swift +++ b/Sources/Mistica/Components/Form/ValidatableView.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor public protocol Validatable: AnyObject { func isValid() -> Bool func validate() diff --git a/Sources/Mistica/Components/InputField/InputField.swift b/Sources/Mistica/Components/InputField/InputField.swift index ce21c964..31a38401 100644 --- a/Sources/Mistica/Components/InputField/InputField.swift +++ b/Sources/Mistica/Components/InputField/InputField.swift @@ -381,12 +381,16 @@ public class InputField: UIView { } deinit { - unsubscribeToPlaceholdeLabelBoundsChanges() + DispatchQueue.main.async { [weak self] in + self?.unsubscribeToPlaceholdeLabelBoundsChanges() + } } override public func observeValue(forKeyPath _: String?, of _: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) { - updatePlaceholderLayerPosition() - updatePlaceholderLayerSize() + Task { @MainActor in + updatePlaceholderLayerPosition() + updatePlaceholderLayerSize() + } } override public var intrinsicContentSize: CGSize { diff --git a/Sources/Mistica/Components/InputField/InputFieldDelegate.swift b/Sources/Mistica/Components/InputField/InputFieldDelegate.swift index 57fded6a..02207014 100644 --- a/Sources/Mistica/Components/InputField/InputFieldDelegate.swift +++ b/Sources/Mistica/Components/InputField/InputFieldDelegate.swift @@ -9,6 +9,7 @@ import Foundation import UIKit +@MainActor public protocol InputFieldDelegate: AnyObject { func inputFieldTextDidChange(_ field: InputField) func inputFieldShouldBeginEditing(_ field: InputField) -> Bool diff --git a/Sources/Mistica/Components/Lists/Internals/CellCenterSectionView.swift b/Sources/Mistica/Components/Lists/Internals/CellCenterSectionView.swift index c3c56c51..4419fb8e 100644 --- a/Sources/Mistica/Components/Lists/Internals/CellCenterSectionView.swift +++ b/Sources/Mistica/Components/Lists/Internals/CellCenterSectionView.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor protocol ListCellContentViewDelegate: AnyObject { func accessibilityChanged() } diff --git a/Sources/Mistica/Components/Lists/ListCellContentView.swift b/Sources/Mistica/Components/Lists/ListCellContentView.swift index 41c94a6f..bcad7d64 100644 --- a/Sources/Mistica/Components/Lists/ListCellContentView.swift +++ b/Sources/Mistica/Components/Lists/ListCellContentView.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor protocol ListCellContentTableViewDelegate { func cellStyleChanged() func accessibilityChanged() diff --git a/Sources/Mistica/Components/RadioButton/RadioButton.swift b/Sources/Mistica/Components/RadioButton/RadioButton.swift index 12e2acc5..53b250a7 100644 --- a/Sources/Mistica/Components/RadioButton/RadioButton.swift +++ b/Sources/Mistica/Components/RadioButton/RadioButton.swift @@ -14,7 +14,7 @@ public class RadioButton: UIControl { private enum Constants { static let viewWidth = CGFloat(20) static let animationDuration = Double(0.4) - static let timingFunction = CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) + nonisolated(unsafe) static let timingFunction = CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) } private var _isActivated = false diff --git a/Sources/Mistica/Components/Sheet/View/BottomSheetPresentation/BottomSheetInteractiveDismissalTransition.swift b/Sources/Mistica/Components/Sheet/View/BottomSheetPresentation/BottomSheetInteractiveDismissalTransition.swift index 6df18a28..60a78502 100644 --- a/Sources/Mistica/Components/Sheet/View/BottomSheetPresentation/BottomSheetInteractiveDismissalTransition.swift +++ b/Sources/Mistica/Components/Sheet/View/BottomSheetPresentation/BottomSheetInteractiveDismissalTransition.swift @@ -11,7 +11,7 @@ import UIKit final class BottomSheetInteractiveDismissalTransition: NSObject { private enum Constants { static let maxBouncingHeight: CGFloat = 250 - static let animationDuration: CGFloat = UIView.defaultAnimationDuration + static let animationDuration: CGFloat = 0.25 static let animationCurve: UIView.AnimationCurve = .easeOut } @@ -29,6 +29,7 @@ final class BottomSheetInteractiveDismissalTransition: NSObject { // MARK: Public methods extension BottomSheetInteractiveDismissalTransition { + @MainActor func start(moving presentedView: UIView, interactiveDismissal: Bool) { self.interactiveDismissal = interactiveDismissal @@ -42,6 +43,7 @@ extension BottomSheetInteractiveDismissalTransition { ) } + @MainActor func move(_ presentedView: UIView, using translation: CGFloat) { let progress = translation / presentedView.frame.height @@ -51,6 +53,7 @@ extension BottomSheetInteractiveDismissalTransition { transitionContext?.updateInteractiveTransition(progress) } + @MainActor func stop( moving presentedView: UIView, at translation: CGFloat, @@ -171,6 +174,7 @@ extension BottomSheetInteractiveDismissalTransition: UIViewControllerInteractive // MARK: Private private extension BottomSheetInteractiveDismissalTransition { + @MainActor func createHeightAnimator( animating view: UIView, from height: CGFloat @@ -198,6 +202,7 @@ private extension BottomSheetInteractiveDismissalTransition { return propertyAnimator } + @MainActor func createOffsetAnimator( animating view: UIView, to offset: CGFloat, diff --git a/Sources/Mistica/Components/Sheet/View/Fragments/List/Touchable.swift b/Sources/Mistica/Components/Sheet/View/Fragments/List/Touchable.swift index 3be6841a..1a1a385c 100644 --- a/Sources/Mistica/Components/Sheet/View/Fragments/List/Touchable.swift +++ b/Sources/Mistica/Components/Sheet/View/Fragments/List/Touchable.swift @@ -8,6 +8,7 @@ import Foundation +@MainActor protocol Touchable { func touchBegan() func touchEnded() diff --git a/Sources/Mistica/Components/Stepper/DeterminateStepperView.swift b/Sources/Mistica/Components/Stepper/DeterminateStepperView.swift index 07c14c2c..4c0ebf61 100644 --- a/Sources/Mistica/Components/Stepper/DeterminateStepperView.swift +++ b/Sources/Mistica/Components/Stepper/DeterminateStepperView.swift @@ -164,7 +164,9 @@ private extension DeterminateStepperView { arrangedSubviews.append(createStep(step: step)) } - arrangedSubviews.forEach(stackView.addArrangedSubview) + Task { @MainActor in + try? arrangedSubviews.forEach(stackView.addArrangedSubview) + } activateSegmentsWidthConstraints() diff --git a/Sources/Mistica/Components/Tabs/Model/TabItem.swift b/Sources/Mistica/Components/Tabs/Model/TabItem.swift index cf2ba04a..598034fe 100644 --- a/Sources/Mistica/Components/Tabs/Model/TabItem.swift +++ b/Sources/Mistica/Components/Tabs/Model/TabItem.swift @@ -8,7 +8,7 @@ import UIKit -public struct TabItem: Equatable { +public struct TabItem: Equatable, Sendable { public let title: String public let icon: UIImage? public let accessibilityIdentifier: String? diff --git a/Sources/Mistica/Utils/Views/Keyboard/KeyboardNotificationCenter.swift b/Sources/Mistica/Utils/Views/Keyboard/KeyboardNotificationCenter.swift index 3e59d3fd..9bea3957 100644 --- a/Sources/Mistica/Utils/Views/Keyboard/KeyboardNotificationCenter.swift +++ b/Sources/Mistica/Utils/Views/Keyboard/KeyboardNotificationCenter.swift @@ -10,6 +10,7 @@ import Foundation import UIKit public extension KeyboardInfo { + @MainActor func animateAlongsideKeyboard(animations: @escaping () -> Void) { UIView.animate( withDuration: duration, @@ -21,7 +22,7 @@ public extension KeyboardInfo { } } -public struct KeyboardEvent: Hashable { +public struct KeyboardEvent: Hashable, Sendable { let notificationName: Notification.Name public static let willShow = KeyboardEvent(notificationName: UIResponder.keyboardWillShowNotification) diff --git a/Sources/MisticaCommon/Assets/MisticaBrandAssets.swift b/Sources/MisticaCommon/Assets/MisticaBrandAssets.swift index 4805090d..11ef7d9e 100644 --- a/Sources/MisticaCommon/Assets/MisticaBrandAssets.swift +++ b/Sources/MisticaCommon/Assets/MisticaBrandAssets.swift @@ -9,7 +9,7 @@ import Foundation import SwiftUI -public protocol MisticaBrandAssets { +public protocol MisticaBrandAssets: Sendable { var iconNotificationInfo: UIImage? { get } var successAnimation: NSDataAsset? { get } var checkAnimation: NSDataAsset? { get } diff --git a/Sources/MisticaCommon/Colors/BlauColorPalette.swift b/Sources/MisticaCommon/Colors/BlauColorPalette.swift index 8805a7dc..49ac3b76 100644 --- a/Sources/MisticaCommon/Colors/BlauColorPalette.swift +++ b/Sources/MisticaCommon/Colors/BlauColorPalette.swift @@ -281,7 +281,7 @@ struct BlauColors: MisticaColors { )) } -public struct BlauColorPalette { +public struct BlauColorPalette: Sendable { public init() {} public let blauBluePrimary = UIColor(hex: "#00B6F1")! public let blauBluePrimary10 = UIColor(hex: "#F7FDFF")! diff --git a/Sources/MisticaCommon/Colors/MisticaColor.swift b/Sources/MisticaCommon/Colors/MisticaColor.swift index a528231c..512b192c 100644 --- a/Sources/MisticaCommon/Colors/MisticaColor.swift +++ b/Sources/MisticaCommon/Colors/MisticaColor.swift @@ -8,7 +8,7 @@ import UIKit -public enum MisticaColor { +public enum MisticaColor: Sendable { case solid(UIColor) case gradient(MisticaGradient) } diff --git a/Sources/MisticaCommon/Colors/MisticaColors.swift b/Sources/MisticaCommon/Colors/MisticaColors.swift index aa81cd6d..1cc4fc47 100644 --- a/Sources/MisticaCommon/Colors/MisticaColors.swift +++ b/Sources/MisticaCommon/Colors/MisticaColors.swift @@ -8,7 +8,7 @@ import UIKit -public protocol MisticaColors { +public protocol MisticaColors: Sendable { var backgroundBrand: MisticaColor { get } var backgroundBrandSecondary: UIColor { get } var appBarBackground: UIColor { get } diff --git a/Sources/MisticaCommon/Colors/MisticaGradient.swift b/Sources/MisticaCommon/Colors/MisticaGradient.swift index 9b80f473..b5046d60 100644 --- a/Sources/MisticaCommon/Colors/MisticaGradient.swift +++ b/Sources/MisticaCommon/Colors/MisticaGradient.swift @@ -8,7 +8,7 @@ import UIKit -public struct MisticaGradient { +public struct MisticaGradient: Sendable { public let colors: [UIColor] public let stops: [CGFloat] public let angle: CGFloat diff --git a/Sources/MisticaCommon/Colors/MovistarColorPalette.swift b/Sources/MisticaCommon/Colors/MovistarColorPalette.swift index 9c5a5559..74b1dbed 100644 --- a/Sources/MisticaCommon/Colors/MovistarColorPalette.swift +++ b/Sources/MisticaCommon/Colors/MovistarColorPalette.swift @@ -281,7 +281,7 @@ struct MovistarColors: MisticaColors { )) } -public struct MovistarColorPalette { +public struct MovistarColorPalette: Sendable { public init() {} public let movistarBlue = UIColor(hex: "#0B9CEA")! public let movistarBlue10 = UIColor(hex: "#E6F5FD")! diff --git a/Sources/MisticaCommon/Colors/O2ColorPalette.swift b/Sources/MisticaCommon/Colors/O2ColorPalette.swift index 8058d0dc..058b7720 100644 --- a/Sources/MisticaCommon/Colors/O2ColorPalette.swift +++ b/Sources/MisticaCommon/Colors/O2ColorPalette.swift @@ -281,7 +281,7 @@ struct O2Colors: MisticaColors { )) } -public struct O2ColorPalette { +public struct O2ColorPalette: Sendable { public init() {} public let o2BluePrimary = UIColor(hex: "#0019A5")! public let o2BluePrimary70 = UIColor(hex: "#000066")! diff --git a/Sources/MisticaCommon/Colors/O2NewColorPalette.swift b/Sources/MisticaCommon/Colors/O2NewColorPalette.swift index d78efe4e..3017ed1c 100644 --- a/Sources/MisticaCommon/Colors/O2NewColorPalette.swift +++ b/Sources/MisticaCommon/Colors/O2NewColorPalette.swift @@ -299,7 +299,7 @@ struct O2NewColors: MisticaColors { )) } -public struct O2NewColorPalette { +public struct O2NewColorPalette: Sendable { public init() {} public let beyondBlue = UIColor(hex: "#0050FF")! public let beyondBlue10 = UIColor(hex: "#E5EDFF")! diff --git a/Sources/MisticaCommon/Colors/TelefonicaColorPalette.swift b/Sources/MisticaCommon/Colors/TelefonicaColorPalette.swift index 46a92fe6..63ff202a 100644 --- a/Sources/MisticaCommon/Colors/TelefonicaColorPalette.swift +++ b/Sources/MisticaCommon/Colors/TelefonicaColorPalette.swift @@ -281,7 +281,7 @@ struct TelefonicaColors: MisticaColors { )) } -public struct TelefonicaColorPalette { +public struct TelefonicaColorPalette: Sendable { public init() {} public let telefonicaBlue = UIColor(hex: "#0066FF")! public let telefonicaBlue10 = UIColor(hex: "#E5F0FF")! diff --git a/Sources/MisticaCommon/Colors/TuColorPalette.swift b/Sources/MisticaCommon/Colors/TuColorPalette.swift index 4692f5e9..4b756b65 100644 --- a/Sources/MisticaCommon/Colors/TuColorPalette.swift +++ b/Sources/MisticaCommon/Colors/TuColorPalette.swift @@ -281,7 +281,7 @@ struct TuColors: MisticaColors { )) } -public struct TuColorPalette { +public struct TuColorPalette: Sendable { public init() {} public let primary = UIColor(hex: "#2B3447")! public let primary10 = UIColor(hex: "#EAEBED")! diff --git a/Sources/MisticaCommon/Colors/VivoColorPalette.swift b/Sources/MisticaCommon/Colors/VivoColorPalette.swift index f6f5ac9f..bfc22e02 100644 --- a/Sources/MisticaCommon/Colors/VivoColorPalette.swift +++ b/Sources/MisticaCommon/Colors/VivoColorPalette.swift @@ -281,7 +281,7 @@ struct VivoColors: MisticaColors { )) } -public struct VivoColorPalette { +public struct VivoColorPalette: Sendable { public init() {} public let vivoPurple = UIColor(hex: "#660099")! public let vivoPurpleDark = UIColor(hex: "#461E5F")! diff --git a/Sources/MisticaCommon/Colors/VivoNewColorPalette.swift b/Sources/MisticaCommon/Colors/VivoNewColorPalette.swift index 10749127..bee64be4 100644 --- a/Sources/MisticaCommon/Colors/VivoNewColorPalette.swift +++ b/Sources/MisticaCommon/Colors/VivoNewColorPalette.swift @@ -281,7 +281,7 @@ struct VivoNewColors: MisticaColors { )) } -public struct VivoNewColorPalette { +public struct VivoNewColorPalette: Sendable { public init() {} public let vivoPurple = UIColor(hex: "#660099")! public let vivoPurpleDark = UIColor(hex: "#461E5F")! diff --git a/Sources/MisticaCommon/Controls/MisticaAppearance.swift b/Sources/MisticaCommon/Controls/MisticaAppearance.swift index f35acdd7..197e913c 100644 --- a/Sources/MisticaCommon/Controls/MisticaAppearance.swift +++ b/Sources/MisticaCommon/Controls/MisticaAppearance.swift @@ -16,6 +16,7 @@ public enum MisticaControlStyle: CaseIterable { case pageControl } +@MainActor enum MisticaAppearance { static func setUp(controls: [MisticaControlStyle]) { for control in controls { diff --git a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/CalloutAccessibilityIdentifiers.swift b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/CalloutAccessibilityIdentifiers.swift index 44cabfbe..0da3759b 100644 --- a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/CalloutAccessibilityIdentifiers.swift +++ b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/CalloutAccessibilityIdentifiers.swift @@ -13,10 +13,10 @@ private extension DefaultAccessibilityIdentifier.Feature { } public enum CalloutAccessibilityIdentifiers { - public static var title = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .title) - public static var description = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .description) - public static var primaryButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .primaryButton) - public static var secondaryButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .secondaryButton) - public static var linkButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .linkButton) - public static var closeButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .closeButton) + public static let title = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .title) + public static let description = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .description) + public static let primaryButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .primaryButton) + public static let secondaryButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .secondaryButton) + public static let linkButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .linkButton) + public static let closeButton = DefaultAccessibilityIdentifier(feature: .callout, section: nil, elementType: .closeButton) } diff --git a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DataCardAccessibilityIdentifiers.swift b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DataCardAccessibilityIdentifiers.swift index 14503ca0..df0c8da1 100644 --- a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DataCardAccessibilityIdentifiers.swift +++ b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DataCardAccessibilityIdentifiers.swift @@ -13,10 +13,10 @@ private extension DefaultAccessibilityIdentifier.Feature { } public enum DataCardAccessibilityIdentifiers { - public static var headline = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .tag) - public static var title = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .title) - public static var subtitle = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .subtitle) - public static var description = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .description) - public static var primaryButton = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .primaryButton) - public static var linkButton = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .linkButton) + public static let headline = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .tag) + public static let title = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .title) + public static let subtitle = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .subtitle) + public static let description = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .description) + public static let primaryButton = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .primaryButton) + public static let linkButton = DefaultAccessibilityIdentifier(feature: .dataCard, section: .item, elementType: .linkButton) } diff --git a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DefaultAccessibilityIdentifiers.swift b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DefaultAccessibilityIdentifiers.swift index 76c3128e..d3bc674b 100644 --- a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DefaultAccessibilityIdentifiers.swift +++ b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/DefaultAccessibilityIdentifiers.swift @@ -8,22 +8,22 @@ import Foundation -public struct DefaultAccessibilityIdentifier { - public struct Feature { +public struct DefaultAccessibilityIdentifier: Sendable { + public struct Feature: Sendable { let description: String public init(_ description: String) { self.description = description } } - public struct Section { + public struct Section: Sendable { let description: String public init(_ description: String) { self.description = description } } - public struct ElementType { + public struct ElementType: Sendable { let description: String public init(_ description: String) { self.description = description diff --git a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/FeedbackAccessibilityIdentifiers.swift b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/FeedbackAccessibilityIdentifiers.swift index d688b92f..8c829169 100644 --- a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/FeedbackAccessibilityIdentifiers.swift +++ b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/FeedbackAccessibilityIdentifiers.swift @@ -11,11 +11,11 @@ private extension DefaultAccessibilityIdentifier.Feature { } public enum FeedbackAccessibilityIdentifiers { - public static var icon = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .icon) - public static var title = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .title) - public static var description = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .description) - public static var primaryButton = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .primaryButton) - public static var secondaryButton = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .secondaryButton) - public static var linkButton = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .linkButton) - public static var slot = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .slot) + public static let icon = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .icon) + public static let title = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .title) + public static let description = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .description) + public static let primaryButton = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .primaryButton) + public static let secondaryButton = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .secondaryButton) + public static let linkButton = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .linkButton) + public static let slot = DefaultAccessibilityIdentifier(feature: .feedback, section: .item, elementType: .slot) } diff --git a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/ListAccessibilityIdentifiers.swift b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/ListAccessibilityIdentifiers.swift index aa0a6db5..0fd4f22d 100644 --- a/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/ListAccessibilityIdentifiers.swift +++ b/Sources/MisticaCommon/DefaultAccessibilityIdentifiers/ListAccessibilityIdentifiers.swift @@ -13,12 +13,12 @@ private extension DefaultAccessibilityIdentifier.Feature { } public enum ListAccessibilityIdentifiers { - public static var icon = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .icon) - public static var tag = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .tag) - public static var title = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .title) - public static var subtitle = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .subtitle) - public static var description = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .description) - public static var slot = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .slot) - public static var action = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .action) - public static var chevron = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .chevron) + public static let icon = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .icon) + public static let tag = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .tag) + public static let title = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .title) + public static let subtitle = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .subtitle) + public static let description = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .description) + public static let slot = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .slot) + public static let action = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .action) + public static let chevron = DefaultAccessibilityIdentifier(feature: .list, section: .item, elementType: .chevron) } diff --git a/Sources/MisticaCommon/Extensions/Bundle+Mistica.swift b/Sources/MisticaCommon/Extensions/Bundle+Mistica.swift index 83d9e172..34c1c0d7 100644 --- a/Sources/MisticaCommon/Extensions/Bundle+Mistica.swift +++ b/Sources/MisticaCommon/Extensions/Bundle+Mistica.swift @@ -23,7 +23,7 @@ extension Bundle { // To fix the problem, we manually search for the bundle assets. https://developer.apple.com/forums/thread/664295 private class CurrentBundleFinder {} private extension Bundle { - static var misticaCommon: Bundle = { + static let misticaCommon: Bundle = { let bundleName = "Mistica_MisticaCommon" let candidates = [ diff --git a/Sources/MisticaCommon/Extensions/Lottie+Utils.swift b/Sources/MisticaCommon/Extensions/Lottie+Utils.swift index 1ac4c459..ed80a5df 100644 --- a/Sources/MisticaCommon/Extensions/Lottie+Utils.swift +++ b/Sources/MisticaCommon/Extensions/Lottie+Utils.swift @@ -15,7 +15,7 @@ import Lottie **/ public extension Lottie.LottieConfiguration { - static var current: LottieConfiguration = { + nonisolated(unsafe) static var current: LottieConfiguration = { var configuration: LottieConfiguration = .init(renderingEngine: .automatic) #if DEBUG if isRunningUnitTests { diff --git a/Sources/MisticaCommon/Fonts/FontStyle.swift b/Sources/MisticaCommon/Fonts/FontStyle.swift index 510dc39a..91c9a958 100644 --- a/Sources/MisticaCommon/Fonts/FontStyle.swift +++ b/Sources/MisticaCommon/Fonts/FontStyle.swift @@ -9,6 +9,39 @@ import SwiftUI import UIKit +public class FontManager: @unchecked Sendable { + public static let shared = FontManager() + + private let queue = DispatchQueue(label: "com.telefonica.fontManager", attributes: .concurrent) + + private var _fontNameForWeight: (@Sendable(Font.Weight) -> String)? = nil + private var _uiFontNameForWeight: (@Sendable(UIFont.Weight) -> String)? = nil + + public var fontNameForWeight: (@Sendable(Font.Weight) -> String)? { + get { + queue.sync { _fontNameForWeight } + } + set { + queue.async { + self._fontNameForWeight = newValue + } + } + } + + public var uiFontNameForWeight: (@Sendable(UIFont.Weight) -> String)? { + get { + queue.sync { _uiFontNameForWeight } + } + set { + queue.async { + self._uiFontNameForWeight = newValue + } + } + } + + private init() {} +} + @frozen @objc public enum FontStyle: Int, CaseIterable, CustomStringConvertible { case textPreset1 @@ -30,22 +63,20 @@ import UIKit ) -> Font { let pointSize = calculateFontSize(constrainedToPreferredSize: constrainedPreferredSize) - if let fontName = Self.fontNameForWeight?(weight) { + if let fontName = FontManager.shared.fontNameForWeight?(weight) { return Font.custom(fontName, size: pointSize) } else { return Font.system(size: pointSize, weight: weight, design: .default) } } - public static var fontNameForWeight: ((Font.Weight) -> String)? = nil - func preferredFont( weight: UIFont.Weight, constrainedToPreferredSize constrainedPreferredSize: UIContentSizeCategory? = nil ) -> UIFont { let pointSize = calculateFontSize(constrainedToPreferredSize: constrainedPreferredSize) - if let fontName = Self.uiFontNameForWeight?(weight), + if let fontName = FontManager.shared.uiFontNameForWeight?(weight), let customFont = UIFont(name: fontName, size: pointSize) { return customFont } else { @@ -53,8 +84,6 @@ import UIKit } } - public static var uiFontNameForWeight: ((UIFont.Weight) -> String)? = nil - public var description: String { switch self { case .textPreset1: @@ -90,14 +119,14 @@ private extension FontStyle { let fontMetrics = UIFontMetrics(forTextStyle: uiFontPressetsCorrelations) var scaledBaseSize = round(fontMetrics.scaledValue(for: baseSize)) - if let constrainedPreferredSize = maximumFonSize(constrainedPreferredSize: constrainedPreferredSize) { + if let constrainedPreferredSize = maximumFontSize(constrainedPreferredSize: constrainedPreferredSize) { scaledBaseSize = min(scaledBaseSize, constrainedPreferredSize) } return scaledBaseSize } - func maximumFonSize(constrainedPreferredSize: UIContentSizeCategory?) -> CGFloat? { + func maximumFontSize(constrainedPreferredSize: UIContentSizeCategory?) -> CGFloat? { guard let constrainedPreferredSize else { return nil } let traitCollection = UITraitCollection(preferredContentSizeCategory: constrainedPreferredSize) diff --git a/Sources/MisticaCommon/Fonts/FontToolkit+UIFont.swift b/Sources/MisticaCommon/Fonts/FontToolkit+UIFont.swift index 183421e4..aa5366c5 100644 --- a/Sources/MisticaCommon/Fonts/FontToolkit+UIFont.swift +++ b/Sources/MisticaCommon/Fonts/FontToolkit+UIFont.swift @@ -8,7 +8,7 @@ import UIKit -var _isDynamicTypeEnabled = true +nonisolated(unsafe) var _isDynamicTypeEnabled = true public extension UIFont { static func textPreset1(weight: FontStyle.TextPreset1Weight, constrainedToPreferredSize: UIContentSizeCategory? = nil) -> UIFont { diff --git a/Sources/MisticaCommon/Fonts/MisticaFontSizes.swift b/Sources/MisticaCommon/Fonts/MisticaFontSizes.swift index 997e4dfc..573cf0a2 100644 --- a/Sources/MisticaCommon/Fonts/MisticaFontSizes.swift +++ b/Sources/MisticaCommon/Fonts/MisticaFontSizes.swift @@ -8,7 +8,7 @@ import Foundation -public protocol MisticaFontSizes { +public protocol MisticaFontSizes: Sendable { var tabsLabel: CGFloat { get } var title3: CGFloat { get } var text1: CGFloat { get } diff --git a/Sources/MisticaCommon/Fonts/MisticaFontWeightType.swift b/Sources/MisticaCommon/Fonts/MisticaFontWeightType.swift index e1019114..5d4ecfae 100644 --- a/Sources/MisticaCommon/Fonts/MisticaFontWeightType.swift +++ b/Sources/MisticaCommon/Fonts/MisticaFontWeightType.swift @@ -9,7 +9,7 @@ import SwiftUI /// Available font weights in Mistica -public enum MisticaFontWeightType { +public enum MisticaFontWeightType: Sendable { case light case regular case medium diff --git a/Sources/MisticaCommon/Fonts/MisticaFontWeights.swift b/Sources/MisticaCommon/Fonts/MisticaFontWeights.swift index 7665d284..6d9ad1c2 100644 --- a/Sources/MisticaCommon/Fonts/MisticaFontWeights.swift +++ b/Sources/MisticaCommon/Fonts/MisticaFontWeights.swift @@ -8,7 +8,7 @@ import UIKit -public protocol MisticaFontWeights { +public protocol MisticaFontWeights: Sendable { var cardTitle: MisticaFontWeightType { get } var button: MisticaFontWeightType { get } var tabsLabel: MisticaFontWeightType { get } diff --git a/Sources/MisticaCommon/MisticaConfig.swift b/Sources/MisticaCommon/MisticaConfig.swift index de90da0f..b486d51c 100644 --- a/Sources/MisticaCommon/MisticaConfig.swift +++ b/Sources/MisticaCommon/MisticaConfig.swift @@ -8,26 +8,86 @@ import Foundation -public enum MisticaConfig { - public private(set) static var currentColors: MisticaColors = MovistarColors() - public private(set) static var currentBrandAssets: MisticaBrandAssets = DefaultMisticaBrandAssets() - public private(set) static var currentStyledControls = [MisticaControlStyle]() - public private(set) static var currentFontWeights: MisticaFontWeights = MovistarFontWeights() - public private(set) static var currentCornerRadius: MisticaCornerRadius = MovistarCornerRadius() - public private(set) static var currentFontSizes: MisticaFontSizes = MovistarFontSizes() +public enum MisticaConfig: @unchecked Sendable { + private static let concurrentQueue = DispatchQueue(label: "com.misticaConfig.queue") + + nonisolated(unsafe) private static var _currentColors: MisticaColors = MovistarColors() + nonisolated(unsafe) private static var _currentBrandAssets: MisticaBrandAssets = DefaultMisticaBrandAssets() + nonisolated(unsafe) private static var _currentStyledControls = [MisticaControlStyle]() + nonisolated(unsafe) private static var _currentFontWeights: MisticaFontWeights = MovistarFontWeights() + nonisolated(unsafe) private static var _currentCornerRadius: MisticaCornerRadius = MovistarCornerRadius() + nonisolated(unsafe) private static var _currentFontSizes: MisticaFontSizes = MovistarFontSizes() + + public static var currentColors: MisticaColors { + get { + concurrentQueue.sync { _currentColors } + } + set { + concurrentQueue.async { _currentColors = newValue } + } + } + + public static var currentBrandAssets: MisticaBrandAssets { + get { + concurrentQueue.sync { _currentBrandAssets } + } + set { + concurrentQueue.async { _currentBrandAssets = newValue } + } + } + + public static var currentStyledControls: [MisticaControlStyle] { + get { + concurrentQueue.sync { _currentStyledControls } + } + set { + concurrentQueue.async { _currentStyledControls = newValue } + } + } + + public static var currentFontWeights: MisticaFontWeights { + get { + concurrentQueue.sync { _currentFontWeights } + } + set { + concurrentQueue.async { _currentFontWeights = newValue } + } + } + + public static var currentCornerRadius: MisticaCornerRadius { + get { + concurrentQueue.sync { _currentCornerRadius } + } + set { + concurrentQueue.async { _currentCornerRadius = newValue } + } + } + + public static var currentFontSizes: MisticaFontSizes { + get { + concurrentQueue.sync { _currentFontSizes } + } + set { + concurrentQueue.async { _currentFontSizes = newValue } + } + } // MARK: Public Setup - public static var brandStyle: BrandStyle = .movistar { + nonisolated(unsafe) public static var brandStyle: BrandStyle = .movistar { didSet { configure(for: brandStyle) - MisticaAppearance.setUp(controls: currentStyledControls) + Task { @MainActor in + MisticaAppearance.setUp(controls: currentStyledControls) + } } } public static func styleControls(_ controls: [MisticaControlStyle]) { currentStyledControls = controls - MisticaAppearance.setUp(controls: controls) + Task { @MainActor in + MisticaAppearance.setUp(controls: controls) + } } } diff --git a/Sources/MisticaCommon/Radius/MisticaCornerRadius.swift b/Sources/MisticaCommon/Radius/MisticaCornerRadius.swift index 26125833..bfe4ce5a 100644 --- a/Sources/MisticaCommon/Radius/MisticaCornerRadius.swift +++ b/Sources/MisticaCommon/Radius/MisticaCornerRadius.swift @@ -12,7 +12,7 @@ public enum MisticaRadiusConstants { static let roundedRadius: CGFloat = 999.0 } -public protocol MisticaCornerRadius { +public protocol MisticaCornerRadius: Sendable { var avatar: CGFloat { get } var bar: CGFloat { get } var button: CGFloat { get } diff --git a/Sources/MisticaCommon/Utils/Accessibility/AccessibilityHelper.swift b/Sources/MisticaCommon/Utils/Accessibility/AccessibilityHelper.swift index 7f3b8ab4..81311162 100644 --- a/Sources/MisticaCommon/Utils/Accessibility/AccessibilityHelper.swift +++ b/Sources/MisticaCommon/Utils/Accessibility/AccessibilityHelper.swift @@ -6,9 +6,10 @@ // Copyright © Telefonica. All rights reserved. // -import UIKit +@preconcurrency import UIKit public enum AccessibilityHelper { + @MainActor public static func post(_ announcement: String) { guard UIAccessibility.isVoiceOverRunning else { return } diff --git a/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellInteractiveData.swift b/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellInteractiveData.swift index 511cdcc3..e8048829 100644 --- a/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellInteractiveData.swift +++ b/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellInteractiveData.swift @@ -8,14 +8,14 @@ import Foundation -public struct AccessibilityListCellInteractiveData { +public struct AccessibilityListCellInteractiveData: Sendable { public let label: String? - public let action: (() -> Void)? + public let action: (@Sendable() -> Void)? - public init(label: String? = nil, action: (() -> Void)? = nil) { + public init(label: String? = nil, action: (@Sendable() -> Void)? = nil) { self.label = label self.action = action } - public static var `default`: AccessibilityListCellInteractiveData = .init() + public static let `default`: AccessibilityListCellInteractiveData = .init() } diff --git a/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellType.swift b/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellType.swift index 10162570..0a80bf00 100644 --- a/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellType.swift +++ b/Sources/MisticaCommon/Utils/Accessibility/ListCells/AccessibilityListCellType.swift @@ -8,11 +8,11 @@ import Foundation -public enum AccessibilityListCellType { +public enum AccessibilityListCellType: Sendable { case interactive(AccessibilityListCellInteractiveData) case doubleInteraction(AccessibilityListCellInteractiveData) case informative case customInformative(String) - public static var `default`: AccessibilityListCellType = .interactive(.default) + public static let `default`: AccessibilityListCellType = .interactive(.default) } diff --git a/Sources/MisticaSwiftUI/Components/Button/MisticaButton.swift b/Sources/MisticaSwiftUI/Components/Button/MisticaButton.swift index aeecf925..76cbf11b 100644 --- a/Sources/MisticaSwiftUI/Components/Button/MisticaButton.swift +++ b/Sources/MisticaSwiftUI/Components/Button/MisticaButton.swift @@ -216,7 +216,7 @@ private extension MisticaButton { // MARK: EnvironmentValues -public struct MisticaButtonLoadingInfo { +public struct MisticaButtonLoadingInfo: Sendable { public let isLoading: Bool public let loadingTitle: String } diff --git a/Sources/MisticaSwiftUI/Components/Button/MisticaButtonStyle.swift b/Sources/MisticaSwiftUI/Components/Button/MisticaButtonStyle.swift index 81a735ec..40b92f68 100644 --- a/Sources/MisticaSwiftUI/Components/Button/MisticaButtonStyle.swift +++ b/Sources/MisticaSwiftUI/Components/Button/MisticaButtonStyle.swift @@ -22,8 +22,8 @@ public struct MisticaButtonStyle: ButtonStyle { // MARK: Styles -private var _opacity = 0.5 -private var _opacityWithBackground = 0.1 +nonisolated(unsafe) private var _opacity = 0.5 +nonisolated(unsafe) private var _opacityWithBackground = 0.1 public extension ButtonStyle where Self == MisticaButtonStyle { static var opacity: CGFloat { diff --git a/Sources/MisticaSwiftUI/Components/Carousel/Carousels/TrackableScrollView.swift b/Sources/MisticaSwiftUI/Components/Carousel/Carousels/TrackableScrollView.swift index 526b80d6..4e6133b7 100644 --- a/Sources/MisticaSwiftUI/Components/Carousel/Carousels/TrackableScrollView.swift +++ b/Sources/MisticaSwiftUI/Components/Carousel/Carousels/TrackableScrollView.swift @@ -66,7 +66,7 @@ private extension TrackableScrollView { struct ScrollOffsetPreferenceKey: PreferenceKey { typealias Value = [CGPoint] - static var defaultValue: [CGPoint] = [.zero] + static let defaultValue: [CGPoint] = [.zero] static func reduce(value: inout [CGPoint], nextValue: () -> [CGPoint]) { value.append(contentsOf: nextValue()) diff --git a/Sources/MisticaSwiftUI/Components/Feedback/Feedback.swift b/Sources/MisticaSwiftUI/Components/Feedback/Feedback.swift index 8ed23a50..da14d6bd 100644 --- a/Sources/MisticaSwiftUI/Components/Feedback/Feedback.swift +++ b/Sources/MisticaSwiftUI/Components/Feedback/Feedback.swift @@ -133,7 +133,9 @@ public struct Feedback< feedbackGenerator.prepare() Timer.scheduledTimer(withTimeInterval: hapticFeedbackDelay, repeats: false) { _ in - feedbackGenerator.notificationOccurred(hapticFeedbackStyle) + Task { @MainActor in + feedbackGenerator.notificationOccurred(hapticFeedbackStyle) + } } } case .image(let image): diff --git a/Sources/MisticaSwiftUI/Components/Feedback/FeedbackStyle.swift b/Sources/MisticaSwiftUI/Components/Feedback/FeedbackStyle.swift index 5398262a..783b8226 100644 --- a/Sources/MisticaSwiftUI/Components/Feedback/FeedbackStyle.swift +++ b/Sources/MisticaSwiftUI/Components/Feedback/FeedbackStyle.swift @@ -16,6 +16,7 @@ enum FeedbackIconStyle { case animation(LottieView) } +@MainActor public enum FeedbackStyle { case success case error(reference: String?) diff --git a/Sources/MisticaSwiftUI/Components/Inputfield/LegacyTextField.swift b/Sources/MisticaSwiftUI/Components/Inputfield/LegacyTextField.swift index 4181be8d..2c7b29d2 100644 --- a/Sources/MisticaSwiftUI/Components/Inputfield/LegacyTextField.swift +++ b/Sources/MisticaSwiftUI/Components/Inputfield/LegacyTextField.swift @@ -160,10 +160,12 @@ extension LegacyTextFieldCoordinator: UIPickerViewDelegate, UIPickerViewDataSour // MARK: Date picker extension LegacyTextFieldCoordinator { + @MainActor @objc func doneButtonTapped(sender: UIBarButtonItem) { textField?.endEditing(true) } + @MainActor @objc func datePickerValueChanged(picker: UIDatePicker) { guard case .date(let format, _) = inputStyle else { return } formatter.dateFormat = format diff --git a/Sources/MisticaSwiftUI/Components/Skeletons/Skeleton.swift b/Sources/MisticaSwiftUI/Components/Skeletons/Skeleton.swift index 63311324..a3316624 100644 --- a/Sources/MisticaSwiftUI/Components/Skeletons/Skeleton.swift +++ b/Sources/MisticaSwiftUI/Components/Skeletons/Skeleton.swift @@ -18,10 +18,10 @@ public enum SkeletonType { public struct Skeleton: View { enum Constants { - static var lineHeight = 8.0 - static var radius = MisticaConfig.currentCornerRadius.container - static var spacing = 16.0 - static var circleSize = 40.0 + static let lineHeight = 8.0 + static let radius = MisticaConfig.currentCornerRadius.container + static let spacing = 16.0 + static let circleSize = 40.0 } let type: SkeletonType diff --git a/Sources/MisticaSwiftUI/Components/Snackbar/Snackbar.swift b/Sources/MisticaSwiftUI/Components/Snackbar/Snackbar.swift index 19418b62..45597185 100644 --- a/Sources/MisticaSwiftUI/Components/Snackbar/Snackbar.swift +++ b/Sources/MisticaSwiftUI/Components/Snackbar/Snackbar.swift @@ -105,7 +105,9 @@ public struct Snackbar: View { } timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false, block: { _ in - executeDismissHandlerBlock(with: .timeout) + Task { @MainActor in + executeDismissHandlerBlock(with: .timeout) + } }) }) } diff --git a/Sources/MisticaSwiftUI/Components/Tabs/TabItem.swift b/Sources/MisticaSwiftUI/Components/Tabs/TabItem.swift index ccbf98cd..7050b73d 100644 --- a/Sources/MisticaSwiftUI/Components/Tabs/TabItem.swift +++ b/Sources/MisticaSwiftUI/Components/Tabs/TabItem.swift @@ -24,8 +24,8 @@ public struct TabItem: Equatable { } public struct TabItemView: Equatable, View { - private var tabItem: TabItem - private var indexRow: Int + nonisolated(unsafe) private var tabItem: TabItem + nonisolated private var indexRow: Int @Binding private var selectedIndexRow: Int private var textAccessibilityLabel: String? @@ -43,7 +43,7 @@ public struct TabItemView: Equatable, View { _selectedIndexRow = selectedIndexRow } - public static func == (lhs: TabItemView, rhs: TabItemView) -> Bool { + nonisolated public static func == (lhs: TabItemView, rhs: TabItemView) -> Bool { lhs.tabItem == rhs.tabItem && lhs.indexRow == rhs.indexRow } diff --git a/Sources/MisticaSwiftUI/Components/Tabs/Tabs.swift b/Sources/MisticaSwiftUI/Components/Tabs/Tabs.swift index ba789128..3bc072b6 100644 --- a/Sources/MisticaSwiftUI/Components/Tabs/Tabs.swift +++ b/Sources/MisticaSwiftUI/Components/Tabs/Tabs.swift @@ -130,7 +130,7 @@ public struct Tabs: View { struct CGFloatPreferenceKey: PreferenceKey { typealias Value = CGFloat - static var defaultValue: Value = 0 + static let defaultValue: Value = 0 static func reduce(value _: inout Value, nextValue: () -> Value) { _ = nextValue() diff --git a/Sources/MisticaSwiftUI/Utils/Extensions/EnvironmentValues.swift b/Sources/MisticaSwiftUI/Utils/Extensions/EnvironmentValues.swift index 58deb829..4f004768 100644 --- a/Sources/MisticaSwiftUI/Utils/Extensions/EnvironmentValues.swift +++ b/Sources/MisticaSwiftUI/Utils/Extensions/EnvironmentValues.swift @@ -21,7 +21,7 @@ public extension EnvironmentValues { @available(iOSApplicationExtension, unavailable) private struct SafeAreaInsetsKey: EnvironmentKey { static var defaultValue: EdgeInsets { - UIApplication.shared.keyWindow?.safeAreaInsets.swiftUiInsets ?? EdgeInsets() + EdgeInsets() } } diff --git a/Sources/MisticaSwiftUI/Utils/Extensions/View+Utils.swift b/Sources/MisticaSwiftUI/Utils/Extensions/View+Utils.swift index 796b3e3e..b7109d1f 100644 --- a/Sources/MisticaSwiftUI/Utils/Extensions/View+Utils.swift +++ b/Sources/MisticaSwiftUI/Utils/Extensions/View+Utils.swift @@ -71,7 +71,7 @@ public extension View { frame(maxHeight: .infinity, alignment: alignment) } - func eraseToAnyView() -> AnyView { + nonisolated func eraseToAnyView() -> AnyView { AnyView(self) } diff --git a/Sources/MisticaSwiftUI/Utils/Modifiers/SizeViewModifier.swift b/Sources/MisticaSwiftUI/Utils/Modifiers/SizeViewModifier.swift index c5436787..f3027446 100644 --- a/Sources/MisticaSwiftUI/Utils/Modifiers/SizeViewModifier.swift +++ b/Sources/MisticaSwiftUI/Utils/Modifiers/SizeViewModifier.swift @@ -10,7 +10,7 @@ import Foundation import SwiftUI struct SizePreferenceKey: PreferenceKey { - static var defaultValue: CGSize = .zero + static let defaultValue: CGSize = .zero static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() diff --git a/Tests/MisticaCommonTests/Fonts/FontStyleTests.swift b/Tests/MisticaCommonTests/Fonts/FontStyleTests.swift index 0c2a36cf..aea1664c 100644 --- a/Tests/MisticaCommonTests/Fonts/FontStyleTests.swift +++ b/Tests/MisticaCommonTests/Fonts/FontStyleTests.swift @@ -13,7 +13,7 @@ import XCTest final class FontStyleTests: XCTestCase { override class func setUp() { - FontStyle.uiFontNameForWeight = { weight in + FontManager.shared.uiFontNameForWeight = { weight in switch weight { case .light, .ultraLight, .thin: return "Telefonica-Light" @@ -30,7 +30,7 @@ final class FontStyleTests: XCTestCase { } override class func tearDown() { - FontStyle.uiFontNameForWeight = nil + FontManager.shared.uiFontNameForWeight = nil } func testMovistarCustomFonts() { diff --git a/Tests/MisticaCommonTests/Fonts/FontToolkitTests.swift b/Tests/MisticaCommonTests/Fonts/FontToolkitTests.swift index a77e1a2a..61a99045 100644 --- a/Tests/MisticaCommonTests/Fonts/FontToolkitTests.swift +++ b/Tests/MisticaCommonTests/Fonts/FontToolkitTests.swift @@ -11,11 +11,12 @@ import SnapshotTesting import UIKit import XCTest +@MainActor final class FontToolkitTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testFonts() { diff --git a/Tests/MisticaCommonTests/TestHelpers.swift b/Tests/MisticaCommonTests/TestHelpers.swift index 37a5840d..6ab73e00 100644 --- a/Tests/MisticaCommonTests/TestHelpers.swift +++ b/Tests/MisticaCommonTests/TestHelpers.swift @@ -22,9 +22,10 @@ extension UIView { // MARK: - Helpers +@MainActor func assertSnapshotForAllBrandsAndStyles( as snapshotting: Snapshotting, - file: StaticString = #file, + file: StaticString = #filePath, testName: String = #function, line: UInt = #line, viewBuilder: @autoclosure () -> View @@ -33,7 +34,7 @@ func assertSnapshotForAllBrandsAndStyles( MisticaConfig.brandStyle = brand assertSnapshot( - matching: viewBuilder(), + of: viewBuilder(), as: snapshotting, named: "with-\(brand)-style", file: file, @@ -45,7 +46,7 @@ func assertSnapshotForAllBrandsAndStyles( darkView.overrideUserInterfaceStyle = .dark assertSnapshot( - matching: darkView, + of: darkView, as: snapshotting, named: "with-\(brand)-dark-style", file: file, @@ -55,6 +56,7 @@ func assertSnapshotForAllBrandsAndStyles( } } +@MainActor protocol UserInterfaceStyling { var overrideUserInterfaceStyle: UIUserInterfaceStyle { get set } } diff --git a/Tests/MisticaSwiftUITests/TestHelpers.swift b/Tests/MisticaSwiftUITests/TestHelpers.swift index 37a5840d..eada6716 100644 --- a/Tests/MisticaSwiftUITests/TestHelpers.swift +++ b/Tests/MisticaSwiftUITests/TestHelpers.swift @@ -22,9 +22,29 @@ extension UIView { // MARK: - Helpers +@MainActor +public func assertSnapshotWithoutAnimations( + of value: @autoclosure () throws -> Value, + as snapshotting: Snapshotting, + file: StaticString = #filePath, + testName: String = #function, + line: UInt = #line +) { + UIView.setAnimationsEnabled(false) + + assertSnapshot( + of: try value(), + as: snapshotting, + file: file, + testName: testName, + line: line + ) +} + +@MainActor func assertSnapshotForAllBrandsAndStyles( as snapshotting: Snapshotting, - file: StaticString = #file, + file: StaticString = #filePath, testName: String = #function, line: UInt = #line, viewBuilder: @autoclosure () -> View @@ -33,7 +53,7 @@ func assertSnapshotForAllBrandsAndStyles( MisticaConfig.brandStyle = brand assertSnapshot( - matching: viewBuilder(), + of: viewBuilder(), as: snapshotting, named: "with-\(brand)-style", file: file, @@ -45,7 +65,7 @@ func assertSnapshotForAllBrandsAndStyles( darkView.overrideUserInterfaceStyle = .dark assertSnapshot( - matching: darkView, + of: darkView, as: snapshotting, named: "with-\(brand)-dark-style", file: file, @@ -55,6 +75,7 @@ func assertSnapshotForAllBrandsAndStyles( } } +@MainActor protocol UserInterfaceStyling { var overrideUserInterfaceStyle: UIUserInterfaceStyle { get set } } diff --git a/Tests/MisticaSwiftUITests/UI/BadgeTests.swift b/Tests/MisticaSwiftUITests/UI/BadgeTests.swift index dd68062f..fabbf191 100644 --- a/Tests/MisticaSwiftUITests/UI/BadgeTests.swift +++ b/Tests/MisticaSwiftUITests/UI/BadgeTests.swift @@ -11,21 +11,24 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class BadgeTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testNumericBadgeContent() { assertSnapshot( - matching: makeTemplateWithNumericBadge(), + of: makeTemplateWithNumericBadge(), as: .image ) } func testFlagBadgeContent() { assertSnapshot( - matching: makeTemplateWithFlagBadge(), + of: makeTemplateWithFlagBadge(), as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/ButtonTests.swift b/Tests/MisticaSwiftUITests/UI/ButtonTests.swift index 6bb49d36..36dd6910 100644 --- a/Tests/MisticaSwiftUITests/UI/ButtonTests.swift +++ b/Tests/MisticaSwiftUITests/UI/ButtonTests.swift @@ -11,72 +11,75 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class ButtonTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: Regular Buttons func testRegularSizeWithPrimaryStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaPrimary(small: false)), + of: makeTemplateWithAllButtonStates(style: .misticaPrimary(small: false)), as: .image ) } func testRegularSizeWithPrimaryInverseStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaPrimaryInverse(small: false), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaPrimaryInverse(small: false), inverse: true), as: .image ) } func testRegularSizeWithSecondaryStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaSecondary(small: false)), + of: makeTemplateWithAllButtonStates(style: .misticaSecondary(small: false)), as: .image ) } func testRegularSizeWithSecondaryInverseStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaSecondaryInverse(small: false), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaSecondaryInverse(small: false), inverse: true), as: .image ) } func testRegularSizeWithDangerStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaDanger(small: false)), + of: makeTemplateWithAllButtonStates(style: .misticaDanger(small: false)), as: .image ) } func testRegularSizeWithLinkStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLink(small: false)), + of: makeTemplateWithAllButtonStates(style: .misticaLink(small: false)), as: .image ) } func testRegularSizeWithLinkInverseStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(small: false), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(small: false), inverse: true), as: .image ) } func testRegularSizeWithLinkWithChevron() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLink(withChevron: true)), + of: makeTemplateWithAllButtonStates(style: .misticaLink(withChevron: true)), as: .image ) } func testRegularSizeWithLinkInverseWithChevron() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(withChevron: true), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(withChevron: true), inverse: true), as: .image ) } @@ -85,63 +88,63 @@ final class ButtonTests: XCTestCase { func testSmallSizeWithPrimaryStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaPrimary(small: true)), + of: makeTemplateWithAllButtonStates(style: .misticaPrimary(small: true)), as: .image ) } func testSmallSizeWithPrimaryInverseStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaPrimaryInverse(small: true), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaPrimaryInverse(small: true), inverse: true), as: .image ) } func testSmallSizeWithSecondaryStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaSecondary(small: true)), + of: makeTemplateWithAllButtonStates(style: .misticaSecondary(small: true)), as: .image ) } func testSmallSizeWithSecondaryInverseStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaSecondaryInverse(small: true), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaSecondaryInverse(small: true), inverse: true), as: .image ) } func testSmallSizeWithDangerStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaDanger(small: true)), + of: makeTemplateWithAllButtonStates(style: .misticaDanger(small: true)), as: .image ) } func testSmallSizeWithLinkStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLink(small: true)), + of: makeTemplateWithAllButtonStates(style: .misticaLink(small: true)), as: .image ) } func testSmallSizeWithLinkInverseStyle() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(small: true), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(small: true), inverse: true), as: .image ) } func testSmallSizeWithLinkWithChevron() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLink(small: true, withChevron: true)), + of: makeTemplateWithAllButtonStates(style: .misticaLink(small: true, withChevron: true)), as: .image ) } func testSmallSizeWithLinkInverseWithChevron() { assertSnapshot( - matching: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(small: true, withChevron: true), inverse: true), + of: makeTemplateWithAllButtonStates(style: .misticaLinkInverse(small: true, withChevron: true), inverse: true), as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/CalloutTests.swift b/Tests/MisticaSwiftUITests/UI/CalloutTests.swift index 592a458e..8d545007 100644 --- a/Tests/MisticaSwiftUITests/UI/CalloutTests.swift +++ b/Tests/MisticaSwiftUITests/UI/CalloutTests.swift @@ -11,11 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class CalloutTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testPrimary() { @@ -27,7 +28,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -42,7 +43,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -57,7 +58,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -71,7 +72,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -86,7 +87,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -100,7 +101,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -113,7 +114,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -125,7 +126,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -141,7 +142,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -156,7 +157,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } @@ -172,7 +173,7 @@ final class CalloutTests: XCTestCase { .frame(width: 350) assertSnapshot( - matching: callout, + of: callout, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/CarouselTests.swift b/Tests/MisticaSwiftUITests/UI/CarouselTests.swift index 702ae6f7..189b1002 100644 --- a/Tests/MisticaSwiftUITests/UI/CarouselTests.swift +++ b/Tests/MisticaSwiftUITests/UI/CarouselTests.swift @@ -11,57 +11,59 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class CarouselTests: XCTestCase { - override class func setUp() { - super.setUp() - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testFree() { assertSnapshot( - matching: givenCarousel(scrollStyle: .free), + of: givenCarousel(scrollStyle: .free), as: .image ) } func testPaginated() { assertSnapshot( - matching: givenCarousel(scrollStyle: .paginated), + of: givenCarousel(scrollStyle: .paginated), as: .image ) } func testIndex() { assertSnapshot( - matching: givenCarousel(index: .constant(1)), + of: givenCarousel(index: .constant(1)), as: .image ) } func testNoBullets() { assertSnapshot( - matching: givenCarousel(controlStyle: .disabled), + of: givenCarousel(controlStyle: .disabled), as: .image ) } func testLeadingBullets() { assertSnapshot( - matching: givenCarousel(controlStyle: .bullets, controlAlignment: .leading), + of: givenCarousel(controlStyle: .bullets, controlAlignment: .leading), as: .image ) } func testTrailingBullets() { assertSnapshot( - matching: givenCarousel(controlStyle: .bullets, controlAlignment: .trailing), + of: givenCarousel(controlStyle: .bullets, controlAlignment: .trailing), as: .image ) } func testFullWith() { assertSnapshot( - matching: givenCarousel(carouselStyle: .fullWidth), + of: givenCarousel(carouselStyle: .fullWidth), as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/CheckboxTests.swift b/Tests/MisticaSwiftUITests/UI/CheckboxTests.swift index f51ffd48..2b5fb647 100644 --- a/Tests/MisticaSwiftUITests/UI/CheckboxTests.swift +++ b/Tests/MisticaSwiftUITests/UI/CheckboxTests.swift @@ -11,16 +11,19 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class CheckboxTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testUnselectedCheckbox() { let checkbox = Checkbox(isSelected: .constant(false)) assertSnapshot( - matching: checkbox, + of: checkbox, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/ChipTests.swift b/Tests/MisticaSwiftUITests/UI/ChipTests.swift index 66aebbee..ea6d27b0 100644 --- a/Tests/MisticaSwiftUITests/UI/ChipTests.swift +++ b/Tests/MisticaSwiftUITests/UI/ChipTests.swift @@ -11,16 +11,19 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class ChipTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testTooShortChip() { let chip = Chip(style: .normal, text: "", isSelected: .constant(false)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -29,7 +32,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .normal, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", icon: .search, onDismiss: {}) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -38,7 +41,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .normal, text: "Lorem ipsum", icon: .search, onDismiss: {}) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -47,7 +50,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .normal, text: "Lorem ipsum", onDismiss: {}) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -56,7 +59,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .normal, text: "Lorem ipsum", icon: .search, isSelected: .constant(false)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -65,7 +68,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .normal, text: "Lorem ipsum", icon: .search, isSelected: .constant(true)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -74,7 +77,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .inverse, text: "", isSelected: .constant(false)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -83,7 +86,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .inverse, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", icon: .search, isSelected: .constant(false)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -92,7 +95,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .inverse, text: "Lorem ipsum", icon: .search, onDismiss: {}) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -101,7 +104,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .inverse, text: "Lorem ipsum", icon: nil, onDismiss: {}) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -110,7 +113,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .inverse, text: "Lorem ipsum", icon: .search, isSelected: .constant(false)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } @@ -119,7 +122,7 @@ final class ChipTests: XCTestCase { let chip = Chip(style: .inverse, text: "Lorem ipsum", icon: .search, isSelected: .constant(true)) assertSnapshot( - matching: fixedContainer { chip }, + of: fixedContainer { chip }, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/CroutonTests.swift b/Tests/MisticaSwiftUITests/UI/CroutonTests.swift index 3c1beb46..78ccf098 100644 --- a/Tests/MisticaSwiftUITests/UI/CroutonTests.swift +++ b/Tests/MisticaSwiftUITests/UI/CroutonTests.swift @@ -11,9 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class CroutonTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testTitle() { @@ -25,7 +28,7 @@ final class CroutonTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -39,7 +42,7 @@ final class CroutonTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -53,7 +56,7 @@ final class CroutonTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -68,7 +71,7 @@ final class CroutonTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -83,7 +86,7 @@ final class CroutonTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -97,7 +100,7 @@ final class CroutonTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -110,7 +113,7 @@ final class CroutonTests: XCTestCase { config: SnackbarConfig(title: "Title", dismissInterval: .tenSeconds(SnackbarAction(title: "Action", handler: {}))) ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -123,7 +126,7 @@ final class CroutonTests: XCTestCase { config: SnackbarConfig(title: "Title", dismissInterval: .infinite(SnackbarAction(title: "Action", handler: {})), forceDismiss: true) ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -137,7 +140,7 @@ final class CroutonTests: XCTestCase { config: SnackbarConfig(title: "Title", dismissInterval: .infinite(SnackbarAction(title: "Large Action", handler: {})), forceDismiss: true) ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } diff --git a/Tests/MisticaSwiftUITests/UI/DataCardTests.swift b/Tests/MisticaSwiftUITests/UI/DataCardTests.swift index 0339b78a..ddc8ea79 100644 --- a/Tests/MisticaSwiftUITests/UI/DataCardTests.swift +++ b/Tests/MisticaSwiftUITests/UI/DataCardTests.swift @@ -11,6 +11,7 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class DataCardTests: XCTestCase { private enum Constants { static let headline = "Headline" @@ -20,10 +21,10 @@ final class DataCardTests: XCTestCase { static let multiLineMessage = "Nam non ipsum id metus cursus dictum. Praesent efficitur erat libero, vitae tempus orci iaculis id. Proin ipsum ante, auctor mattis rutrum sit amet, elementum vitae quam. Praesent velit lectus, lacinia ut accumsan sit amet, convallis non leo. Ut quis facilisis sapien. " } - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testAlternativeColors() { @@ -49,7 +50,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -66,7 +67,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -83,7 +84,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -98,7 +99,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: UIHostingController(rootView: dataCard), + of: UIHostingController(rootView: dataCard), as: .image(on: .iPhone8) ) } @@ -114,7 +115,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -130,7 +131,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -146,7 +147,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -164,7 +165,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -180,7 +181,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -199,7 +200,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -219,7 +220,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -239,7 +240,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -258,7 +259,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -274,7 +275,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } @@ -290,7 +291,7 @@ final class DataCardTests: XCTestCase { .padding(16) assertSnapshot( - matching: dataCard, + of: dataCard, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/EmptyStateTests.swift b/Tests/MisticaSwiftUITests/UI/EmptyStateTests.swift index 23128599..155832c2 100644 --- a/Tests/MisticaSwiftUITests/UI/EmptyStateTests.swift +++ b/Tests/MisticaSwiftUITests/UI/EmptyStateTests.swift @@ -11,9 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class EmptyStateTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testIconAsset() { @@ -26,7 +29,7 @@ final class EmptyStateTests: XCTestCase { ) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -42,7 +45,7 @@ final class EmptyStateTests: XCTestCase { .frame(width: 300, height: 300) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -57,7 +60,7 @@ final class EmptyStateTests: XCTestCase { ) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -73,7 +76,7 @@ final class EmptyStateTests: XCTestCase { .frame(height: 300) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -87,7 +90,7 @@ final class EmptyStateTests: XCTestCase { ) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -101,7 +104,7 @@ final class EmptyStateTests: XCTestCase { ) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -115,7 +118,7 @@ final class EmptyStateTests: XCTestCase { .frame(width: 150) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -129,7 +132,7 @@ final class EmptyStateTests: XCTestCase { ) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } @@ -146,7 +149,7 @@ final class EmptyStateTests: XCTestCase { .padding(24) assertSnapshot( - matching: emptyState, + of: emptyState, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/FeedbackTests.swift b/Tests/MisticaSwiftUITests/UI/FeedbackTests.swift index 68ffb369..d4ee3003 100644 --- a/Tests/MisticaSwiftUITests/UI/FeedbackTests.swift +++ b/Tests/MisticaSwiftUITests/UI/FeedbackTests.swift @@ -11,6 +11,7 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class FeedbackTests: XCTestCase { private enum Constants { static let singleLineTitle = "Title" @@ -19,18 +20,17 @@ final class FeedbackTests: XCTestCase { static let multiLineSubtitle = "Nam non ipsum id metus cursus dictum. Praesent efficitur erat libero, vitae tempus orci iaculis id. Proin ipsum ante, auctor mattis rutrum sit amet, elementum vitae quam. Praesent velit lectus, lacinia ut accumsan sit amet, convallis non leo. Ut quis facilisis sapien. " } - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .failed) { + super.invokeTest() + } } func testInformative() { let feedback = makeTemplate(style: .informative) - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -38,8 +38,8 @@ final class FeedbackTests: XCTestCase { func testError() { let feedback = makeTemplate(style: .error(reference: nil)) - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -47,8 +47,8 @@ final class FeedbackTests: XCTestCase { func testErrorReference() { let feedback = makeTemplate(style: .error(reference: "Error reference: #1992")) - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -56,8 +56,8 @@ final class FeedbackTests: XCTestCase { func testSuccess() { let feedback = makeTemplate(style: .success) - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -65,8 +65,8 @@ final class FeedbackTests: XCTestCase { func testFeedback() { let feedback = makeTemplate(style: .feedback(Image(systemName: "swift"))) - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -75,7 +75,7 @@ final class FeedbackTests: XCTestCase { let feedback = makeTemplate(style: .informative, title: Constants.multiLineTitle, message: Constants.multiLineSubtitle) assertSnapshot( - matching: UIHostingController(rootView: feedback), + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -94,7 +94,7 @@ final class FeedbackTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: feedback), + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -113,7 +113,7 @@ final class FeedbackTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: feedback), + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -135,7 +135,7 @@ final class FeedbackTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: feedback), + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -154,7 +154,7 @@ final class FeedbackTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: feedback), + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -172,8 +172,8 @@ final class FeedbackTests: XCTestCase { Button("Link", action: {}) } - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } @@ -191,8 +191,8 @@ final class FeedbackTests: XCTestCase { Button("Link", action: {}) } - assertSnapshot( - matching: UIHostingController(rootView: feedback), + assertSnapshotWithoutAnimations( + of: UIHostingController(rootView: feedback), as: .image(on: .iPhone8) ) } diff --git a/Tests/MisticaSwiftUITests/UI/GradientTests.swift b/Tests/MisticaSwiftUITests/UI/GradientTests.swift index 5aaf33a7..525a9a9e 100644 --- a/Tests/MisticaSwiftUITests/UI/GradientTests.swift +++ b/Tests/MisticaSwiftUITests/UI/GradientTests.swift @@ -11,9 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class GradientTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testGradientInView() { @@ -21,7 +24,7 @@ final class GradientTests: XCTestCase { let misticaColor: MisticaColor = .gradient(misticaGradient) assertSnapshot( - matching: makeTemplate(misticaColor: misticaColor), + of: makeTemplate(misticaColor: misticaColor), as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/HeaderTests.swift b/Tests/MisticaSwiftUITests/UI/HeaderTests.swift index 9a3afcc8..33b163b4 100644 --- a/Tests/MisticaSwiftUITests/UI/HeaderTests.swift +++ b/Tests/MisticaSwiftUITests/UI/HeaderTests.swift @@ -11,12 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class HeaderTests: XCTestCase { - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } } @@ -30,7 +30,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -42,7 +42,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -54,7 +54,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -66,7 +66,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -78,7 +78,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -90,7 +90,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -106,7 +106,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -120,7 +120,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -134,7 +134,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -148,7 +148,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -166,7 +166,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -180,7 +180,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } @@ -194,7 +194,7 @@ extension HeaderTests { ) assertSnapshot( - matching: UIHostingController(rootView: header), + of: UIHostingController(rootView: header), as: .image(on: .iPhone8) ) } diff --git a/Tests/MisticaSwiftUITests/UI/InputFieldTests.swift b/Tests/MisticaSwiftUITests/UI/InputFieldTests.swift index 78508d34..963ce9f3 100644 --- a/Tests/MisticaSwiftUITests/UI/InputFieldTests.swift +++ b/Tests/MisticaSwiftUITests/UI/InputFieldTests.swift @@ -11,19 +11,19 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class InputFieldTests: XCTestCase { - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testText() { let input = makeTemplate(style: .text) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -32,7 +32,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .secure) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -41,7 +41,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .phone(code: "+34")) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -50,7 +50,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .search) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -59,7 +59,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .date()) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -68,7 +68,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .dropdown(options: ["1", "2"])) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -77,7 +77,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .text, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque ullamcorper at justo eget porta. Pellentesque sit amet felis vel eros commodo euismod vel quis nisl.") assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -86,7 +86,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .text, placeholder: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque ullamcorper at justo eget porta. Pellentesque sit amet felis vel eros commodo euismod vel quis nisl.") assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -95,7 +95,7 @@ final class InputFieldTests: XCTestCase { let input = makeTemplate(style: .text, assistiveText: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque ullamcorper at justo eget porta. Pellentesque sit amet felis vel eros commodo euismod vel quis nisl.") assertSnapshot( - matching: input, + of: input, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/ListTests.swift b/Tests/MisticaSwiftUITests/UI/ListTests.swift index ff4bfe63..af0e1ae8 100644 --- a/Tests/MisticaSwiftUITests/UI/ListTests.swift +++ b/Tests/MisticaSwiftUITests/UI/ListTests.swift @@ -11,21 +11,24 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class ListTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testFullwidthRowContent() { assertSnapshot( - matching: makeTemplateWithStyle(style: .fullwidth), + of: makeTemplateWithStyle(style: .fullwidth), as: .image ) } func testBoxedRowContent() { assertSnapshot( - matching: makeTemplateWithStyle(style: .boxed), + of: makeTemplateWithStyle(style: .boxed), as: .image ) } @@ -39,7 +42,7 @@ final class ListTests: XCTestCase { ).frame(width: 400, height: 200) assertSnapshot( - matching: row, + of: row, as: .image ) } @@ -53,7 +56,7 @@ final class ListTests: XCTestCase { ).frame(width: 400, height: 200) assertSnapshot( - matching: row, + of: row, as: .image ) } @@ -90,7 +93,7 @@ final class ListTests: XCTestCase { .frame(width: 250, height: 400) assertSnapshot( - matching: rows, + of: rows, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/RadioButtonTests.swift b/Tests/MisticaSwiftUITests/UI/RadioButtonTests.swift index 34776a5a..46e48038 100644 --- a/Tests/MisticaSwiftUITests/UI/RadioButtonTests.swift +++ b/Tests/MisticaSwiftUITests/UI/RadioButtonTests.swift @@ -11,16 +11,19 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class RadioButtonTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testSelectedRadioButton() { let radioButton = RadioButton(isSelected: .constant(true)) assertSnapshot( - matching: radioButton, + of: radioButton, as: .image ) } @@ -29,7 +32,7 @@ final class RadioButtonTests: XCTestCase { let radioButton = RadioButton(isSelected: .constant(false)) assertSnapshot( - matching: radioButton, + of: radioButton, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/SkeletonTests.swift b/Tests/MisticaSwiftUITests/UI/SkeletonTests.swift index 0bc89da8..18a3e1f6 100644 --- a/Tests/MisticaSwiftUITests/UI/SkeletonTests.swift +++ b/Tests/MisticaSwiftUITests/UI/SkeletonTests.swift @@ -11,16 +11,19 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class SkeletonTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testLineSkeleton() { let skeleton = Skeleton(type: .line(width: 300)) assertSnapshot( - matching: skeleton, + of: skeleton, as: .image ) } @@ -30,7 +33,7 @@ final class SkeletonTests: XCTestCase { .frame(width: 300, height: 60) assertSnapshot( - matching: skeleton, + of: skeleton, as: .image ) } @@ -40,7 +43,7 @@ final class SkeletonTests: XCTestCase { .frame(width: 300, height: 110) assertSnapshot( - matching: skeleton, + of: skeleton, as: .image ) } @@ -49,7 +52,7 @@ final class SkeletonTests: XCTestCase { let skeleton = Skeleton(type: .circle(size: CGSize(width: 40, height: 40))) assertSnapshot( - matching: skeleton, + of: skeleton, as: .image ) } @@ -59,7 +62,7 @@ final class SkeletonTests: XCTestCase { .frame(width: 300) assertSnapshot( - matching: skeleton, + of: skeleton, as: .image ) } @@ -68,7 +71,7 @@ final class SkeletonTests: XCTestCase { let skeleton = Skeleton(type: .rectangle(width: 360, height: 180, isRounded: true)) assertSnapshot( - matching: skeleton, + of: skeleton, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/SnackbarTests.swift b/Tests/MisticaSwiftUITests/UI/SnackbarTests.swift index 982b1c48..53fdecda 100644 --- a/Tests/MisticaSwiftUITests/UI/SnackbarTests.swift +++ b/Tests/MisticaSwiftUITests/UI/SnackbarTests.swift @@ -11,9 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class SnackbarTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testTitle() { @@ -25,7 +28,7 @@ final class SnackbarTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -39,7 +42,7 @@ final class SnackbarTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -53,7 +56,7 @@ final class SnackbarTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -68,7 +71,7 @@ final class SnackbarTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -83,7 +86,7 @@ final class SnackbarTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -97,7 +100,7 @@ final class SnackbarTests: XCTestCase { ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -110,7 +113,7 @@ final class SnackbarTests: XCTestCase { config: SnackbarConfig(title: "Title", dismissInterval: .tenSeconds(SnackbarAction(title: "Action", handler: {}))) ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -123,7 +126,7 @@ final class SnackbarTests: XCTestCase { config: SnackbarConfig(title: "Title", dismissInterval: .infinite(SnackbarAction(title: "Action", handler: {})), forceDismiss: true) ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } @@ -137,7 +140,7 @@ final class SnackbarTests: XCTestCase { config: SnackbarConfig(title: "Title", dismissInterval: .infinite(SnackbarAction(title: "Large Action", handler: {})), forceDismiss: true) ) assertSnapshot( - matching: UIHostingController(rootView: view), + of: UIHostingController(rootView: view), as: .image(on: .iPhone8) ) } diff --git a/Tests/MisticaSwiftUITests/UI/StepperTests.swift b/Tests/MisticaSwiftUITests/UI/StepperTests.swift index 9e7e977b..ddea35b2 100644 --- a/Tests/MisticaSwiftUITests/UI/StepperTests.swift +++ b/Tests/MisticaSwiftUITests/UI/StepperTests.swift @@ -11,19 +11,19 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class StepperTests: XCTestCase { - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testStepZeroOfFourSteps() { let input = makeTemplate(step: 0, steps: 4) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -32,7 +32,7 @@ final class StepperTests: XCTestCase { let input = makeTemplate(step: 1, steps: 4) assertSnapshot( - matching: input, + of: input, as: .image ) } @@ -41,7 +41,7 @@ final class StepperTests: XCTestCase { let input = makeTemplate(step: 4, steps: 4) assertSnapshot( - matching: input, + of: input, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/TabsTests.swift b/Tests/MisticaSwiftUITests/UI/TabsTests.swift index b59e804c..468a6477 100644 --- a/Tests/MisticaSwiftUITests/UI/TabsTests.swift +++ b/Tests/MisticaSwiftUITests/UI/TabsTests.swift @@ -11,9 +11,12 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class TabsTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testTwoLongTabs() { @@ -21,7 +24,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -31,7 +34,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -41,7 +44,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -51,7 +54,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -61,7 +64,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -71,7 +74,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -81,7 +84,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -91,7 +94,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -101,7 +104,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } @@ -111,7 +114,7 @@ final class TabsTests: XCTestCase { .frame(width: 400) assertSnapshot( - matching: tabs, + of: tabs, as: .image ) } diff --git a/Tests/MisticaSwiftUITests/UI/TagTests.swift b/Tests/MisticaSwiftUITests/UI/TagTests.swift index fc27410b..b3b128f1 100644 --- a/Tests/MisticaSwiftUITests/UI/TagTests.swift +++ b/Tests/MisticaSwiftUITests/UI/TagTests.swift @@ -11,28 +11,31 @@ import SnapshotTesting import SwiftUI import XCTest +@MainActor final class TagTests: XCTestCase { - override class func setUp() { - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testLargeTagContent() { assertSnapshot( - matching: makeTemplateWithAllTags(content: "Large tag content"), + of: makeTemplateWithAllTags(content: "Large tag content"), as: .image ) } func testSmallTagContent() { assertSnapshot( - matching: makeTemplateWithAllTags(content: "Tag"), + of: makeTemplateWithAllTags(content: "Tag"), as: .image ) } func testSmallTagContentWitchIcon() { assertSnapshot( - matching: makeTemplateWithAllTags(content: "Tag", icon: true), + of: makeTemplateWithAllTags(content: "Tag", icon: true), as: .image ) } diff --git a/Tests/MisticaTests/UI/BadgeTests.swift b/Tests/MisticaTests/UI/BadgeTests.swift index 5b275ddf..d71f2282 100644 --- a/Tests/MisticaTests/UI/BadgeTests.swift +++ b/Tests/MisticaTests/UI/BadgeTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class BadgeTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testFlagBadge() { @@ -35,7 +36,7 @@ final class BadgeTests: XCTestCase { view.secondNumericBadge.style = .numeric view.secondNumericBadge.value = 1_000 - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } } diff --git a/Tests/MisticaTests/UI/ButtonTests.swift b/Tests/MisticaTests/UI/ButtonTests.swift index 472309d0..753f01d6 100644 --- a/Tests/MisticaTests/UI/ButtonTests.swift +++ b/Tests/MisticaTests/UI/ButtonTests.swift @@ -10,12 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class ButtonTests: XCTestCase { - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -187,7 +187,7 @@ final class ButtonTests: XCTestCase { buttonNormalState.title = "A very very very long long long long teeeext" assertSnapshot( - matching: buttonNormalState, + of: buttonNormalState, as: .image(size: CGSize(width: 156, height: 48)) ) } @@ -200,7 +200,7 @@ final class ButtonTests: XCTestCase { buttonNormalState.isLoading = true assertSnapshot( - matching: buttonNormalState, + of: buttonNormalState, as: .image(size: CGSize(width: 156, height: 48)) ) } @@ -214,7 +214,7 @@ final class ButtonTests: XCTestCase { button.rightImage = .chevron assertSnapshot( - matching: button, + of: button, as: .image(size: CGSize(width: 500, height: 48)) ) } @@ -223,7 +223,7 @@ final class ButtonTests: XCTestCase { MisticaConfig.brandStyle = .vivo assertSnapshot( - matching: makeTemplateWithRegularAndSmallButtonsAndLinkButton(), + of: makeTemplateWithRegularAndSmallButtonsAndLinkButton(), as: .image ) } @@ -232,7 +232,7 @@ final class ButtonTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: makeTemplateAlignment(contentMode: .left), + of: makeTemplateAlignment(contentMode: .left), as: .image ) } @@ -241,7 +241,7 @@ final class ButtonTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: makeTemplateAlignment(contentMode: .right), + of: makeTemplateAlignment(contentMode: .right), as: .image ) } @@ -256,7 +256,7 @@ final class ButtonTests: XCTestCase { buttonNormalState.loadingTitle = "Loading" assertSnapshot( - matching: buttonNormalState, + of: buttonNormalState, as: .image(size: buttonNormalState.intrinsicContentSize), named: "assertInitialState" ) @@ -264,7 +264,7 @@ final class ButtonTests: XCTestCase { buttonNormalState.isLoading = true assertSnapshot( - matching: buttonNormalState, + of: buttonNormalState, as: .image(size: buttonNormalState.intrinsicContentSize), named: "finalState" ) @@ -278,7 +278,7 @@ final class ButtonTests: XCTestCase { button.loadingTitle = "Loading" assertSnapshot( - matching: button, + of: button, as: .image(size: button.intrinsicContentSize), named: "assertInitialState" ) @@ -287,7 +287,7 @@ final class ButtonTests: XCTestCase { button.isLoading = false assertSnapshot( - matching: button, + of: button, as: .image(size: button.intrinsicContentSize), named: "finalState" ) @@ -300,7 +300,7 @@ final class ButtonTests: XCTestCase { button.title = "Regular" assertSnapshot( - matching: button, + of: button, as: .image(size: button.intrinsicContentSize), named: "assertInitialState" ) @@ -309,7 +309,7 @@ final class ButtonTests: XCTestCase { button.isEnabled = true assertSnapshot( - matching: button, + of: button, as: .image(size: button.intrinsicContentSize), named: "finalState" ) @@ -322,7 +322,7 @@ final class ButtonTests: XCTestCase { button.title = "Regular" assertSnapshot( - matching: button, + of: button, as: .image(size: button.intrinsicContentSize), named: "assertInitialState" ) @@ -331,7 +331,7 @@ final class ButtonTests: XCTestCase { button.isSelected = false assertSnapshot( - matching: button, + of: button, as: .image(size: button.intrinsicContentSize), named: "finalState" ) @@ -353,7 +353,7 @@ final class ButtonTests: XCTestCase { view.buttonCentered.isLoading = true assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneX) // We need a device with Safe Area ) } @@ -361,139 +361,141 @@ final class ButtonTests: XCTestCase { // MARK: - Helpers -private func makeTemplateWithAllButtonStates(style: Button.Style, isSmall: Bool, rightImage: Button.RightImage? = nil) -> UIView { - let buttonNormalState = Button() - buttonNormalState.title = "Normal" - buttonNormalState.style = style - buttonNormalState.isSmall = isSmall - buttonNormalState.rightImage = rightImage - - let buttonDisabledState = Button() - buttonDisabledState.title = "Disabled" - buttonDisabledState.style = style - buttonDisabledState.isEnabled = false - buttonDisabledState.isSmall = isSmall - buttonDisabledState.rightImage = rightImage - - let buttonSelectedState = Button() - buttonSelectedState.title = "Selected" - buttonSelectedState.style = style - buttonSelectedState.isSelected = true - buttonSelectedState.isSmall = isSmall - buttonSelectedState.rightImage = rightImage - - let buttonLoadingState = Button() - buttonLoadingState.loadingTitle = "Loading" - buttonLoadingState.style = style - buttonLoadingState.isLoading = true - buttonLoadingState.isSmall = isSmall - buttonLoadingState.rightImage = rightImage - - let vStack = UIStackView(arrangedSubviews: [ - buttonNormalState, - buttonSelectedState, - buttonDisabledState, - buttonLoadingState - ]) - - vStack.axis = .vertical - vStack.alignment = .center - vStack.spacing = 0 - vStack.frame = CGRect( - x: 0, - y: 0, - width: buttonLoadingState.intrinsicContentSize.width, - height: buttonLoadingState.intrinsicContentSize.height * 4 - ) - - return vStack -} - -private func makeTemplateWithRegularAndSmallButtonsAndLinkButton() -> UIStackView { - let smallButton = Button() - smallButton.title = "O" - smallButton.isSmall = true - - let regularButton = Button() - regularButton.title = "O" - - let linkButton = Button() - linkButton.title = "O" - linkButton.isSelected = true - linkButton.style = .link - - let vStack = UIStackView(arrangedSubviews: [ - smallButton, - regularButton, - linkButton - ]) - - let expectedWidth = vStack.arrangedSubviews - .map(\.intrinsicContentSize) - .map(\.width) - .reduce(CGFloat(0), CGFloat.maximum) - let expectedHeight = vStack.arrangedSubviews - .map(\.intrinsicContentSize) - .map(\.height) - .reduce(CGFloat(0), +) - - vStack.axis = .vertical - vStack.alignment = .center - vStack.spacing = 0 - vStack.frame = CGRect( - x: 0, - y: 0, - width: expectedWidth, - height: expectedHeight - ) - - return vStack -} - -private func makeTemplateAlignment(contentMode: UIView.ContentMode) -> UIView { - let containerView = UIView() - containerView.backgroundColor = .white - - let title = UILabel() - title.text = "Lorem ipsum dolor sit amet" - title.translatesAutoresizingMaskIntoConstraints = false - - let linkButton = Button() - linkButton.title = "Link" - linkButton.style = .link - linkButton.contentMode = contentMode - linkButton.translatesAutoresizingMaskIntoConstraints = false - - containerView.addSubview(title) - containerView.addSubview(linkButton) - - NSLayoutConstraint.activate([ - title.topAnchor.constraint(equalTo: containerView.topAnchor), - title.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -5), - title.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 5), - linkButton.topAnchor.constraint(equalTo: title.bottomAnchor) - ]) - - switch contentMode { - case .left: - linkButton.leadingAnchor.constraint(equalTo: title.leadingAnchor).isActive = true - case .right: - linkButton.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true - default: - fatalError("Sorry but at the moment of implementing this, I only took into account left and right contentMode") - } - - let expectedHeight = containerView.subviews - .map(\.intrinsicContentSize) - .map(\.height) - .reduce(CGFloat(0), +) - - containerView.frame = CGRect( - x: 0, - y: 0, - width: title.intrinsicContentSize.width + 10, // title width plus some margin - height: expectedHeight - ) - - return containerView +private extension ButtonTests { + func makeTemplateWithAllButtonStates(style: Button.Style, isSmall: Bool, rightImage: Button.RightImage? = nil) -> UIView { + let buttonNormalState = Button() + buttonNormalState.title = "Normal" + buttonNormalState.style = style + buttonNormalState.isSmall = isSmall + buttonNormalState.rightImage = rightImage + + let buttonDisabledState = Button() + buttonDisabledState.title = "Disabled" + buttonDisabledState.style = style + buttonDisabledState.isEnabled = false + buttonDisabledState.isSmall = isSmall + buttonDisabledState.rightImage = rightImage + + let buttonSelectedState = Button() + buttonSelectedState.title = "Selected" + buttonSelectedState.style = style + buttonSelectedState.isSelected = true + buttonSelectedState.isSmall = isSmall + buttonSelectedState.rightImage = rightImage + + let buttonLoadingState = Button() + buttonLoadingState.loadingTitle = "Loading" + buttonLoadingState.style = style + buttonLoadingState.isLoading = true + buttonLoadingState.isSmall = isSmall + buttonLoadingState.rightImage = rightImage + + let vStack = UIStackView(arrangedSubviews: [ + buttonNormalState, + buttonSelectedState, + buttonDisabledState, + buttonLoadingState + ]) + + vStack.axis = .vertical + vStack.alignment = .center + vStack.spacing = 0 + vStack.frame = CGRect( + x: 0, + y: 0, + width: buttonLoadingState.intrinsicContentSize.width, + height: buttonLoadingState.intrinsicContentSize.height * 4 + ) + + return vStack + } + + func makeTemplateWithRegularAndSmallButtonsAndLinkButton() -> UIStackView { + let smallButton = Button() + smallButton.title = "O" + smallButton.isSmall = true + + let regularButton = Button() + regularButton.title = "O" + + let linkButton = Button() + linkButton.title = "O" + linkButton.isSelected = true + linkButton.style = .link + + let vStack = UIStackView(arrangedSubviews: [ + smallButton, + regularButton, + linkButton + ]) + + let expectedWidth = vStack.arrangedSubviews + .map(\.intrinsicContentSize) + .map(\.width) + .reduce(CGFloat(0), CGFloat.maximum) + let expectedHeight = vStack.arrangedSubviews + .map(\.intrinsicContentSize) + .map(\.height) + .reduce(CGFloat(0), +) + + vStack.axis = .vertical + vStack.alignment = .center + vStack.spacing = 0 + vStack.frame = CGRect( + x: 0, + y: 0, + width: expectedWidth, + height: expectedHeight + ) + + return vStack + } + + func makeTemplateAlignment(contentMode: UIView.ContentMode) -> UIView { + let containerView = UIView() + containerView.backgroundColor = .white + + let title = UILabel() + title.text = "Lorem ipsum dolor sit amet" + title.translatesAutoresizingMaskIntoConstraints = false + + let linkButton = Button() + linkButton.title = "Link" + linkButton.style = .link + linkButton.contentMode = contentMode + linkButton.translatesAutoresizingMaskIntoConstraints = false + + containerView.addSubview(title) + containerView.addSubview(linkButton) + + NSLayoutConstraint.activate([ + title.topAnchor.constraint(equalTo: containerView.topAnchor), + title.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -5), + title.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 5), + linkButton.topAnchor.constraint(equalTo: title.bottomAnchor) + ]) + + switch contentMode { + case .left: + linkButton.leadingAnchor.constraint(equalTo: title.leadingAnchor).isActive = true + case .right: + linkButton.trailingAnchor.constraint(equalTo: title.trailingAnchor).isActive = true + default: + fatalError("Sorry but at the moment of implementing this, I only took into account left and right contentMode") + } + + let expectedHeight = containerView.subviews + .map(\.intrinsicContentSize) + .map(\.height) + .reduce(CGFloat(0), +) + + containerView.frame = CGRect( + x: 0, + y: 0, + width: title.intrinsicContentSize.width + 10, // title width plus some margin + height: expectedHeight + ) + + return containerView + } } diff --git a/Tests/MisticaTests/UI/CalloutTests.swift b/Tests/MisticaTests/UI/CalloutTests.swift index ce4ce450..e15ab1fc 100644 --- a/Tests/MisticaTests/UI/CalloutTests.swift +++ b/Tests/MisticaTests/UI/CalloutTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class CalloutTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -36,7 +37,7 @@ final class CalloutTests: XCTestCase { title: "This is a title" ) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testMinimumContent() { @@ -44,7 +45,7 @@ final class CalloutTests: XCTestCase { let view = makeBasicCallout() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContent() { @@ -52,7 +53,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutIcon() { @@ -60,7 +61,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutTitle() { @@ -68,7 +69,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(title: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryButtonOnly() { @@ -76,7 +77,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.primary(AnyValues.primary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryButtonOnlyWithoutAsset() { @@ -84,7 +85,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none, actions: CalloutConfiguration.CalloutActions.primary(AnyValues.primary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndLinkButtonsOnly() { @@ -92,7 +93,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.primaryAndLink(primary: AnyValues.primary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndLinkButtonsOnlyWithoutAsset() { @@ -100,7 +101,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none, actions: CalloutConfiguration.CalloutActions.primaryAndLink(primary: AnyValues.primary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndSecondaryButtonsOnly() { @@ -108,7 +109,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.primaryAndSecondary(primary: AnyValues.primary, secondary: AnyValues.secondary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndSecondaryButtonsOnlyWithoutAsset() { @@ -116,7 +117,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none, actions: CalloutConfiguration.CalloutActions.primaryAndSecondary(primary: AnyValues.primary, secondary: AnyValues.secondary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryButtonOnly() { @@ -124,7 +125,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.secondary(AnyValues.secondary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryButtonOnlyWithoutAsset() { @@ -132,7 +133,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none, actions: CalloutConfiguration.CalloutActions.secondary(AnyValues.secondary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryAndLinkButtonsOnly() { @@ -140,7 +141,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.secondaryAndLink(secondary: AnyValues.secondary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryAndLinkButtonsOnlyWithoutAsset() { @@ -148,7 +149,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none, actions: CalloutConfiguration.CalloutActions.secondaryAndLink(secondary: AnyValues.secondary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testLinkButtonOnly() { @@ -156,7 +157,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.link(AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testLinkButtonOnlyWithoutAsset() { @@ -164,7 +165,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(asset: .none, actions: CalloutConfiguration.CalloutActions.link(AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: Behaviour @@ -175,7 +176,7 @@ final class CalloutTests: XCTestCase { let view = makeCalloutWithContentAndButtons(actions: CalloutConfiguration.CalloutActions.primaryAndLink(primary: AnyValues.primary, link: AnyValues.link)) view.primaryButton.isLoading = true - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: XIB integration @@ -193,7 +194,7 @@ final class CalloutTests: XCTestCase { view.callout.contentConfiguration = configurationWithActions assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneX) ) } diff --git a/Tests/MisticaTests/UI/CarouselTests.swift b/Tests/MisticaTests/UI/CarouselTests.swift index 3b8275e2..d32289d3 100644 --- a/Tests/MisticaTests/UI/CarouselTests.swift +++ b/Tests/MisticaTests/UI/CarouselTests.swift @@ -10,14 +10,19 @@ import SnapshotTesting import XCTest +@MainActor final class CarouselTests: XCTestCase { override func setUp() { super.setUp() - - isRecording = false MisticaConfig.brandStyle = .movistar } + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } + } + // MARK: - Layout // MARK: - Default config @@ -28,7 +33,7 @@ final class CarouselTests: XCTestCase { ) assertSnapshot( - matching: carouselTestsViewController, + of: carouselTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -40,7 +45,7 @@ final class CarouselTests: XCTestCase { ) assertSnapshot( - matching: carouselTestsViewController, + of: carouselTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -52,7 +57,7 @@ final class CarouselTests: XCTestCase { ) assertSnapshot( - matching: carouselTestsViewController, + of: carouselTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -65,7 +70,7 @@ final class CarouselTests: XCTestCase { ) assertSnapshot( - matching: carouselTestsViewController, + of: carouselTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -79,7 +84,7 @@ final class CarouselTests: XCTestCase { ) assertSnapshot( - matching: carouselTestsViewController, + of: carouselTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -94,7 +99,7 @@ final class CarouselTests: XCTestCase { ) assertSnapshot( - matching: carouselTestsViewController, + of: carouselTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -216,6 +221,6 @@ extension CarouselTests { enum AnyValues { static let title = "Any title" static let subtitle = "Any subtitle" - static var image = UIImage(color: .green) + static let image = UIImage(color: .green) } } diff --git a/Tests/MisticaTests/UI/CheckboxTests.swift b/Tests/MisticaTests/UI/CheckboxTests.swift index a09caa1d..281a9709 100644 --- a/Tests/MisticaTests/UI/CheckboxTests.swift +++ b/Tests/MisticaTests/UI/CheckboxTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class CheckboxTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -42,7 +43,7 @@ final class CheckboxTests: XCTestCase { checkbox.isChecked = false assertSnapshot( - matching: checkbox, + of: checkbox, as: .image(size: checkbox.intrinsicContentSize), named: "assertInitialState" ) @@ -50,7 +51,7 @@ final class CheckboxTests: XCTestCase { checkbox.isChecked = true assertSnapshot( - matching: checkbox, + of: checkbox, as: .image(size: checkbox.intrinsicContentSize), named: "finalState" ) @@ -64,7 +65,7 @@ final class CheckboxTests: XCTestCase { let view = CheckboxXIBIntegration.viewFromNib() assertSnapshot( - matching: view, + of: view, as: .image ) } @@ -72,13 +73,15 @@ final class CheckboxTests: XCTestCase { // MARK: - Helpers -private func makeTemplateWithCheckboxState(isChecked: Bool) -> UIView { - let checkbox = Checkbox(frame: CGRect(origin: .zero, size: CGSize(width: 18, height: 18))) - checkbox.isChecked = isChecked +private extension CheckboxTests { + func makeTemplateWithCheckboxState(isChecked: Bool) -> UIView { + let checkbox = Checkbox(frame: CGRect(origin: .zero, size: CGSize(width: 18, height: 18))) + checkbox.isChecked = isChecked - let containerView = UIView(frame: CGRect(origin: .zero, size: checkbox.intrinsicContentSize)) - containerView.backgroundColor = .white - containerView.addSubview(checkbox) + let containerView = UIView(frame: CGRect(origin: .zero, size: checkbox.intrinsicContentSize)) + containerView.backgroundColor = .white + containerView.addSubview(checkbox) - return containerView + return containerView + } } diff --git a/Tests/MisticaTests/UI/ControlsTests.swift b/Tests/MisticaTests/UI/ControlsTests.swift index bb8b2afe..8bc904fa 100644 --- a/Tests/MisticaTests/UI/ControlsTests.swift +++ b/Tests/MisticaTests/UI/ControlsTests.swift @@ -10,11 +10,12 @@ import Mistica import SnapshotTesting import XCTest +@MainActor final class ControlsTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Switch Style @@ -47,14 +48,14 @@ final class ControlsTests: XCTestCase { func testTabBarControl() { let tabView = makeTabBarTemplate() assertSnapshot( - matching: tabView, + of: tabView, as: .image(size: CGSize(width: 420, height: 60)) ) tabView.overrideUserInterfaceStyle = .dark assertSnapshot( - matching: tabView, + of: tabView, as: .image(size: CGSize(width: 420, height: 60)), named: "with-dark-style" ) @@ -79,7 +80,7 @@ final class ControlsTests: XCTestCase { segmentedControl.selectedSegmentIndex = 1 assertSnapshot( - matching: segmentedControl, + of: segmentedControl, as: .image(size: segmentedControl.intrinsicContentSize), named: "assertInitialState" ) @@ -87,7 +88,7 @@ final class ControlsTests: XCTestCase { segmentedControl.selectedSegmentIndex = 3 assertSnapshot( - matching: segmentedControl, + of: segmentedControl, as: .image(size: segmentedControl.intrinsicContentSize), named: "finalState" ) @@ -103,7 +104,7 @@ final class ControlsTests: XCTestCase { tabBarController.selectedIndex = 1 assertSnapshot( - matching: tabBarController, + of: tabBarController, as: .image(size: CGSize(width: 420, height: 60)), named: "assertInitialState" ) @@ -111,7 +112,7 @@ final class ControlsTests: XCTestCase { tabBarController.selectedIndex = 2 assertSnapshot( - matching: tabBarController, + of: tabBarController, as: .image(size: CGSize(width: 420, height: 60)), named: "finalState" ) @@ -128,7 +129,7 @@ final class ControlsTests: XCTestCase { pageControl.currentPage = 3 assertSnapshot( - matching: pageControl, + of: pageControl, as: .image(size: pageControl.intrinsicContentSize), named: "assertInitialState" ) @@ -136,7 +137,7 @@ final class ControlsTests: XCTestCase { pageControl.currentPage = 1 assertSnapshot( - matching: pageControl, + of: pageControl, as: .image(size: pageControl.intrinsicContentSize), named: "finalState" ) diff --git a/Tests/MisticaTests/UI/CroutonTests.swift b/Tests/MisticaTests/UI/CroutonTests.swift index 15d1eef3..ea4130ba 100644 --- a/Tests/MisticaTests/UI/CroutonTests.swift +++ b/Tests/MisticaTests/UI/CroutonTests.swift @@ -10,12 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class CroutonTests: XCTestCase { - override func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testInfoCrouton() { diff --git a/Tests/MisticaTests/UI/DataCardTests.swift b/Tests/MisticaTests/UI/DataCardTests.swift index aeadfd3e..742fc19c 100644 --- a/Tests/MisticaTests/UI/DataCardTests.swift +++ b/Tests/MisticaTests/UI/DataCardTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class DataCardTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -32,7 +33,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(asset: .image(.init(color: .cyan))) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testShowAssetOfTypeIcon() { @@ -40,7 +41,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(asset: .icon(.init(color: .cyan), backgroundColor: .black)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testMinimumContent() { @@ -48,7 +49,7 @@ final class DataCardTests: XCTestCase { let view = makeBasicCard() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContent() { @@ -56,7 +57,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutIcon() { @@ -64,7 +65,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(asset: .none) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutHeadline() { @@ -72,7 +73,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(headline: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutSubtitle() { @@ -80,7 +81,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(subtitle: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutFragment() { @@ -88,7 +89,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(hasFragment: false) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testTextsWithMultiLine() { @@ -100,7 +101,7 @@ final class DataCardTests: XCTestCase { descriptionTitle: "Mauris vel nisi efficitur, fringilla urna at, gravida nunc. Sed eu dui sit amet est fringilla eleifend. Ut aliquam, tortor ac varius sodales" ) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryButtonsOnly() { @@ -108,7 +109,7 @@ final class DataCardTests: XCTestCase { let view = makeBasicCard(buttons: .primary(AnyValues.button)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndLinkButtons() { @@ -116,7 +117,7 @@ final class DataCardTests: XCTestCase { let view = makeBasicCard(buttons: .primaryAndLink(primary: AnyValues.button, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: Behaviour @@ -127,7 +128,7 @@ final class DataCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(buttons: .primaryAndLink(primary: AnyValues.button, link: AnyValues.link)) view.primaryButton.isLoading = true - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: XIB integration @@ -145,7 +146,7 @@ final class DataCardTests: XCTestCase { view.card.contentConfiguration = configurationWithActions assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneX) ) } diff --git a/Tests/MisticaTests/UI/DeterminateStepperTests.swift b/Tests/MisticaTests/UI/DeterminateStepperTests.swift index 5fbb5934..f5b49597 100644 --- a/Tests/MisticaTests/UI/DeterminateStepperTests.swift +++ b/Tests/MisticaTests/UI/DeterminateStepperTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class DeterminateStepperTests: XCTestCase { - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -34,7 +35,7 @@ final class DeterminateStepperTests: XCTestCase { let stepper = makeTemplateWithStepperState(currentStep: 0) assertSnapshot( - matching: stepper, + of: stepper, as: .image, named: "assertInitialState" ) @@ -42,7 +43,7 @@ final class DeterminateStepperTests: XCTestCase { stepper.currentStep = 1 assertSnapshot( - matching: stepper, + of: stepper, as: .image, named: "finalState" ) @@ -54,7 +55,7 @@ final class DeterminateStepperTests: XCTestCase { let stepper = makeTemplateWithStepperState(numberOfSteps: 3) assertSnapshot( - matching: stepper, + of: stepper, as: .image, named: "assertInitialState" ) @@ -62,7 +63,7 @@ final class DeterminateStepperTests: XCTestCase { stepper.numberOfSteps = 4 assertSnapshot( - matching: stepper, + of: stepper, as: .image, named: "finalState" ) @@ -76,7 +77,7 @@ final class DeterminateStepperTests: XCTestCase { let view = DeterminateStepperXIBIntegration.viewFromNib() assertSnapshot( - matching: view, + of: view, as: .image ) } @@ -84,9 +85,11 @@ final class DeterminateStepperTests: XCTestCase { // MARK: - Helpers -private func makeTemplateWithStepperState(currentStep: Int = 0, numberOfSteps: Int = 3) -> DeterminateStepperView { - let stepperView = DeterminateStepperView(frame: CGRect(origin: .zero, size: CGSize(width: 600, height: 24))) - stepperView.numberOfSteps = numberOfSteps - stepperView.currentStep = currentStep - return stepperView +private extension DeterminateStepperTests { + func makeTemplateWithStepperState(currentStep: Int = 0, numberOfSteps: Int = 3) -> DeterminateStepperView { + let stepperView = DeterminateStepperView(frame: CGRect(origin: .zero, size: CGSize(width: 600, height: 24))) + stepperView.numberOfSteps = numberOfSteps + stepperView.currentStep = currentStep + return stepperView + } } diff --git a/Tests/MisticaTests/UI/EmptyStatesTests.swift b/Tests/MisticaTests/UI/EmptyStatesTests.swift index e2b7b37a..aa41f5c9 100644 --- a/Tests/MisticaTests/UI/EmptyStatesTests.swift +++ b/Tests/MisticaTests/UI/EmptyStatesTests.swift @@ -10,11 +10,16 @@ import SnapshotTesting import XCTest +@MainActor final class EmptyStatesTests: XCTestCase { override class func setUp() { super.setUp() + } - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -32,7 +37,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeBasicEmptyState() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testShowActions() { @@ -45,7 +50,7 @@ final class EmptyStatesTests: XCTestCase { actions: .primary(AnyValues.primary) ) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentAsACard() { @@ -58,7 +63,7 @@ final class EmptyStatesTests: XCTestCase { actions: .primaryAndLink(primary: AnyValues.primary, link: AnyValues.link) ) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutDescription() { @@ -66,7 +71,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(description: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryButtonOnly() { @@ -74,7 +79,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .primary(AnyValues.primary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndLinkButtonsOnly() { @@ -82,7 +87,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .primaryAndLink(primary: AnyValues.primary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndLinkButtonsOnlyAsACard() { @@ -90,7 +95,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .primaryAndLink(primary: AnyValues.primary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryAndLinkButtonsOnly() { @@ -98,7 +103,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .secondaryAndLink(secondary: AnyValues.secondary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryButtonOnly() { @@ -106,7 +111,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .secondary(AnyValues.secondary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryButtonOnlyAsACard() { @@ -114,7 +119,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(type: .card(.icon(AnyValues.iconImage)), actions: .secondary(AnyValues.secondary)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testSecondaryAndLinkButtonsOnlyAsACard() { @@ -122,7 +127,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(type: .card(.icon(AnyValues.iconImage)), actions: .secondaryAndLink(secondary: AnyValues.secondary, link: AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testEmptyButtonOnly() { @@ -130,7 +135,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .empty) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testEmptyButtonOnlyAsACard() { @@ -138,7 +143,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(type: .card(.icon(AnyValues.iconImage)), actions: .empty) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testLinkButtonOnlyAsACard() { @@ -146,7 +151,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(type: .card(.icon(AnyValues.iconImage)), actions: .link(AnyValues.link)) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: Behaviour @@ -157,7 +162,7 @@ final class EmptyStatesTests: XCTestCase { let view = makeEmptyStateWithContentAndButtons(actions: .primaryAndLink(primary: AnyValues.primary, link: AnyValues.link)) view.primaryButton.isLoading = true - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: XIB integration @@ -176,7 +181,7 @@ final class EmptyStatesTests: XCTestCase { view.emptyState.contentConfiguration = configurationWithActions assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneX) ) } diff --git a/Tests/MisticaTests/UI/FeedbackTests.swift b/Tests/MisticaTests/UI/FeedbackTests.swift index c237ad2d..c29ab771 100644 --- a/Tests/MisticaTests/UI/FeedbackTests.swift +++ b/Tests/MisticaTests/UI/FeedbackTests.swift @@ -10,6 +10,7 @@ import Mistica import SnapshotTesting import XCTest +@MainActor final class FeedbackTests: XCTestCase { private enum Constants { static let singleLineTitle = "Title" @@ -23,11 +24,10 @@ final class FeedbackTests: XCTestCase { static let retryLoadingTitle = "Loading Title" } - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: Simple views diff --git a/Tests/MisticaTests/UI/FilterTests.swift b/Tests/MisticaTests/UI/FilterTests.swift index 46e447f5..963ea21e 100644 --- a/Tests/MisticaTests/UI/FilterTests.swift +++ b/Tests/MisticaTests/UI/FilterTests.swift @@ -10,12 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class FilterTests: XCTestCase { - override func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testSegmentsInFilter() { diff --git a/Tests/MisticaTests/UI/FormTests.swift b/Tests/MisticaTests/UI/FormTests.swift index 449cc60b..84b586f7 100644 --- a/Tests/MisticaTests/UI/FormTests.swift +++ b/Tests/MisticaTests/UI/FormTests.swift @@ -10,6 +10,7 @@ import SnapshotTesting import XCTest +@MainActor final class FormsTests: XCTestCase { private enum Constants { static let headerTitle = "Header view" @@ -17,10 +18,10 @@ final class FormsTests: XCTestCase { static let footerTitle = "Footer view" } - override func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Simple view @@ -78,7 +79,7 @@ final class FormsTests: XCTestCase { let formTestsViewController = FormTestsViewController(formView: formView) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -97,7 +98,7 @@ final class FormsTests: XCTestCase { let formTestsViewController = FormTestsViewController(formView: formView) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "assertInitialState" ) @@ -105,7 +106,7 @@ final class FormsTests: XCTestCase { formView.addInputFields([makeInputFieldWithEmailStyle()]) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "finalState" ) @@ -126,7 +127,7 @@ final class FormsTests: XCTestCase { let formTestsViewController = FormTestsViewController(formView: formView) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "assertInitialState" ) @@ -134,7 +135,7 @@ final class FormsTests: XCTestCase { formView.removeInputFields([firstInputField]) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "finalState" ) @@ -159,7 +160,7 @@ final class FormsTests: XCTestCase { let formTestsViewController = FormTestsViewController(formView: formView) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "assertInitialState" ) @@ -167,7 +168,7 @@ final class FormsTests: XCTestCase { formView.validate() assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "finalState" ) @@ -191,7 +192,7 @@ final class FormsTests: XCTestCase { let formTestsViewController = FormTestsViewController(formView: formView) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "assertInitialState" ) @@ -199,7 +200,7 @@ final class FormsTests: XCTestCase { formView.validate() assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "finalState" ) @@ -222,7 +223,7 @@ final class FormsTests: XCTestCase { let formTestsViewController = FormTestsViewController(formView: formView) assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "assertInitialState" ) @@ -230,7 +231,7 @@ final class FormsTests: XCTestCase { formView.validate() assertSnapshot( - matching: formTestsViewController, + of: formTestsViewController, as: .image(on: .iPhoneSe), named: "finalState" ) @@ -256,7 +257,7 @@ final class FormsTests: XCTestCase { formView.button.title = Constants.buttonTitle formView.addFooterView(makeLabel(withText: Constants.footerTitle)) - assertSnapshot(matching: view.asRootOfViewController(), as: .image(on: .iPhoneSe)) + assertSnapshot(of: view.asRootOfViewController(), as: .image(on: .iPhoneSe)) } } diff --git a/Tests/MisticaTests/UI/GradientTests.swift b/Tests/MisticaTests/UI/GradientTests.swift index 1692dfb5..ef090bd7 100644 --- a/Tests/MisticaTests/UI/GradientTests.swift +++ b/Tests/MisticaTests/UI/GradientTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class GradientTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testGradientInView() { @@ -26,7 +27,7 @@ final class GradientTests: XCTestCase { gradientView.setMisticaColorBackground(misticaColor) assertSnapshot( - matching: gradientView, + of: gradientView, as: .image ) } diff --git a/Tests/MisticaTests/UI/HeaderTests.swift b/Tests/MisticaTests/UI/HeaderTests.swift index e57a63ab..9a76ff28 100644 --- a/Tests/MisticaTests/UI/HeaderTests.swift +++ b/Tests/MisticaTests/UI/HeaderTests.swift @@ -10,14 +10,18 @@ import SnapshotTesting import XCTest +@MainActor final class HeaderTests: XCTestCase { override func setUp() { super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false MisticaConfig.brandStyle = .movistar } + + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } + } } // MARK: - Minimal header @@ -25,14 +29,14 @@ final class HeaderTests: XCTestCase { extension HeaderTests { func testMinimalPretitleHeader() { assertSnapshot( - matching: makeHeader(pretitle: HeaderText(text: "Only a pretitle")), + of: makeHeader(pretitle: HeaderText(text: "Only a pretitle")), as: .image(on: .iPhoneSe) ) } func testMinimalPretitleHeaderInNavigationBar() { assertSnapshot( - matching: makeHeader( + of: makeHeader( style: .inverse, pretitle: HeaderText(text: "Only a pretitle") ), @@ -42,14 +46,14 @@ extension HeaderTests { func testMinimalTitleHeader() { assertSnapshot( - matching: makeHeader(title: HeaderText(text: "Only a title")), + of: makeHeader(title: HeaderText(text: "Only a title")), as: .image(on: .iPhoneSe) ) } func testMinimalTitleHeaderInNavigationBar() { assertSnapshot( - matching: makeHeader( + of: makeHeader( style: .inverse, title: HeaderText(text: "Only a title") ), @@ -59,14 +63,14 @@ extension HeaderTests { func testMinimalDescriptionHeader() { assertSnapshot( - matching: makeHeader(descriptionValue: HeaderText(text: "Only a description")), + of: makeHeader(descriptionValue: HeaderText(text: "Only a description")), as: .image(on: .iPhoneSe) ) } func testMinimalDescriptionHeaderInNavigationBar() { assertSnapshot( - matching: makeHeader( + of: makeHeader( style: .inverse, descriptionValue: HeaderText(text: "Only a description") ), @@ -78,7 +82,7 @@ extension HeaderTests { extension HeaderTests { func testFullHeader() { assertSnapshot( - matching: makeHeader( + of: makeHeader( pretitle: HeaderText(text: "Pretitle"), title: HeaderText(text: "Title"), descriptionValue: HeaderText(text: "Description") @@ -89,7 +93,7 @@ extension HeaderTests { func testFullHeaderWithLongTexts() { assertSnapshot( - matching: makeHeader( + of: makeHeader( pretitle: HeaderText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"), title: HeaderText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit"), descriptionValue: HeaderText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit") @@ -100,7 +104,7 @@ extension HeaderTests { func testFullHeaderWithLongTextsAndLineLimitToTwo() { assertSnapshot( - matching: makeHeader( + of: makeHeader( pretitle: HeaderText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit", lineLimit: 2), title: HeaderText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit", lineLimit: 2), descriptionValue: HeaderText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit", lineLimit: 2) @@ -111,7 +115,7 @@ extension HeaderTests { func testFullHeaderWithAlternateColorsInverse() { assertSnapshot( - matching: makeHeader( + of: makeHeader( style: .inverse, pretitle: HeaderText(text: "Pretitle"), title: HeaderText(text: "Title"), diff --git a/Tests/MisticaTests/UI/HighlightedCardTests.swift b/Tests/MisticaTests/UI/HighlightedCardTests.swift index 4aa3cb4d..d079ca6d 100644 --- a/Tests/MisticaTests/UI/HighlightedCardTests.swift +++ b/Tests/MisticaTests/UI/HighlightedCardTests.swift @@ -11,11 +11,12 @@ import SnapshotTesting import XCTest +@MainActor final class HighlightedCardTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -83,7 +84,7 @@ final class HighlightedCardTests: XCTestCase { ) assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -101,7 +102,7 @@ final class HighlightedCardTests: XCTestCase { card.rightImageStyle = .fill assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -119,7 +120,7 @@ final class HighlightedCardTests: XCTestCase { card.rightImageStyle = .fit assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -136,7 +137,7 @@ final class HighlightedCardTests: XCTestCase { card.backgroundImage = UIImage.circle(diameter: 30, color: .yellow) assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -153,7 +154,7 @@ final class HighlightedCardTests: XCTestCase { card.showActionButton = false assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -170,7 +171,7 @@ final class HighlightedCardTests: XCTestCase { card.showCloseButton = true assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -188,7 +189,7 @@ final class HighlightedCardTests: XCTestCase { card.showCloseButton = true assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -206,7 +207,7 @@ final class HighlightedCardTests: XCTestCase { card.showCloseButton = true assertSnapshot( - matching: card, + of: card, as: .image ) } @@ -222,7 +223,7 @@ final class HighlightedCardTests: XCTestCase { view.card.actionButtonTitle = "Empezar pruebas" assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneSe) ) } @@ -230,30 +231,32 @@ final class HighlightedCardTests: XCTestCase { // MARK: - Helpers -private func makeCard( - style: HighlightedCardStyle = .normal, - title: String = "Resolver problema técnico", - subtitle: String = "Usa nuestra herramienta para resolver tus problemas técnicos", - rightImage: UIImage? = nil, - actionButtonTitle: String? = "Empezar pruebas", - actionButtonStyle: HighlightedCard.ButtonStyle = .primary -) -> HighlightedCard { - let view = HighlightedCard( - title: title, - subtitle: subtitle, - rightImage: rightImage, - actionButtonStyle: actionButtonStyle - ) - - view.style = style - view.actionButtonTitle = actionButtonTitle - - let cardSize = view.systemLayoutSizeFitting( - CGSize(width: 300, height: 0), - withHorizontalFittingPriority: .required, - verticalFittingPriority: .defaultLow - ) - view.frame = CGRect(x: 0, y: 0, width: cardSize.width, height: cardSize.height) - - return view +private extension HighlightedCardTests { + func makeCard( + style: HighlightedCardStyle = .normal, + title: String = "Resolver problema técnico", + subtitle: String = "Usa nuestra herramienta para resolver tus problemas técnicos", + rightImage: UIImage? = nil, + actionButtonTitle: String? = "Empezar pruebas", + actionButtonStyle: HighlightedCard.ButtonStyle = .primary + ) -> HighlightedCard { + let view = HighlightedCard( + title: title, + subtitle: subtitle, + rightImage: rightImage, + actionButtonStyle: actionButtonStyle + ) + + view.style = style + view.actionButtonTitle = actionButtonTitle + + let cardSize = view.systemLayoutSizeFitting( + CGSize(width: 300, height: 0), + withHorizontalFittingPriority: .required, + verticalFittingPriority: .defaultLow + ) + view.frame = CGRect(x: 0, y: 0, width: cardSize.width, height: cardSize.height) + + return view + } } diff --git a/Tests/MisticaTests/UI/IndeterminateStepperTests.swift b/Tests/MisticaTests/UI/IndeterminateStepperTests.swift index 3536571b..e432caa0 100644 --- a/Tests/MisticaTests/UI/IndeterminateStepperTests.swift +++ b/Tests/MisticaTests/UI/IndeterminateStepperTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class IndeterminateStepperTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -34,7 +35,7 @@ final class IndeterminateStepperTests: XCTestCase { let stepper = makeTemplateWithStepperState(value: 0) assertSnapshot( - matching: stepper, + of: stepper, as: .image, named: "assertInitialState" ) @@ -42,7 +43,7 @@ final class IndeterminateStepperTests: XCTestCase { stepper.value = 50 assertSnapshot( - matching: stepper, + of: stepper, as: .image, named: "finalState" ) @@ -56,7 +57,7 @@ final class IndeterminateStepperTests: XCTestCase { let view = IndeterminateStepperXIBIntegration.viewFromNib() assertSnapshot( - matching: view, + of: view, as: .image ) } @@ -64,8 +65,10 @@ final class IndeterminateStepperTests: XCTestCase { // MARK: - Helpers -private func makeTemplateWithStepperState(value: Int = 0) -> IndeterminateStepperView { - let stepperView = IndeterminateStepperView(frame: CGRect(origin: .zero, size: CGSize(width: 600, height: 24))) - stepperView.value = value - return stepperView +private extension IndeterminateStepperTests { + func makeTemplateWithStepperState(value: Int = 0) -> IndeterminateStepperView { + let stepperView = IndeterminateStepperView(frame: CGRect(origin: .zero, size: CGSize(width: 600, height: 24))) + stepperView.value = value + return stepperView + } } diff --git a/Tests/MisticaTests/UI/InputFieldTests.swift b/Tests/MisticaTests/UI/InputFieldTests.swift index 806f1fff..110d3a9c 100644 --- a/Tests/MisticaTests/UI/InputFieldTests.swift +++ b/Tests/MisticaTests/UI/InputFieldTests.swift @@ -10,16 +10,16 @@ import Mistica import SnapshotTesting import XCTest +@MainActor final class InputFieldTests: XCTestCase { private enum Constants { static let defaultTextValue = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." } - override func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles diff --git a/Tests/MisticaTests/UI/ListsTests.swift b/Tests/MisticaTests/UI/ListsTests.swift index bcda0843..3326d54e 100644 --- a/Tests/MisticaTests/UI/ListsTests.swift +++ b/Tests/MisticaTests/UI/ListsTests.swift @@ -10,14 +10,20 @@ import SnapshotTesting import XCTest +@MainActor final class ListsTests: XCTestCase { override func setUp() { super.setUp() - isRecording = false MisticaConfig.brandStyle = .movistar } + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } + } + // MARK: - Layout // MARK: - Default config @@ -26,7 +32,7 @@ final class ListsTests: XCTestCase { let listTestsViewController = makeListTestsViewController(assetType: .custom(.image(AnyValues.image))) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -35,7 +41,7 @@ final class ListsTests: XCTestCase { let listTestsViewController = makeListTestsViewController(assetType: .custom(.image(AnyValues.image), size: CGSize(width: 100, height: 40))) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -44,7 +50,7 @@ final class ListsTests: XCTestCase { let listTestsViewController = makeListTestsViewController(assetType: .smallIcon(AnyValues.image)) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -53,7 +59,7 @@ final class ListsTests: XCTestCase { let listTestsViewController = makeListTestsViewController(assetType: .largeIcon(AnyValues.image, backgroundColor: .blue)) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -65,7 +71,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -76,7 +82,7 @@ final class ListsTests: XCTestCase { let listTestsViewController = makeListTestsViewController(title: AnyValues.title) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -88,7 +94,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -100,7 +106,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -112,7 +118,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -124,7 +130,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -137,7 +143,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -151,7 +157,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -164,7 +170,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -177,7 +183,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -190,7 +196,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -203,7 +209,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -217,7 +223,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -231,7 +237,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -244,7 +250,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -257,7 +263,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -270,7 +276,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -283,7 +289,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -297,7 +303,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -312,7 +318,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -326,7 +332,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -340,7 +346,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -354,7 +360,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -368,7 +374,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -383,7 +389,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -397,7 +403,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -411,7 +417,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -426,7 +432,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -441,7 +447,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -457,7 +463,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -473,7 +479,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -487,7 +493,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -501,7 +507,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -515,7 +521,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -529,7 +535,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -543,7 +549,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -557,7 +563,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -571,7 +577,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -585,7 +591,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -600,7 +606,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -615,7 +621,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -631,7 +637,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -648,7 +654,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -662,7 +668,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -677,7 +683,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -693,7 +699,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -711,7 +717,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -725,7 +731,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -740,7 +746,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -756,7 +762,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -774,7 +780,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -796,7 +802,7 @@ final class ListsTests: XCTestCase { ) assertSnapshot( - matching: listTestsViewController, + of: listTestsViewController, as: .image(on: .iPhoneSe) ) } @@ -838,7 +844,7 @@ extension ListsTests { Detail text line 1 Detail text line 2 """ - static var image = UIImage(color: .green) + static let image = UIImage(color: .green) } private func makeListTestsViewController( diff --git a/Tests/MisticaTests/UI/LoadErrorViewControllerTests.swift b/Tests/MisticaTests/UI/LoadErrorViewControllerTests.swift index 12838e50..9e130487 100644 --- a/Tests/MisticaTests/UI/LoadErrorViewControllerTests.swift +++ b/Tests/MisticaTests/UI/LoadErrorViewControllerTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class LoadErrorViewControllerTests: XCTestCase { - override func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } } @@ -28,21 +29,21 @@ extension LoadErrorViewControllerTests { func testNoTitle() { assertSnapshot( - matching: makeLoadErrorViewController(title: nil), + of: makeLoadErrorViewController(title: nil), as: .image ) } func testNoAction() { assertSnapshot( - matching: makeLoadErrorViewController(showActionButton: false), + of: makeLoadErrorViewController(showActionButton: false), as: .image ) } func testEmptyDescriptionAction() { assertSnapshot( - matching: makeLoadErrorViewController(descriptionText: ""), + of: makeLoadErrorViewController(descriptionText: ""), as: .image ) } diff --git a/Tests/MisticaTests/UI/MediaCardTests.swift b/Tests/MisticaTests/UI/MediaCardTests.swift index 32a7f9d1..3c534353 100644 --- a/Tests/MisticaTests/UI/MediaCardTests.swift +++ b/Tests/MisticaTests/UI/MediaCardTests.swift @@ -10,11 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class MediaCardTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -32,7 +33,7 @@ final class MediaCardTests: XCTestCase { let view = makeBasicCard() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContent() { @@ -40,7 +41,7 @@ final class MediaCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutFragment() { @@ -48,7 +49,7 @@ final class MediaCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(hasFragment: false) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutHeadline() { @@ -56,7 +57,7 @@ final class MediaCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(headline: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutTitle() { @@ -64,7 +65,7 @@ final class MediaCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(title: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testFullContentWithoutPretitle() { @@ -72,7 +73,7 @@ final class MediaCardTests: XCTestCase { let view = makeCardWithFullContentAndButtons(pretitle: nil) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testTextsWithMultiLine() { @@ -84,7 +85,7 @@ final class MediaCardTests: XCTestCase { descriptionTitle: "Mauris vel nisi efficitur, fringilla urna at, gravida nunc. Sed eu dui sit amet est fringilla eleifend. Ut aliquam, tortor ac varius sodales" ) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryButtonsOnly() { @@ -92,7 +93,7 @@ final class MediaCardTests: XCTestCase { let view = makeBasicCard() - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } func testPrimaryAndLinkButtons() { @@ -102,7 +103,7 @@ final class MediaCardTests: XCTestCase { primaryButton: AnyValues.button, linkButton: AnyValues.link ) - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: Behaviour @@ -115,7 +116,7 @@ final class MediaCardTests: XCTestCase { ) view.primaryButton.isLoading = true - assertSnapshot(matching: view, as: .image) + assertSnapshot(of: view, as: .image) } // MARK: XIB integration @@ -137,7 +138,7 @@ final class MediaCardTests: XCTestCase { view.card.contentConfiguration = configurationWithActions assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneX) ) } @@ -149,6 +150,7 @@ extension MediaCardTests { enum AnyValues { static let button = CardButton(title: "Button", loadingTitle: "Loading", tapHandler: nil) static let link = CardLinkButton(title: "Button Link", tapHandler: nil) + @MainActor static var richMedia: UIImageView { let image = UIImageView(image: UIImage(color: .green)) diff --git a/Tests/MisticaTests/UI/PopoverViewTests.swift b/Tests/MisticaTests/UI/PopoverViewTests.swift index ce8fb0fe..7aeadb1b 100644 --- a/Tests/MisticaTests/UI/PopoverViewTests.swift +++ b/Tests/MisticaTests/UI/PopoverViewTests.swift @@ -10,11 +10,12 @@ import Mistica import SnapshotTesting import XCTest +@MainActor final class PopoverViewTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Styles @@ -32,14 +33,14 @@ final class PopoverViewTests: XCTestCase { let downPopover = makePopover(tipDirection: .down) assertSnapshot( - matching: downPopover, + of: downPopover, as: .image(size: .init(width: 200, height: 100)) ) let upPopover = makePopover(tipDirection: .up) assertSnapshot( - matching: upPopover, + of: upPopover, as: .image(size: .init(width: 200, height: 100)) ) } @@ -50,7 +51,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 400, height: 150)) ) } @@ -59,7 +60,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, title: nil) assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 200, height: 100)) ) } @@ -70,7 +71,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, subtitle: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 400, height: 150)) ) } @@ -79,7 +80,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, subtitle: nil) assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 500, height: 100)) ) } @@ -91,7 +92,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, title: largeText, subtitle: largeText) assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 400, height: 200)) ) } @@ -102,7 +103,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, image: nil) assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 200, height: 100)) ) } @@ -113,7 +114,7 @@ final class PopoverViewTests: XCTestCase { let popover = makePopover(tipDirection: .down, canClose: false) assertSnapshot( - matching: popover, + of: popover, as: .image(size: .init(width: 200, height: 100)) ) } diff --git a/Tests/MisticaTests/UI/RadioButtonTests.swift b/Tests/MisticaTests/UI/RadioButtonTests.swift index f68cfe73..0104f9c9 100644 --- a/Tests/MisticaTests/UI/RadioButtonTests.swift +++ b/Tests/MisticaTests/UI/RadioButtonTests.swift @@ -10,13 +10,14 @@ import Mistica import SnapshotTesting import XCTest +@MainActor final class RadioButtonTests: XCTestCase { private let buttonSize = CGSize(width: 30.0, height: 30.0) - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testRadioButtonEnabled() { diff --git a/Tests/MisticaTests/UI/SheetTests.swift b/Tests/MisticaTests/UI/SheetTests.swift index 035342b7..715dab5d 100644 --- a/Tests/MisticaTests/UI/SheetTests.swift +++ b/Tests/MisticaTests/UI/SheetTests.swift @@ -10,12 +10,12 @@ import SnapshotTesting import XCTest +@MainActor final class SheetTests: XCTestCase { - override func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: Common behaviour @@ -216,7 +216,7 @@ final class SheetTests: XCTestCase { // MARK: Actions func testSingleAction() { - assertSnapshot(matching: sheetView( + assertSnapshot(of: sheetView( title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", subtitle: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", description: "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", @@ -225,7 +225,7 @@ final class SheetTests: XCTestCase { } func testActions() { - assertSnapshot(matching: sheetView( + assertSnapshot(of: sheetView( title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", subtitle: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", description: "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", diff --git a/Tests/MisticaTests/UI/SkeletonTests.swift b/Tests/MisticaTests/UI/SkeletonTests.swift index e6298aea..b19167db 100644 --- a/Tests/MisticaTests/UI/SkeletonTests.swift +++ b/Tests/MisticaTests/UI/SkeletonTests.swift @@ -10,51 +10,52 @@ import SnapshotTesting import XCTest +@MainActor final class SkeletonTests: XCTestCase { - override class func setUp() { - super.setUp() - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testLineSkeleton() { assertSnapshot( - matching: makeSkeletonTemplate(type: .line(width: 300)), + of: makeSkeletonTemplate(type: .line(width: 300)), as: .image ) } func testTextSkeleton() { assertSnapshot( - matching: makeSkeletonTemplate(type: .text()), + of: makeSkeletonTemplate(type: .text()), as: .image ) } func testTextSkeletonWithCustomLines() { assertSnapshot( - matching: makeSkeletonTemplate(type: .text(numberOfLines: 5)), + of: makeSkeletonTemplate(type: .text(numberOfLines: 5)), as: .image ) } func testCircleSkeleton() { assertSnapshot( - matching: makeSkeletonTemplate(type: .circle(size: 40), containerWidth: 40), + of: makeSkeletonTemplate(type: .circle(size: 40), containerWidth: 40), as: .image ) } func testRowSkeleton() { assertSnapshot( - matching: makeSkeletonTemplate(type: .row), + of: makeSkeletonTemplate(type: .row), as: .image ) } func testRectangleSkeleton() { assertSnapshot( - matching: makeSkeletonTemplate(type: .rectangle(size: CGSize(width: 360, height: 180), isRounded: true), containerWidth: 360), + of: makeSkeletonTemplate(type: .rectangle(size: CGSize(width: 360, height: 180), isRounded: true), containerWidth: 360), as: .image ) } diff --git a/Tests/MisticaTests/UI/TabsTests.swift b/Tests/MisticaTests/UI/TabsTests.swift index e8a482bd..2c29bebf 100644 --- a/Tests/MisticaTests/UI/TabsTests.swift +++ b/Tests/MisticaTests/UI/TabsTests.swift @@ -10,6 +10,7 @@ import SnapshotTesting import XCTest +@MainActor final class TabsTests: XCTestCase { enum Constants { static let defaultWidth: CGFloat = 390 @@ -57,11 +58,10 @@ final class TabsTests: XCTestCase { ] } - override class func setUp() { - super.setUp() - UIView.setAnimationsEnabled(false) - - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } // MARK: - Mobile Width Styles @@ -77,7 +77,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.threeItem) ), as: .image(on: .iPhoneSe) @@ -88,7 +88,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.threeItemWithoutIcon) ), as: .image(on: .iPhoneSe) @@ -99,7 +99,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.threeItemWithLongText) ), as: .image(on: .iPhoneSe) @@ -110,7 +110,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.threeItemWithLongTextAndNoIcon) ), as: .image(on: .iPhoneSe) @@ -121,7 +121,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.eightItem) ), as: .image(on: .iPhoneSe) @@ -134,7 +134,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.threeItem) ), as: .image(on: .iPadMini) @@ -145,7 +145,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.twoItem) ), as: .image(on: .iPadMini) @@ -156,7 +156,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.threeItemWithLongText) ), as: .image(on: .iPadMini) @@ -167,7 +167,7 @@ final class TabsTests: XCTestCase { MisticaConfig.brandStyle = .movistar assertSnapshot( - matching: TabsTestsViewController( + of: TabsTestsViewController( tabsView: makeTemplateTabsView(tabItems: Constants.eightItem) ), as: .image(on: .iPadMini) @@ -183,7 +183,7 @@ final class TabsTests: XCTestCase { view.tabs.reload(with: Constants.twoItem) assertSnapshot( - matching: view.asRootOfViewController(), + of: view.asRootOfViewController(), as: .image(on: .iPhoneSe) ) } diff --git a/Tests/MisticaTests/UI/TagTests.swift b/Tests/MisticaTests/UI/TagTests.swift index 781efe47..475d2309 100644 --- a/Tests/MisticaTests/UI/TagTests.swift +++ b/Tests/MisticaTests/UI/TagTests.swift @@ -10,11 +10,19 @@ import SnapshotTesting import XCTest +@MainActor final class TagTests: XCTestCase { override func setUp() { super.setUp() - UIView.setAnimationsEnabled(false) - isRecording = false + Task { @MainActor in + UIView.setAnimationsEnabled(false) + } + } + + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testPromoTagView() { @@ -73,7 +81,7 @@ final class TagTests: XCTestCase { view.tagView.text = "Xib integration" assertSnapshot( - matching: view, + of: view, as: .image ) } diff --git a/Tests/MisticaTests/UI/TitleHeaderFooterViewTests.swift b/Tests/MisticaTests/UI/TitleHeaderFooterViewTests.swift index a22b50ff..e54db971 100644 --- a/Tests/MisticaTests/UI/TitleHeaderFooterViewTests.swift +++ b/Tests/MisticaTests/UI/TitleHeaderFooterViewTests.swift @@ -10,12 +10,19 @@ import SnapshotTesting import XCTest +@MainActor final class TitleHeaderFooterViewTests: XCTestCase { override func setUp() { super.setUp() - UIView.setAnimationsEnabled(false) + Task { @MainActor in + UIView.setAnimationsEnabled(false) + } + } - isRecording = false + override func invokeTest() { + withSnapshotTesting(record: .never) { + super.invokeTest() + } } func testTitle1() { diff --git a/Tests/MisticaTests/Utils/TestHelpers.swift b/Tests/MisticaTests/Utils/TestHelpers.swift index c3c2dc0b..1fb47d97 100644 --- a/Tests/MisticaTests/Utils/TestHelpers.swift +++ b/Tests/MisticaTests/Utils/TestHelpers.swift @@ -22,18 +22,22 @@ extension UIView { // MARK: - Helpers +@MainActor func assertSnapshotForAllBrandsAndStyles( as snapshotting: Snapshotting, - file: StaticString = #file, + file: StaticString = #filePath, testName: String = #function, line: UInt = #line, - viewBuilder: @autoclosure () -> View + viewBuilder: @autoclosure () -> View, + animationsEnabled: Bool = false ) { + UIView.setAnimationsEnabled(animationsEnabled) + for brand in BrandStyle.allCases { MisticaConfig.brandStyle = brand assertSnapshot( - matching: viewBuilder(), + of: viewBuilder(), as: snapshotting, named: "with-\(brand)-style", file: file, @@ -45,7 +49,7 @@ func assertSnapshotForAllBrandsAndStyles( darkView.overrideUserInterfaceStyle = .dark assertSnapshot( - matching: darkView, + of: darkView, as: snapshotting, named: "with-\(brand)-dark-style", file: file, @@ -55,11 +59,12 @@ func assertSnapshotForAllBrandsAndStyles( } } +@MainActor func assertSnapshot( for brands: [BrandStyle] = BrandStyle.allCases, and styles: [UIUserInterfaceStyle] = [.light, .dark], as snapshotting: Snapshotting, - file: StaticString = #file, + file: StaticString = #filePath, testName: String = #function, line: UInt = #line, viewBuilder: @autoclosure () -> View @@ -71,7 +76,7 @@ func assertSnapshot( var view = viewBuilder() view.overrideUserInterfaceStyle = style assertSnapshot( - matching: view, + of: view, as: snapshotting, named: "with-\(brand)-\(style.testSuffix)-style", file: file, @@ -82,6 +87,7 @@ func assertSnapshot( } } +@MainActor protocol UserInterfaceStyling { var overrideUserInterfaceStyle: UIUserInterfaceStyle { get set } }