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

Record Attachments in Never mode #943

Merged
merged 2 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
matrix:
xcode:
- 15.4
- '16.0'
- '16.1'

name: macOS
runs-on: macos-14
Expand Down
68 changes: 54 additions & 14 deletions Sources/SnapshotTesting/AssertSnapshot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -352,42 +352,69 @@ public func verifySnapshot<Value, Format>(
return "Couldn't snapshot value"
}

func recordSnapshot() throws {
try snapshotting.diffing.toData(diffable).write(to: snapshotFileUrl)
func recordSnapshot(writeToDisk: Bool) throws {
let snapshotData = snapshotting.diffing.toData(diffable)

if writeToDisk {
try snapshotData.write(to: snapshotFileUrl)
}

#if !os(Linux) && !os(Windows)
if !isSwiftTesting,
ProcessInfo.processInfo.environment.keys.contains("__XCODE_BUILT_PRODUCTS_DIR_PATHS")
{
XCTContext.runActivity(named: "Attached Recorded Snapshot") { activity in
let attachment = XCTAttachment(contentsOfFile: snapshotFileUrl)
activity.add(attachment)
if writeToDisk {
// Snapshot was written to disk. Create attachment from file
let attachment = XCTAttachment(contentsOfFile: snapshotFileUrl)
activity.add(attachment)
} else {
// Snapshot was not written to disk. Create attachment from data and path extension
let typeIdentifier = snapshotting.pathExtension.flatMap(uniformTypeIdentifier(fromExtension:))

let attachment = XCTAttachment(
uniformTypeIdentifier: typeIdentifier,
name: snapshotFileUrl.lastPathComponent,
payload: snapshotData
)

activity.add(attachment)
}
}
}
#endif
}

guard
record != .all,
(record != .missing && record != .failed)
|| fileManager.fileExists(atPath: snapshotFileUrl.path)
else {
try recordSnapshot()
if record == .all {
try recordSnapshot(writeToDisk: true)

return SnapshotTestingConfiguration.current?.record == .all
? """
return """
Record mode is on. Automatically recorded snapshot: …

open "\(snapshotFileUrl.absoluteString)"

Turn record mode off and re-run "\(testName)" to assert against the newly-recorded snapshot
"""
: """
}

guard fileManager.fileExists(atPath: snapshotFileUrl.path) else {
if record == .never {
try recordSnapshot(writeToDisk: false)

return """
No reference was found on disk. New snapshot was not recorded because recording is disabled
"""
} else {
try recordSnapshot(writeToDisk: true)

return """
No reference was found on disk. Automatically recorded snapshot: …

open "\(snapshotFileUrl.absoluteString)"

Re-run "\(testName)" to assert against the newly-recorded snapshot.
"""
}
}

let data = try Data(contentsOf: snapshotFileUrl)
Expand Down Expand Up @@ -444,7 +471,7 @@ public func verifySnapshot<Value, Format>(
}

if record == .failed {
try recordSnapshot()
try recordSnapshot(writeToDisk: true)
failureMessage += " A new snapshot was automatically recorded."
}

Expand Down Expand Up @@ -473,6 +500,19 @@ func sanitizePathComponent(_ string: String) -> String {
.replacingOccurrences(of: "^-|-$", with: "", options: .regularExpression)
}

#if !os(Linux) && !os(Windows)
func uniformTypeIdentifier(fromExtension pathExtension: String) -> String? {
// This can be much cleaner in macOS 11+ using UTType
let unmanagedString = UTTypeCreatePreferredIdentifierForTag(
kUTTagClassFilenameExtension as CFString,
pathExtension as CFString,
nil
)

return unmanagedString?.takeRetainedValue() as String?
}
#endif

// We need to clean counter between tests executions in order to support test-iterations.
private class CleanCounterBetweenTestCases: NSObject, XCTestObservation {
private static var registered = false
Expand Down
2 changes: 1 addition & 1 deletion Tests/SnapshotTestingTests/RecordTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class RecordTests: XCTestCase {
}
} issueMatcher: {
$0.compactDescription == """
failed - The file “testRecordNever.1.json” couldn’t be opened because there is no such file.
failed - No reference was found on disk. New snapshot was not recorded because recording is disabled
"""
}

Expand Down