Skip to content
Closed
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
6 changes: 4 additions & 2 deletions Sources/XCTestHTMLReportCore/Classes/Models/Summary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ public struct Summary {
/// Call-site checks catch failures XCResultKit surfaces as `nil`. They do
/// not catch failures in *nested* decoding, where a parent object still
/// decodes but a child field comes back empty. The observable symptom is an
/// attachment that resolved to no content, so check for that directly.
/// attachment whose referenced payload resolved to no content, so check
/// for that directly. Attachments without a payload reference legitimately
/// have no content and require no resolution.
///
/// Idempotent across sequential calls: repeated calls do not duplicate
/// faults. Dedup keys on `Attachment.faultDescription`, which assumes
Expand All @@ -123,7 +125,7 @@ public struct Summary {
)

for attachment in allAttachments {
guard case .none = attachment.content else {
guard attachment.payloadId != nil, case .none = attachment.content else {
continue
}
let detail = attachment.faultDescription
Expand Down
10 changes: 5 additions & 5 deletions Tests/XCTestHTMLReportTests/CoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ final class CoreTests: XCTestCase {
// because a run still depends on the simulator behaving, and an
// exact split would measure that rather than this project.
//
// 17 = 14 XCTest methods + 3 Swift Testing `@Test` functions in
// SwiftTestingSuite (SampleAppUnitTests target). The 14th is
// FirstSuite.testAttachScreenshot, added by #393 to give the image
// rendering path a fixture.
XCTAssertEqual(all, 17, "One row per test method; fixed by the sample sources")
// 18 = 15 XCTest methods + 3 Swift Testing `@Test` functions in
// SwiftTestingSuite (SampleAppUnitTests target). The latest is
// FirstSuite.testAttachDeletedOnSuccess, whose passing attachment
// retains metadata but has no payload.
XCTAssertEqual(all, 18, "One row per test method; fixed by the sample sources")
XCTAssertEqual(
skipped,
1,
Expand Down
21 changes: 17 additions & 4 deletions Tests/XCTestHTMLReportTests/FaultReportingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class FaultReportingTests: XCTestCase {
XCTAssertEqual(summary.faults, [], "Clean fixture must not produce faults")
}

func testValidateFlagsUnresolvedAttachments() throws {
func testValidateIgnoresPayloadlessAttachments() throws {
let url = try XCTUnwrap(
Bundle.testBundle.url(forResource: "TestResults", withExtension: "xcresult")
)
Expand All @@ -49,14 +49,27 @@ final class FaultReportingTests: XCTestCase {
downsizeScaleFactor: 0.25,
faultCollector: collector
)

let payloadlessAttachments = summary.allAttachments.filter { attachment in
guard attachment.payloadId == nil else {
return false
}
if case .none = attachment.content {
return true
}
return false
}
XCTAssertFalse(
payloadlessAttachments.isEmpty,
"Fixture must contain an attachment whose payload was deleted after a passing test"
)

summary.validate()

// Every attachment the model knows about must have resolved to real
// content. An unresolved one renders as an empty src.
let unresolved = summary.faults.filter { $0.kind == .unresolvedAttachment }
XCTAssertEqual(
unresolved, [],
"Unresolved attachments: \(unresolved.map(\.detail))"
"Payload-less attachments must not be reported as unresolved: \(unresolved.map(\.detail))"
)
}

Expand Down
7 changes: 7 additions & 0 deletions XCTestHTMLReportSampleApp/SampleAppUITests/FirstSuite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ class FirstSuite: XCTestCase {
add(screenshot)
}

func testAttachDeletedOnSuccess() {
let attachment = XCTAttachment(string: "This payload is removed after the test passes")
attachment.name = "Deleted on Success"
attachment.lifetime = .deleteOnSuccess
add(attachment)
}

func testOne() {
XCTContext.runActivity(named: "Text Attachment") { activity in
let logs = """
Expand Down