Skip to content

Commit 0fcf721

Browse files
authored
Migrate Snapshot Tests to Swift Testing Framework (#534)
* update testsplans * add references * migrate to swift testing * update references * update testplans * add extensions * update color * update lanes and add snapshot tests workflow file
1 parent 9469065 commit 0fcf721

File tree

66 files changed

+488
-289
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+488
-289
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Snapshot Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
jobs:
10+
snapshot_tests:
11+
name: Snapshot Tests
12+
runs-on: macos-latest
13+
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v6
17+
18+
- name: Create Required Simulators
19+
run: |
20+
set -eo pipefail
21+
xcrun simctl delete all
22+
fastlane create_simulators platform:iOS version:18
23+
24+
- name: List available simulators
25+
run: xcrun simctl list devices available
26+
27+
- name: Setup Xcode version
28+
uses: maxim-lobanov/setup-xcode@v1.6.0
29+
with:
30+
xcode-version: latest-stable
31+
32+
- name: Run Snapshot Tests
33+
run: fastlane snapshot_tests
34+
35+
- name: Archive test artifacts
36+
uses: actions/upload-artifact@v6
37+
if: failure()
38+
with:
39+
name: snapshot-test-artifacts
40+
path: |
41+
./fastlane/test_output/*.xcresult
42+
43+
- name: Upload snapshot failures
44+
uses: actions/upload-artifact@v6
45+
if: failure()
46+
with:
47+
name: snapshot-failures
48+
path: |
49+
**/__Snapshots__/**/*.png
50+
**/FailureDiffs/*.png

CriticalMaps.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
73CD4DA12C595584003CAEA2 /* GuideFeature.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = GuideFeature.xctestplan; sourceTree = "<group>"; };
5353
73CF5FF1263EB0A6001925A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
5454
73CF5FF6263EB0A6001925A3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
55+
73D622122F096BD200B72BF1 /* Styleguide.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Styleguide.xctestplan; sourceTree = "<group>"; };
5556
73EA92422C595702008DEEFE /* MastodonFeedFeature.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MastodonFeedFeature.xctestplan; sourceTree = "<group>"; };
5657
73EA92432C59585D008DEEFE /* SocialFeature.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = SocialFeature.xctestplan; sourceTree = "<group>"; };
5758
73EB0310263F23A100941D57 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
@@ -98,6 +99,7 @@
9899
7347AB282A27C0CA00BCA949 /* Testplans */ = {
99100
isa = PBXGroup;
100101
children = (
102+
73D622122F096BD200B72BF1 /* Styleguide.xctestplan */,
101103
73EA92432C59585D008DEEFE /* SocialFeature.xctestplan */,
102104
73EA92422C595702008DEEFE /* MastodonFeedFeature.xctestplan */,
103105
73CD4DA12C595584003CAEA2 /* GuideFeature.xctestplan */,

CriticalMapsKit/.swiftpm/xcode/xcshareddata/xcschemes/Styleguide.xcscheme

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@
2727
buildConfiguration = "Debug"
2828
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2929
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
30-
shouldUseLaunchSchemeArgsEnv = "YES"
31-
shouldAutocreateTestPlan = "YES">
30+
shouldUseLaunchSchemeArgsEnv = "YES">
31+
<TestPlans>
32+
<TestPlanReference
33+
reference = "container:../Testplans/Styleguide.xctestplan"
34+
default = "YES">
35+
</TestPlanReference>
36+
</TestPlans>
3237
</TestAction>
3338
<LaunchAction
3439
buildConfiguration = "Debug"

CriticalMapsKit/Package.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,6 @@ package.targets.append(contentsOf: [
282282
"MapFeature",
283283
.testHelper,
284284
.tca
285-
],
286-
exclude: [
287-
"__Snapshots__"
288285
]
289286
),
290287
.testTarget(

CriticalMapsKit/Sources/ChatFeature/SubViews/UITextViewWrapper.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct UITextViewWrapper: UIViewRepresentable {
4848
view.delegate = context.coordinator
4949

5050
view.font = UIFont.preferredFont(forTextStyle: .body)
51-
view.textColor = UIColor.label
51+
view.textColor = UIColor.textPrimary
5252
view.backgroundColor = .clear
5353

5454
let attrs = textAttributes

CriticalMapsKit/Sources/TestHelper/SnapshotIntegration.swift renamed to CriticalMapsKit/Sources/TestHelper/Export.swift

File renamed without changes.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import SnapshotTesting
2+
import SwiftUI
3+
import XCTest
4+
5+
public enum SnapshotHelper {
6+
@MainActor
7+
private static func enforceSnapshotDevice() throws {
8+
let is2XDevice = UIScreen.main.scale >= 2
9+
let isMinVersion16 = operatingSystemVersion.majorVersion >= 16
10+
11+
guard is2XDevice, isMinVersion16 else {
12+
throw SnapshotError.deviceNot2XOrNotIOS16
13+
}
14+
}
15+
16+
@MainActor
17+
public static func assertScreenSnapshot(
18+
_ view: some View,
19+
sloppy: Bool = true,
20+
file: StaticString = #filePath,
21+
testName: String = #function,
22+
line: UInt = #line
23+
) throws {
24+
try enforceSnapshotDevice()
25+
26+
let precision: Float = (sloppy ? .sloppyPrecision : 1)
27+
28+
withSnapshotTesting(diffTool: .ksdiff) {
29+
assertSnapshots(
30+
of: view,
31+
as: [
32+
.image(
33+
precision: precision,
34+
perceptualPrecision: precision,
35+
layout: .device(config: .iPhone16),
36+
traits: .iPhone16(.portrait)
37+
)
38+
],
39+
file: file,
40+
testName: testName,
41+
line: line
42+
)
43+
}
44+
}
45+
46+
@MainActor
47+
public static func assertViewSnapshot(
48+
_ view: some View,
49+
height: CGFloat? = nil,
50+
width: CGFloat = 375,
51+
sloppy: Bool = false,
52+
file: StaticString = #filePath,
53+
testName: String = #function,
54+
line: UInt = #line
55+
) throws {
56+
try enforceSnapshotDevice()
57+
58+
var layout = SwiftUISnapshotLayout.device(config: .iPhone16)
59+
if let height {
60+
layout = .fixed(width: width, height: height)
61+
}
62+
let precision: Float = (sloppy ? .sloppyPrecision : 1)
63+
64+
withSnapshotTesting(diffTool: .ksdiff) {
65+
assertSnapshot(
66+
of: view,
67+
as: .image(precision: precision, layout: layout),
68+
file: file,
69+
testName: testName,
70+
line: line
71+
)
72+
}
73+
}
74+
}
75+
76+
// MARK: - Helper
77+
78+
private extension Float {
79+
static let sloppyPrecision: Float = 0.95
80+
}
81+
82+
private let operatingSystemVersion = ProcessInfo().operatingSystemVersion
83+
84+
public enum SnapshotError: Error {
85+
case deviceNot2XOrNotIOS16
86+
}
87+
88+
public extension ViewImageConfig {
89+
static let iPhone16 = ViewImageConfig.iPhone16(.portrait)
90+
91+
static func iPhone16(_ orientation: Orientation) -> ViewImageConfig {
92+
let safeArea: UIEdgeInsets
93+
let size: CGSize
94+
switch orientation {
95+
case .landscape:
96+
safeArea = .init(top: 0, left: 59, bottom: 21, right: 59)
97+
size = .init(width: 852, height: 393)
98+
case .portrait:
99+
safeArea = .init(top: 59, left: 0, bottom: 34, right: 0)
100+
size = .init(width: 393, height: 852)
101+
}
102+
return .init(safeArea: safeArea, size: size, traits: .iPhone16(orientation))
103+
}
104+
}
105+
106+
public extension UITraitCollection {
107+
static func iPhone16(_ orientation: ViewImageConfig.Orientation) -> UITraitCollection {
108+
if #available(iOS 17.0, *) {
109+
return UITraitCollection(mutations: { mutableTraits in
110+
mutableTraits.forceTouchCapability = .unavailable
111+
mutableTraits.layoutDirection = .leftToRight
112+
mutableTraits.preferredContentSizeCategory = .medium
113+
mutableTraits.userInterfaceIdiom = .phone
114+
switch orientation {
115+
case .landscape:
116+
mutableTraits.horizontalSizeClass = .compact
117+
mutableTraits.verticalSizeClass = .compact
118+
case .portrait:
119+
mutableTraits.horizontalSizeClass = .compact
120+
mutableTraits.verticalSizeClass = .regular
121+
}
122+
})
123+
} else {
124+
let base: [UITraitCollection] = [
125+
.init(forceTouchCapability: .unavailable),
126+
.init(layoutDirection: .leftToRight),
127+
.init(preferredContentSizeCategory: .medium),
128+
.init(userInterfaceIdiom: .phone)
129+
]
130+
switch orientation {
131+
case .landscape:
132+
return .init(
133+
traitsFrom: base + [
134+
.init(horizontalSizeClass: .compact),
135+
.init(verticalSizeClass: .compact)
136+
]
137+
)
138+
case .portrait:
139+
return .init(
140+
traitsFrom: base + [
141+
.init(horizontalSizeClass: .compact),
142+
.init(verticalSizeClass: .regular)
143+
]
144+
)
145+
}
146+
}
147+
}
148+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
import Testing
3+
4+
public extension Tag {
5+
@Tag
6+
static var snapshot: Self
7+
}

CriticalMapsKit/Sources/TestHelper/XCTestCase+Additions.swift

Lines changed: 0 additions & 80 deletions
This file was deleted.

0 commit comments

Comments
 (0)