Skip to content

Commit b5b9a80

Browse files
authored
Add missing Animation UITests cases (#630)
1 parent b77ec9e commit b5b9a80

File tree

14 files changed

+232
-8
lines changed

14 files changed

+232
-8
lines changed

Configurations/OpenSwiftUIUITests.xcconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ CODE_SIGN_ENTITLEMENTS = TestingHost/TestingHost.entitlements
44

55
// Remove -module_alias Testing=_Testing_Unavailable
66
OTHER_SWIFT_FLAGS = $(OPENSWIFTUI_AVAILABILITY_MACRO)
7+
8+
CLANG_ENABLE_MODULES = YES;
9+
10+
SWIFT_OBJC_BRIDGING_HEADER = OpenSwiftUIUITests/OpenSwiftUIUITests-Bridging-Header.h
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// AnimationCompletionUITests.swift
3+
// OpenSwiftUIUITests
4+
5+
import Testing
6+
import SnapshotTesting
7+
8+
@MainActor
9+
@Suite(.snapshots(record: .never, diffTool: diffTool))
10+
struct AnimationCompletionUITests {
11+
@Test
12+
func logicalAndRemovedComplete() {
13+
struct ContentView: AnimationTestView {
14+
nonisolated static var model: AnimationTestModel {
15+
AnimationTestModel(duration: 3, count: 3)
16+
}
17+
18+
@State private var opacity = 1.0
19+
@State private var scale = 1.0
20+
21+
@State private var showGreen = false
22+
@State private var showBlue = false
23+
24+
var body: some View {
25+
ZStack {
26+
Color.red
27+
.frame(width: 100 * scale, height: 100 * scale)
28+
.opacity(opacity)
29+
if showGreen { Color.green.frame(width: 20, height: 20) }
30+
if showBlue { Color.blue.frame(width: 10, height: 10) }
31+
}
32+
.onAppear {
33+
let animation = Animation.linear(duration: 2)
34+
.logicallyComplete(after: 1)
35+
withAnimation(animation, completionCriteria: .logicallyComplete) {
36+
opacity = 0.1
37+
} completion: {
38+
showGreen.toggle()
39+
}
40+
withAnimation(animation, completionCriteria: .removed) {
41+
scale = 0.1
42+
} completion: {
43+
showBlue.toggle()
44+
}
45+
}
46+
}
47+
}
48+
// When run seperately, precision: 1.0 works fine
49+
// but in the full suite, it will hit the same issue of #340
50+
withKnownIssue("#340", isIntermittent: true) {
51+
openSwiftUIAssertAnimationSnapshot(
52+
of: ContentView()
53+
)
54+
}
55+
}
56+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//
2+
// BezierAnimationUITests.swift
3+
// OpenSwiftUIUITests
4+
5+
import Testing
6+
import SnapshotTesting
7+
8+
@MainActor
9+
@Suite(.snapshots(record: .never, diffTool: diffTool))
10+
struct BezierAnimationUITests {
11+
@Test
12+
func colorRow() {
13+
struct ContentView: AnimationTestView {
14+
nonisolated static var model: AnimationTestModel {
15+
AnimationTestModel(duration: 2, count: 5)
16+
}
17+
18+
@State private var animate = false
19+
private var animationDuration: Double { Self.model.duration }
20+
21+
var body: some View {
22+
VStack(spacing: 10) {
23+
AnimationRow(
24+
color: .blue,
25+
animate: animate,
26+
animation: .linear(duration: animationDuration)
27+
)
28+
AnimationRow(
29+
color: .green,
30+
animate: animate,
31+
animation: .easeIn(duration: animationDuration)
32+
)
33+
AnimationRow(
34+
color: .red,
35+
animate: animate,
36+
animation: .easeOut(duration: animationDuration)
37+
)
38+
AnimationRow(
39+
color: .orange,
40+
animate: animate,
41+
animation: .easeInOut(duration: animationDuration)
42+
)
43+
AnimationRow(
44+
color: .purple,
45+
animate: animate,
46+
animation: .timingCurve(0.68, -0.6, 0.32, 1.6, duration: animationDuration)
47+
)
48+
}
49+
.padding()
50+
.frame(width: 200, height: 200)
51+
.onAppear {
52+
animate.toggle()
53+
}
54+
}
55+
struct AnimationRow: View {
56+
let color: Color
57+
let animate: Bool
58+
let animation: Animation
59+
60+
private let squareSize: CGFloat = 20.0
61+
62+
var body: some View {
63+
GeometryReader { geometry in
64+
ZStack(alignment: .leading) {
65+
Color.black.opacity(0.1)
66+
color
67+
// TODO: Color interpolation not aligned yet
68+
// Color(animate ? color : .gray)
69+
.frame(width: squareSize, height: squareSize)
70+
.offset(x: animate ? geometry.size.width - squareSize : 0)
71+
}
72+
}
73+
.frame(height: squareSize)
74+
.animation(animation, value: animate)
75+
}
76+
}
77+
}
78+
// When run seperately, precision: 1.0 works fine
79+
// but in the full suite, it will hit the same issue of #340
80+
withKnownIssue("$340", isIntermittent: true) {
81+
openSwiftUIAssertAnimationSnapshot(
82+
of: ContentView(),
83+
)
84+
}
85+
}
86+
}

Example/OpenSwiftUIUITests/Graphic/Color/ColorUITests.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ struct ColorUITests {
7575
}
7676
}
7777
}
78-
openSwiftUIAssertAnimationSnapshot(of: ContentView())
78+
withKnownIssue("#340", isIntermittent: true) {
79+
openSwiftUIAssertAnimationSnapshot(of: ContentView())
80+
}
7981
}
8082

