Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beta support for Swift Testing, and other improvements. #867

Merged
merged 50 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
2d45183
wip
mbrandonw Jul 3, 2024
3cda2a7
wip
mbrandonw Jul 3, 2024
e71cde1
wip
mbrandonw Jul 3, 2024
822361a
wip
mbrandonw Jul 3, 2024
4201a54
wip
mbrandonw Jul 3, 2024
2408cc7
tests
mbrandonw Jul 3, 2024
8f8da79
wip
mbrandonw Jul 3, 2024
3e37ab0
migration guide
mbrandonw Jul 4, 2024
1efdcec
wip
mbrandonw Jul 4, 2024
b479fa4
wip
mbrandonw Jul 4, 2024
7760adf
wip
stephencelis Jul 4, 2024
7ad8430
Update Sources/SnapshotTesting/AssertSnapshot.swift
stephencelis Jul 4, 2024
cf5666e
wip
mbrandonw Jul 4, 2024
9a6f879
formatting
mbrandonw Jul 4, 2024
104d43f
wip
stephencelis Jul 4, 2024
d69e681
format
stephencelis Jul 4, 2024
9125d57
more
stephencelis Jul 4, 2024
0b9826b
wip
stephencelis Jul 4, 2024
ca6f4dc
fix
stephencelis Jul 4, 2024
d8fecd2
Merge remote-tracking branch 'origin/main' into swift-testing
stephencelis Jul 4, 2024
d84b345
Merge remote-tracking branch 'origin/main' into swift-testing
stephencelis Jul 4, 2024
ac36312
Make record mode opaque.
mbrandonw Jul 4, 2024
246c2e1
more docs
mbrandonw Jul 4, 2024
9d2c475
wip
mbrandonw Jul 4, 2024
9810df4
wip
mbrandonw Jul 4, 2024
0c6b449
Added new 'failed' record strategy, and wrote some tests.
mbrandonw Jul 4, 2024
a30e1ad
remove test artificats
mbrandonw Jul 4, 2024
54945d9
wip
mbrandonw Jul 4, 2024
f18aa61
more docs
mbrandonw Jul 4, 2024
f78bb29
fix linux tests
mbrandonw Jul 4, 2024
4463f37
more test fixes
mbrandonw Jul 4, 2024
6b5147e
test clean up
mbrandonw Jul 4, 2024
a3dd71d
debugging
mbrandonw Jul 4, 2024
6031605
debug
mbrandonw Jul 4, 2024
7617c60
wip
mbrandonw Jul 4, 2024
b87309a
fix
mbrandonw Jul 4, 2024
2de533c
fix tests
mbrandonw Jul 4, 2024
ef4f24e
wip
stephencelis Jul 4, 2024
aaf6ce4
wip
stephencelis Jul 4, 2024
f98a7e7
wip
stephencelis Jul 4, 2024
30c3469
make snapshot configuration optional
mbrandonw Jul 8, 2024
50e71d5
make snapshot configuration optional
mbrandonw Jul 8, 2024
42feef6
clean up
mbrandonw Jul 8, 2024
bd68b8f
fix
mbrandonw Jul 8, 2024
3eba8e2
indent
mbrandonw Jul 8, 2024
9a5361e
typo
mbrandonw Jul 8, 2024
c4842c3
more clean up
mbrandonw Jul 8, 2024
2dc8dab
record before difftool
mbrandonw Jul 8, 2024
ea63fe0
more tests
mbrandonw Jul 8, 2024
f4227b3
clean up test code
mbrandonw Jul 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 98 additions & 75 deletions Sources/InlineSnapshotTesting/AssertInlineSnapshot.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

