Consider tests for animations (#1779)

This commit is contained in:
Alfonso Grillo
2023-09-21 17:49:38 +02:00
committed by GitHub
parent 37afc8c253
commit bc1910e9bb
8 changed files with 30 additions and 12 deletions
@@ -21,9 +21,22 @@ public extension Animation {
/// Animation to be used to disable animations. /// Animation to be used to disable animations.
static let noAnimation: Animation = .linear(duration: 0) static let noAnimation: Animation = .linear(duration: 0)
/// `noAnimation` if running UI tests, otherwise `default` animation. /// `noAnimation` if running tests, otherwise `default` animation if `UIAccessibility.isReduceMotionEnabled` is false
static var elementDefault: Animation { static var elementDefault: Animation {
Tests.isRunningUITests ? .noAnimation : (UIAccessibility.isReduceMotionEnabled ? .noAnimation : .default) let animation: Animation = Tests.isRunningTests ? .noAnimation : .default
return animation.disabledIfReduceMotionEnabled()
}
// `noAnimation` if running tests, otherwise `self` if `UIAccessibility.isReduceMotionEnabled` is false
func disabledDuringTests() -> Self {
let animation: Animation = Tests.isRunningTests ? .noAnimation : self
return animation.disabledIfReduceMotionEnabled()
}
// MARK: - Private
private func disabledIfReduceMotionEnabled() -> Self {
UIAccessibility.isReduceMotionEnabled ? .noAnimation : self
} }
} }
@@ -33,8 +46,5 @@ public extension Animation {
/// - animation: Animation /// - animation: Animation
/// - body: operations to be animated /// - body: operations to be animated
public func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result { public func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
if Tests.isRunningUITests { try withAnimation(animation?.disabledDuringTests(), body)
return try withAnimation(.noAnimation, body)
}
return try withAnimation(animation, body)
} }
@@ -41,7 +41,10 @@ struct ShimmerModifier: ViewModifier {
private let regularColor = Color.white private let regularColor = Color.white
/// A slow linear animation which auto-repeats after a delay. /// A slow linear animation which auto-repeats after a delay.
private let animation: Animation = Tests.isRunningUITests ? .noAnimation : .linear(duration: 1.75).delay(0.5).repeatForever(autoreverses: false) private let animation: Animation = .linear(duration: 1.75)
.delay(0.5)
.repeatForever(autoreverses: false)
.disabledDuringTests()
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
+5
View File
@@ -35,6 +35,11 @@ public enum Tests {
#endif #endif
} }
/// Flag indicating whether the app is running the UI tests or unit tests.
static var isRunningTests: Bool {
isRunningUITests || isRunningUnitTests
}
/// The identifier of the screen to be loaded when running UI tests. /// The identifier of the screen to be loaded when running UI tests.
static var screenID: UITestsScreenIdentifier? { static var screenID: UITestsScreenIdentifier? {
#if DEBUG #if DEBUG
@@ -102,7 +102,7 @@ struct ComposerToolbar: View {
.padding(4) .padding(4)
} }
.disabled(context.viewState.sendButtonDisabled) .disabled(context.viewState.sendButtonDisabled)
.animation(.linear(duration: 0.1), value: context.viewState.sendButtonDisabled) .animation(.linear(duration: 0.1).disabledDuringTests(), value: context.viewState.sendButtonDisabled)
.keyboardShortcut(.return, modifiers: [.command]) .keyboardShortcut(.return, modifiers: [.command])
} }
@@ -167,7 +167,7 @@ struct HomeScreenRoomCellButtonStyle: ButtonStyle {
configuration.label configuration.label
.background(isSelected ? Color.compound.bgSubtleSecondary : Color.compound.bgCanvasDefault) .background(isSelected ? Color.compound.bgSubtleSecondary : Color.compound.bgCanvasDefault)
.contentShape(Rectangle()) .contentShape(Rectangle())
.animation(isSelected ? .none : .easeOut(duration: 0.1), value: isSelected) .animation(isSelected ? .none : .easeOut(duration: 0.1).disabledDuringTests(), value: isSelected)
} }
} }
@@ -106,7 +106,7 @@ struct InviteUsersScreen: View {
} }
.onChange(of: context.viewState.scrollToLastID) { lastAddedID in .onChange(of: context.viewState.scrollToLastID) { lastAddedID in
guard let id = lastAddedID else { return } guard let id = lastAddedID else { return }
withAnimation(.easeInOut) { withElementAnimation(.easeInOut) {
scrollView.scrollTo(id) scrollView.scrollTo(id)
} }
} }
@@ -31,7 +31,7 @@ struct LongPressWithFeedback: ViewModifier {
.shadow(color: .black.opacity(isLongPressing ? 0.1 : 0.0), radius: isLongPressing ? 3 : 0) .shadow(color: .black.opacity(isLongPressing ? 0.1 : 0.0), radius: isLongPressing ? 3 : 0)
.scaleEffect(x: isLongPressing ? 1.05 : 1, .scaleEffect(x: isLongPressing ? 1.05 : 1,
y: isLongPressing ? 1.05 : 1) y: isLongPressing ? 1.05 : 1)
.animation(isLongPressing ? .spring(response: 0.5).delay(0.1) : .spring(response: 0.5), .animation(.spring(response: 0.5).delay(isLongPressing ? 0.1 : 0).disabledDuringTests(),
value: isLongPressing) value: isLongPressing)
// The minimum duration here doesn't actually invoke the perform block when elapsed (thus // The minimum duration here doesn't actually invoke the perform block when elapsed (thus
// the implementation below) but it does cancel other system gestures e.g. swipe to reply // the implementation below) but it does cancel other system gestures e.g. swipe to reply
@@ -61,7 +61,7 @@ struct TimelineReactionsView: View {
.reactionLayoutItem(.addMore) .reactionLayoutItem(.addMore)
} }
.environment(\.layoutDirection, reactionsLayoutDirection) .environment(\.layoutDirection, reactionsLayoutDirection)
.animation(.easeInOut(duration: 0.1), value: reactions) .animation(.easeInOut(duration: 0.1).disabledDuringTests(), value: reactions)
.padding(.leading, 4) .padding(.leading, 4)
} }
} }