8183
// FIXME

Example/OpenSwiftUIUITests/Layout/Dynamic/DynamicLayoutViewUITests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct DynamicLayoutViewUITests {
1111
@Test
1212
func dynamicLayout() {
1313
struct ContentView: View {
14-
@State var show = false
14+
@State private var show = false
1515
var body: some View {
1616
VStack {
1717
Color.red
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//
2+
// Use this file to import your target's public headers that you would like to expose to Swift.
3+
//
4+
5+
#import "AnimationDebugControllerHelper.h"

Example/OpenSwiftUIUITests/UITests/AnimationDebugController.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// OpenSwiftUIUITests
44

55
import Foundation
6-
import OpenSwiftUI_SPI
76

87
struct AnimationTestModel: Hashable {
98
var intervals: [Double]
@@ -99,17 +98,23 @@ final class AnimationDebugController<V>: PlatformHostingController<V> where V: V
9998
// Avoid generic parameter casting
10099
private protocol AnimationDebuggableController: PlatformViewController {
101100
var disableLayoutSubview: Bool { get set }
101+
102+
func advance(interval: Double)
102103
}
103104

104105
extension AnimationDebugController: AnimationDebuggableController {}
105106

106107
extension PlatformView {
108+
// Fix swift-snapshot-testing trigger extra layoutSubviews and advance time issue
107109
@objc func swizzled_layoutSubviews() {
108110
guard let vc = _viewControllerForAncestor as? AnimationDebuggableController else {
109111
swizzled_layoutSubviews()
110112
return
111113
}
112114
guard !vc.disableLayoutSubview else {
115+
// superLayoutSubviews(type(of: self))
116+
// Fix swift-snapshot-testing set initialFrame as .zero and then trigger setProposedSize(.zero) causing DisplayList layout issue (View is placed at topLeft instead of center)
117+
vc.advance(interval: .zero)
113118
return
114119
}
115120
swizzled_layoutSubviews()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// AnimationDebugControllerHelper.h
3+
// OpenSwiftUIUITests
4+
5+
#import <Foundation/Foundation.h>
6+
7+
#if TARGET_OS_IPHONE
8+
9+
#import <UIKit/UIKit.h>
10+
11+
NS_ASSUME_NONNULL_BEGIN
12+
13+
@interface UIView (OpenSwiftUIUITests)
14+
@property(nonatomic, readonly, nullable) UIViewController *_viewControllerForAncestor;
15+
@end
16+
17+
void superLayoutSubviews(Class cls);
18+
19+
NS_ASSUME_NONNULL_END
20+
21+
22+
#endif
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// AnimationDebugControllerHelper.m
3+
// OpenSwiftUIUITests
4+
5+
#import "AnimationDebugControllerHelper.h"
6+
#import <objc/runtime.h>
7+
#import <objc/message.h>
8+
9+
#if TARGET_OS_IPHONE
10+
11+
void superLayoutSubviews(Class cls) {
12+
((void (*)(struct objc_super *, SEL))(void *)objc_msgSendSuper)(&((struct objc_super){(id)cls, (id)class_getSuperclass(cls)}), sel_registerName("layoutSubviews"));
13+
}
14+
15+
#endif

Example/OpenSwiftUIUITests/View/DynamicViewContent/ForEachUITests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,32 @@ struct ForEachUITests {
3737
}
3838
openSwiftUIAssertSnapshot(of: ContentView())
3939
}
40+
41+
@Test
42+
func insertAnimation() {
43+
struct ContentView: AnimationTestView {
44+
nonisolated static var model: AnimationTestModel {
45+
AnimationTestModel(duration: 1.0, count: 5)
46+
}
47+
48+
@State private var opacities = [0, 0.5, 1.0]
49+
50+
var body: some View {
51+
VStack(spacing: 0) {
52+
ForEach(opacities, id: \.self) { opacity in
53+
Color.red.opacity(opacity)
54+
}
55+
}.onAppear {
56+
withAnimation(.spring(duration: Self.model.duration)) {
57+
opacities.insert(0.25, at: 1)
58+
opacities.insert(0.75, at: 3)
59+
}
60+
}
61+
}
62+
}
63+
withKnownIssue("#632") {
64+
Issue.record("AttributeGraph precondition failure: accessing attribute in a different namespace: 36376.")
65+
// openSwiftUIAssertAnimationSnapshot(of: ContentView())
66+
}
67+
}
4068
}

0 commit comments

Comments
 (0)