Skip to content

Commit 7c06008

Browse files
authored
Merge pull request #6 from oreillymedia/fix/update-dec-2024
FIX Update to latest, including Swift Testing support
2 parents 2d0d95e + 42a0861 commit 7c06008

File tree

15 files changed

+174
-59
lines changed

15 files changed

+174
-59
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ jobs:
1313
strategy:
1414
matrix:
1515
xcode:
16-
- "14.3.1"
16+
- 15.4
17+
- '16.0'
1718

18-
name: macOS 13 (Xcode ${{ matrix.xcode }})
19-
runs-on: macos-13
19+
name: macOS
20+
runs-on: macos-14
2021
steps:
2122
- uses: actions/checkout@v3
2223
- name: Select Xcode ${{ matrix.xcode }}

Sources/SnapshotTesting/AssertSnapshot.swift

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import XCTest
22

3+
#if canImport(Testing)
4+
import Testing
5+
#endif
6+
37
/// Enhances failure messages with a command line diff tool expression that can be copied and pasted
48
/// into a terminal.
59
@available(
@@ -9,12 +13,33 @@ import XCTest
913
"Use 'withSnapshotTesting' to customize the diff tool. See the documentation for more information."
1014
)
1115
public var diffTool: SnapshotTestingConfiguration.DiffTool {
12-
get { _diffTool }
16+
get {
17+
_diffTool
18+
}
1319
set { _diffTool = newValue }
1420
}
1521

1622
@_spi(Internals)
17-
public var _diffTool: SnapshotTestingConfiguration.DiffTool = .default
23+
public var _diffTool: SnapshotTestingConfiguration.DiffTool {
24+
get {
25+
#if canImport(Testing)
26+
if let test = Test.current {
27+
for trait in test.traits.reversed() {
28+
if let diffTool = (trait as? _SnapshotsTestTrait)?.configuration.diffTool {
29+
return diffTool
30+
}
31+
}
32+
}
33+
#endif
34+
return __diffTool
35+
}
36+
set {
37+
__diffTool = newValue
38+
}
39+
}
40+
41+
@_spi(Internals)
42+
public var __diffTool: SnapshotTestingConfiguration.DiffTool = .default
1843

