pointfreeco / swift-snapshot-testing

📸 Delightful Swift snapshot testing.
https://www.pointfree.co/episodes/ep41-a-tour-of-snapshot-testing
MIT License
3.74k stars 570 forks source link

UIViewRepresentable that wraps a TextKit 1 UITextView gives a blank snapshot. #871

Closed pixlwave closed 2 months ago

pixlwave commented 2 months ago

Describe the bug Hi, I'm attempting to update our project from Xcode 15.2 to Xcode 15.4 and have hit a weird bug in our snapshot tests:

We have a custom SwiftUI text view that wraps a UITextView that's using the old TextKit 1 layout engine for various custom layout needs. With Xcode 15.4, when the height of this view exceeds a certain threshold (~5 lines of body text), then the text is no longer visible in any snapshots. All of our snapshots are generated from Xcode Previews which don't exhibit this behaviour so it appears to only be an issue with the snapshotting.

Allowing the text view to use TextKit 2 by initialising with usingTextLayoutManager: true fixes the snapshots but sadly isn't a viable option for us at this time.

To Reproduce A minimal reproduction case looks like so:

import SwiftUI

struct CustomText: UIViewRepresentable {
    let attributedString: AttributedString

    func makeUIView(context: Context) -> UITextView {
        // Need to use TextKit 1 for mentions
        let textView = UITextView(usingTextLayoutManager: false)
        textView.attributedText = NSAttributedString(attributedString)
        return textView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.attributedText = NSAttributedString(attributedString)
    }

    func sizeThatFits(_ proposal: ProposedViewSize, uiView: UITextView, context: Context) -> CGSize? {
        let proposalWidth = proposal.width ?? UIView.layoutFittingExpandedSize.width
        return uiView.sizeThatFits(CGSize(width: proposalWidth, height: UIView.layoutFittingCompressedSize.height))
    }
}

// MARK: - Previews

struct CustomText_Previews: PreviewProvider {
    static var previews: some View {
        CustomText(attributedString: makeBasicAttributedString())
            .border(Color.purple)
    }

    static func makeBasicAttributedString() -> AttributedString {
        let string = "This is a list\n• One\n• Two\n• Three\n• Four\n• Five\n• Six\n• Seven\n• Eight\n• Nine\n• And number 10\nThat was a list"
        let attributedString = NSAttributedString(string: string)

        return AttributedString(attributedString)
    }
}
import SnapshotTesting
import XCTest
@testable import TextKitSnapshots

final class TextKitSnapshotsTests: XCTestCase {
    func testSnapshot() throws {
        let view = CustomText_Previews.previews
            .frame(width: 390, height: 844)
        assertSnapshot(of: view, as: .image)
    }
}

Expected behavior The snapshots should continue to render as they do when generated by Xcode 15.2.

Screenshots Xcode 15.2 (iOS 17.2 Simulator) Xcode 15.4 (iOS 17.5 Simulator)
Xcode 15 2 Xcode15 4

Environment

Additional context Sample Xcode project: TextKitSnapshots.zip

mbrandonw commented 2 months ago

Hi @pixlwave, something in Xcode/iOS must have changed this, but I don't think it's really a bug per se with the library. For these kinds of open ended questions I think discussions are better, so I am going to move this over to the discussions tab of the repo. Perhaps someone can help you figure it out over there!