#if canImport(SwiftSyntax509)
import SnapshotTesting
@_spi(Internals) import SnapshotTesting
import SwiftParser
import SwiftSyntax
import SwiftSyntaxBuilder
Expand Down Expand Up @@ -35,7 +35,7 @@ import Foundation
of value: @autoclosure () throws -> Value?,
as snapshotting: Snapshotting<Value, String>,
message: @autoclosure () -> String = "",
record isRecording: Bool = isRecording,
record isRecording: Bool? = nil,
timeout: TimeInterval = 5,
syntaxDescriptor: InlineSnapshotSyntaxDescriptor = InlineSnapshotSyntaxDescriptor(),
matches expected: (() -> String)? = nil,
Expand All @@ -44,95 +44,116 @@ import Foundation
line: UInt = #line,
column: UInt = #column
) {
let _: Void = installTestObserver
do {
var actual: String?
let expectation = XCTestExpectation()
if let value = try value() {
snapshotting.snapshot(value).run {
actual = $0
expectation.fulfill()
let record =
(isRecording == true ? .all : isRecording == false ? .missing : nil)
?? SnapshotTestingConfiguration.current?.record
?? _record
withSnapshotTesting(record: record) {
let _: Void = installTestObserver
do {
var actual: String?
let expectation = XCTestExpectation()
if let value = try value() {
snapshotting.snapshot(value).run {
actual = $0
expectation.fulfill()
}
switch XCTWaiter.wait(for: [expectation], timeout: timeout) {
case .completed:
break
case .timedOut:
recordIssue(
"""
Exceeded timeout of \(timeout) seconds waiting for snapshot.

This can happen when an asynchronously loaded value (like a network response) has not \
loaded. If a timeout is unavoidable, consider setting the "timeout" parameter of
"assertInlineSnapshot" to a higher value.
""",
file: file,
line: line
)
return
case .incorrectOrder, .interrupted, .invertedFulfillment:
recordIssue("Couldn't snapshot value", file: file, line: line)
return
@unknown default:
recordIssue("Couldn't snapshot value", file: file, line: line)
return
}
}
switch XCTWaiter.wait(for: [expectation], timeout: timeout) {
case .completed:
break
case .timedOut:
XCTFail(
let expected = expected?()
guard
record != .all,
record != .missing || expected != nil
else {
// NB: Write snapshot state before calling `XCTFail` in case `continueAfterFailure = false`
inlineSnapshotState[File(path: file), default: []].append(
InlineSnapshot(
expected: expected,
actual: actual,
wasRecording: record == .all,
syntaxDescriptor: syntaxDescriptor,
function: "\(function)",
line: line,
column: column
)
)

var failure: String
if syntaxDescriptor.trailingClosureLabel
== InlineSnapshotSyntaxDescriptor.defaultTrailingClosureLabel
{
failure = "Automatically recorded a new snapshot."
} else {
failure = """
Automatically recorded a new snapshot for "\(syntaxDescriptor.trailingClosureLabel)".
"""
}
if let difference = snapshotting.diffing.diff(expected ?? "", actual ?? "")?.0 {
failure += " Difference: …\n\n\(difference.indenting(by: 2))"
}
recordIssue(
"""
Exceeded timeout of \(timeout) seconds waiting for snapshot.
\(failure)

This can happen when an asynchronously loaded value (like a network response) has not \
loaded. If a timeout is unavoidable, consider setting the "timeout" parameter of
"assertInlineSnapshot" to a higher value.
Re-run "\(function)" to assert against the newly-recorded snapshot.
""",
file: file,
line: line
)
return
case .incorrectOrder, .interrupted, .invertedFulfillment:
XCTFail("Couldn't snapshot value", file: file, line: line)
return
@unknown default:
XCTFail("Couldn't snapshot value", file: file, line: line)
return
}
}
let expected = expected?()
guard !isRecording, let expected
else {
// NB: Write snapshot state before calling `XCTFail` in case `continueAfterFailure = false`
inlineSnapshotState[File(path: file), default: []].append(
InlineSnapshot(
expected: expected,
actual: actual,
wasRecording: isRecording,
syntaxDescriptor: syntaxDescriptor,
function: "\(function)",
line: line,
column: column
)
)

var failure: String
if syntaxDescriptor.trailingClosureLabel
== InlineSnapshotSyntaxDescriptor.defaultTrailingClosureLabel
{
failure = "Automatically recorded a new snapshot."
} else {
failure = """
Automatically recorded a new snapshot for "\(syntaxDescriptor.trailingClosureLabel)".
guard let expected
else {
recordIssue(
"""
No expected value to assert against.
""",
file: file,
line: line
)
return
}
if let difference = snapshotting.diffing.diff(expected ?? "", actual ?? "")?.0 {
failure += " Difference: …\n\n\(difference.indenting(by: 2))"
}
XCTFail(
guard
let difference = snapshotting.diffing.diff(expected, actual ?? "")?.0
else { return }

let message = message()
syntaxDescriptor.fail(
"""
\(failure)
\(message.isEmpty ? "Snapshot did not match. Difference: …" : message)

Re-run "\(function)" to assert against the newly-recorded snapshot.
\(difference.indenting(by: 2))
""",
file: file,
line: line
line: line,
column: column
)
return
} catch {
recordIssue("Threw error: \(error)", file: file, line: line)
}
guard let difference = snapshotting.diffing.diff(expected, actual ?? "")?.0
else { return }

let message = message()
syntaxDescriptor.fail(
"""
\(message.isEmpty ? "Snapshot did not match. Difference: …" : message)

\(difference.indenting(by: 2))
""",
file: file,
line: line,
column: column
)
} catch {
XCTFail("Threw error: \(error)", file: file, line: line)
}
}
#else
Expand Down Expand Up @@ -197,6 +218,8 @@ public struct InlineSnapshotSyntaxDescriptor: Hashable {
/// Initializes an inline snapshot syntax descriptor.
///
/// - Parameters:
/// - deprecatedTrailingClosureLabels: An array of deprecated labels to consider for the inline
/// snapshot.
/// - trailingClosureLabel: The label of the trailing closure that returns the inline snapshot.
/// - trailingClosureOffset: The offset of the trailing closure that returns the inline
/// snapshot, relative to the first trailing closure.
Expand Down Expand Up @@ -242,7 +265,7 @@ public struct InlineSnapshotSyntaxDescriptor: Hashable {
visitor.walk(testSource.sourceFile)
trailingClosureLine = visitor.trailingClosureLine
}
XCTFail(
recordIssue(
message(),
file: file,
line: trailingClosureLine.map(UInt.init) ?? line
Expand Down Expand Up @@ -386,7 +409,7 @@ public struct InlineSnapshotSyntaxDescriptor: Hashable {
) {
self.file = file
self.line = snapshots.first?.line
self.wasRecording = snapshots.first?.wasRecording ?? isRecording
self.wasRecording = snapshots.first?.wasRecording ?? false
self.indent = String(
sourceLocationConverter.sourceLines
.first { $0.first?.isWhitespace == true && $0.contains { !$0.isWhitespace } }?
Expand Down
Loading
Loading