1944
/// Whether or not to record all new references.
2045
@available(
@@ -28,7 +53,26 @@ public var isRecording: Bool {
2853
}
2954

3055
@_spi(Internals)
31-
public var _record: SnapshotTestingConfiguration.Record = {
56+
public var _record: SnapshotTestingConfiguration.Record {
57+
get {
58+
#if canImport(Testing)
59+
if let test = Test.current {
60+
for trait in test.traits.reversed() {
61+
if let record = (trait as? _SnapshotsTestTrait)?.configuration.record {
62+
return record
63+
}
64+
}
65+
}
66+
#endif
67+
return __record
68+
}
69+
set {
70+
__record = newValue
71+
}
72+
}
73+
74+
@_spi(Internals)
75+
public var __record: SnapshotTestingConfiguration.Record = {
3276
if let value = ProcessInfo.processInfo.environment["SNAPSHOT_TESTING_RECORD"],
3377
let record = SnapshotTestingConfiguration.Record(rawValue: value)
3478
{
@@ -311,7 +355,9 @@ public func verifySnapshot<Value, Format>(
311355
func recordSnapshot() throws {
312356
try snapshotting.diffing.toData(diffable).write(to: snapshotFileUrl)
313357
#if !os(Linux) && !os(Windows)
314-
if ProcessInfo.processInfo.environment.keys.contains("__XCODE_BUILT_PRODUCTS_DIR_PATHS") {
358+
if !isSwiftTesting,
359+
ProcessInfo.processInfo.environment.keys.contains("__XCODE_BUILT_PRODUCTS_DIR_PATHS")
360+
{
315361
XCTContext.runActivity(named: "Attached Recorded Snapshot") { activity in
316362
let attachment = XCTAttachment(contentsOfFile: snapshotFileUrl)
317363
activity.add(attachment)
@@ -373,7 +419,9 @@ public func verifySnapshot<Value, Format>(
373419

374420
if !attachments.isEmpty {
375421
#if !os(Linux) && !os(Windows)
376-
if ProcessInfo.processInfo.environment.keys.contains("__XCODE_BUILT_PRODUCTS_DIR_PATHS") {
422+
if ProcessInfo.processInfo.environment.keys.contains("__XCODE_BUILT_PRODUCTS_DIR_PATHS"),
423+
!isSwiftTesting
424+
{
377425
XCTContext.runActivity(named: "Attached Failure Diff") { activity in
378426
attachments.forEach {
379427
activity.add($0)

Sources/SnapshotTesting/Documentation.docc/Articles/IntegratingWithTestFrameworks.md

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,14 @@ class FeatureTests: XCTestCase {
6767

6868
This will override the `diffTool` and `record` properties for each test function.
6969

70-
Swift's new testing framework does not currently have a public API for this kind of customization.
71-
There is an experimental feature, called `CustomExecutionTrait`, that does gives us this ability,
72-
and the library provides such a trait called ``Testing/Trait/snapshots(diffTool:record:)``. It can
73-
be attached to any `@Test` or `@Suite` to configure snapshot testing:
70+
Swift's new testing framework also allows for this kind of configuration, both for a single test
71+
and an entire test suite. This is done via what are known as "test traits":
7472

7573
```swift
76-
@_spi(Experimental) import SnapshotTesting
74+
import SnapshotTesting
7775

7876
@Suite(.snapshots(record: .all, diffTool: .ksdiff))
7977
struct FeatureTests {
8078
8179
}
8280
```
83-
84-
> Important: You must import SnapshotTesting with the `@_spi(Experimental)` attribute to get access
85-
to this functionality because Swift Testing's own `CustomExecutionTrait` is hidden behind the same
86-
SPI flag. This means this API is subject to change in the future, but hopefully Apple will
87-
publicize this tool soon.

Sources/SnapshotTesting/Documentation.docc/Articles/MigrationGuides/MigratingTo1.17.md

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,12 @@ in an XCTest context or a Swift Testing context, and will determine if it should
151151
`Issue.record` to trigger a test failure.
152152

153153
For the most part you can write tests for Swift Testing exactly as you would for XCTest. However,
154-
there is one major difference. Swift Testing does not (yet) have a substitute for `invokeTest`,
155-
which we used alongside `withSnapshotTesting` to customize snapshotting for a full test class.
156-
157-
There is an experimental version of this tool in Swift Testing, called `CustomExecutionTrait`, and
158-
this library provides such a trait called ``Testing/Trait/snapshots(diffTool:record:)``. It allows
159-
you to customize snapshots for a `@Test` or `@Suite`, but to get access to it you must perform an
160-
`@_spi(Experimental)` import of snapshot testing:
154+
there is one major difference. In order to override a snapshot's
155+
[configuration](<doc:SnapshotTestingConfiguration>) for a particular test or an entire suite you
156+
must use what are known as "test traits":
161157
162158
```swift
163-
@_spi(Experimental) import SnapshotTesting
159+
import SnapshotTesting
164160
165161
@Suite(.snapshots(record: .all, diffTool: .ksdiff))
166162
struct FeatureTests {
@@ -169,7 +165,4 @@ struct FeatureTests {
169165
```
170166
171167
That will override the `diffTool` and `record` options for the entire `FeatureTests` suite.
172-
173-
> Important: As evident by the usage of `@_spi(Experimental)` this API is subject to change. As
174-
soon as the Swift Testing library finalizes its API for `CustomExecutionTrait` we will update
175-
the library accordingly and remove the `@_spi` annotation.
168+
These traits can also be used on individual `@Test`s too.

Sources/SnapshotTesting/Internal/RecordIssue.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import XCTest
44
import Testing
55
#endif
66

7+
var isSwiftTesting: Bool {
8+
#if canImport(Testing)
9+
return Test.current != nil
10+
#else
11+
return false
12+
#endif
13+
}
14+
715
@_spi(Internals)
816
public func recordIssue(
917
_ message: @autoclosure () -> String,

Sources/SnapshotTesting/SnapshotsTestTrait.swift

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#if canImport(Testing)
2-
@_spi(Experimental) import Testing
2+
import Testing
33

4-
@_spi(Experimental)
54
extension Trait where Self == _SnapshotsTestTrait {
65
/// Configure snapshot testing in a suite or test.
76
///
@@ -31,22 +30,21 @@
3130
}
3231

3332
/// A type representing the configuration of snapshot testing.
34-
@_spi(Experimental)
35-
public struct _SnapshotsTestTrait: CustomExecutionTrait, SuiteTrait, TestTrait {
33+
public struct _SnapshotsTestTrait: SuiteTrait, TestTrait {
3634
public let isRecursive = true
3735
let configuration: SnapshotTestingConfiguration
3836

39-
public func execute(
40-
_ function: @escaping () async throws -> Void,
41-
for test: Test,
42-
testCase: Test.Case?
43-
) async throws {
44-
try await withSnapshotTesting(
45-
record: configuration.record,
46-
diffTool: configuration.diffTool
47-
) {
48-
try await function()
49-
}
50-
}
37+
// public func execute(
38+
// _ function: @escaping () async throws -> Void,
39+
// for test: Test,
40+
// testCase: Test.Case?
41+
// ) async throws {
42+
// try await withSnapshotTesting(
43+
// record: configuration.record,
44+
// diffTool: configuration.diffTool
45+
// ) {
46+
// try await function()
47+
// }
48+
// }
5149
}
5250
#endif

Sources/SnapshotTesting/Snapshotting/CGPath.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@
153153

154154
private let defaultNumberFormatter: NumberFormatter = {
155155
let numberFormatter = NumberFormatter()
156+
numberFormatter.decimalSeparator = "."
156157
numberFormatter.minimumFractionDigits = 1
157158
numberFormatter.maximumFractionDigits = 3
158159
return numberFormatter

Sources/SnapshotTesting/Snapshotting/NSBezierPath.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105

106106
private let defaultNumberFormatter: NumberFormatter = {
107107
let numberFormatter = NumberFormatter()
108+
numberFormatter.decimalSeparator = "."
108109
numberFormatter.minimumFractionDigits = 1
109110
numberFormatter.maximumFractionDigits = 3
110111
return numberFormatter

Tests/InlineSnapshotTestingTests/AssertInlineSnapshotSwiftTests.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import Testing
33
import Foundation
44
import InlineSnapshotTesting
5-
@_spi(Experimental) import SnapshotTesting
5+
import SnapshotTesting
66

77
@Suite(
88
.snapshots(
@@ -21,6 +21,28 @@
2121
}
2222
}
2323

24+
@Test func inlineSnapshotFailure() {
25+
withKnownIssue {
26+
assertInlineSnapshot(of: ["Hello", "World"], as: .dump) {
27+
"""
28+
▿ 2 elements
29+
- "Hello"
30+
31+
"""
32+
}
33+
} matching: { issue in
34+
issue.description == """
35+
Issue recorded: Snapshot did not match. Difference: …
36+
37+
@@ −1,3 +1,4 @@
38+
 ▿ 2 elements
39+
  - "Hello"
40+
+ - "World"
41+
42+
"""
43+
}
44+
}
45+
2446
@Test func inlineSnapshot_NamedTrailingClosure() {
2547
assertInlineSnapshot(
2648
of: ["Hello", "World"], as: .dump,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#if canImport(Testing)
2+
import Testing
3+
import Foundation
4+
import SnapshotTesting
5+
6+
@Suite(
7+
.snapshots(
8+
record: .missing
9+
)
10+
)
11+
struct AssertSnapshotTests {
12+
@Test func dump() {
13+
struct User { let id: Int, name: String, bio: String }
14+
let user = User(id: 1, name: "Blobby", bio: "Blobbed around the world.")
15+
assertSnapshot(of: user, as: .dump)
16+
}
17+
}
18+
#endif

Tests/SnapshotTestingTests/SnapshotsTraitTests.swift

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#if compiler(>=6) && canImport(Testing)
2-
@_spi(Experimental) import Testing
3-
@_spi(Experimental) @_spi(Internals) import SnapshotTesting
2+
import Testing
3+
@_spi(Internals) import SnapshotTesting
44

55
struct SnapshotsTraitTests {
66
@Test(.snapshots(diffTool: "ksdiff"))
77
func testDiffTool() {
88
#expect(
9-
SnapshotTestingConfiguration.current?
10-
.diffTool?(currentFilePath: "old.png", failedFilePath: "new.png")
9+
_diffTool(currentFilePath: "old.png", failedFilePath: "new.png")
1110
== "ksdiff old.png new.png"
1211
)
1312
}
@@ -17,8 +16,7 @@
1716
@Test(.snapshots(diffTool: "difftool"))
1817
func testDiffToolOverride() {
1918
#expect(
20-
SnapshotTestingConfiguration.current?
21-
.diffTool?(currentFilePath: "old.png", failedFilePath: "new.png")
19+
_diffTool(currentFilePath: "old.png", failedFilePath: "new.png")
2220
== "difftool old.png new.png"
2321
)
2422
}
@@ -28,23 +26,21 @@
2826
@Test
2927
func config() {
3028
#expect(
31-
SnapshotTestingConfiguration.current?
32-
.diffTool?(currentFilePath: "old.png", failedFilePath: "new.png")
29+
_diffTool(currentFilePath: "old.png", failedFilePath: "new.png")
3330
== "ksdiff old.png new.png"
3431
)
35-
#expect(SnapshotTestingConfiguration.current?.record == .all)
32+
#expect(_record == .all)
3633
}
3734

3835
@Suite(.snapshots(record: .failed, diffTool: "diff"))
3936
struct OverrideDiffToolAndRecord {
4037
@Test
4138
func config() {
4239
#expect(
43-
SnapshotTestingConfiguration.current?
44-
.diffTool?(currentFilePath: "old.png", failedFilePath: "new.png")
40+
_diffTool(currentFilePath: "old.png", failedFilePath: "new.png")
4541
== "diff old.png new.png"
4642
)
47-
#expect(SnapshotTestingConfiguration.current?.record == .failed)
43+
#expect(_record == .failed)
4844
}
4945
}
5046
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#if compiler(>=6) && canImport(Testing)
2+
import Testing
3+
import SnapshotTesting
4+
5+
@Suite(.snapshots(diffTool: "ksdiff"))
6+
struct SwiftTestingTests {
7+
@Test func testSnapshot() {
8+
assertSnapshot(of: ["Hello", "World"], as: .dump)
9+
}
10+
11+
@Test func testSnapshotFailure() {
12+
withKnownIssue {
13+
assertSnapshot(of: ["Goodbye", "World"], as: .dump)
14+
} matching: { issue in
15+
issue.description.hasSuffix(
16+
"""
17+
@@ −1,4 +1,4 @@
18+
 ▿ 2 elements
19+
− - "Hello"
20+
+ - "Goodbye"
21+
  - "World"
22+
""")
23+
}
24+
}
25+
}
26+
#endif
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
▿ User
2+
- bio: "Blobbed around the world."
3+
- id: 1
4+
- name: "Blobby"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
▿ 2 elements
2+
- "Hello"
3+
- "World"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
▿ 2 elements
2+
- "Hello"
3+
- "World"

0 commit comments

Comments
 (0)