Code Monkey home page Code Monkey logo

Comments (7)

mbrandonw avatar mbrandonw commented on July 30, 2024 3

Hey! Thanks for giving the library a spin! We're in the process of creating a full set of docs for it, so hopefully things will be clearer once we have that. Until then, here's some info:

It's not necessary to use the DefaultSnapshottable protocol, in fact it's not really encouraged. It's just a small bit of convenience we wanted to provide until people got used to the API, but we may even deprecate it in the future.

The best way to consume the API is to use the assertSnapshot(matching:as:) overload, which takes the value you want to snapshot as the first argument, and an explicit Strategy value for the second argument (this is the value that is defaulted via the DefaultSnapshottable protocol). The strategy type is the thing that holds all the logic for snapshotting values and turning values into data that can be diffed and serialized to disk. It has two generics, Strategy<Snapshottable, Format>, where Snapshottable is the type you want to snapshot, and Format is the diffable format you want to snapshot into. The library comes with a bunch of strategies that can be used out of the box.

However, we don't currently have a strategy for NSAttributedString, so let's look at that as an example. If you want to snapshot an attributed string as an image, then you ultimately want to construct a Strategy<NSAttributedString, UIImage> (assuming we are running this test on iOS). Now you can technically create a value of this type from scratch, but it would be a lot of work. The cool thing is that there's an operation on strategies called pullback that lets you take existing strategies and pull them back to completely different types along a transformation.

In particular, we can take the Strategy<UIView, UIImage>.image strategy that ships with this library for snapshotting UIViews into UIImages, and pull it back to be able to snapshot attributed strings as images:

extension Strategy where Snapshottable == NSAttributedString, Format == UIImage {
  public static var image: Strategy {
    return Strategy<UIView, UIImage>.image.pullback { string in
      let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 200))
      label.attributedText = string
      return label
    }
  }
}

All this does is create a label, put the attributed string in it, and then return the label. Then the .image strategy on UIView takes care of the rest.

Once you have that strategy at your disposal, snapshotting an attributed string in your test is as easy as:

import SnapshotTesting

class MyTest: XCTestCase {
  func testAttributedString() {
    let string = /* do something to create an attributed string */

    assertSnapshot(matching: string, as: .image)
  }
}

This will now generate an image representation of your attributed string and use that for testing!

Now currently the image static we created above explicitly sets the bounds of the label to 300x200. You may want to be able to customize that. That's also easy to do, you just use a static func that takes some configuration up front and uses it in the pullback. For example, this is what we do for a .image strategy that takes an explicit size, but I'll leave that to you to explore.

But, now here is where things can get really interesting. You can also snapshot NSAttributedString as text, not just an image. For example, you can use the .dump strategy to get the contents of the string as raw text representation using the dump function:

assertSnapshot(matching: string, as: .dump)

This would save a txt file to your __Snapshots__ directory with something that looks like this:

- Hello{
    NSColor = "UIExtendedSRGBColorSpace 0 0 1 1";
    NSFont = "<UICTFont> font-family: \".SFUIDisplay-Semibold\"; font-weight: bold; font-style: normal; font-size: 20.00pt";
}

which shows you how attributes are applied to every span of text in your string. It may be easier to understand regressions in this format, because if a snapshot fails you will get a nicely formatted diff like this:

 - Hello{
     NSColor = "UIExtendedSRGBColorSpace 0 0 1 1";
-    NSFont = "<UICTFont> font-family: \".SFUIDisplay-Semibold\"; font-weight: bold; font-style: normal; font-size: 20.00pt";
+    NSFont = "<UICTFont> font-family: \".SFUIText-Semibold\"; font-weight: bold; font-style: normal; font-size: 18.00pt";
 }

Even cooler, you can also use an NSAttributedString API for converting a string into HTML, and snapshot that:

extension Strategy where Snapshottable == NSAttributedString, Format == String {
  public static var html: Strategy {
    var strategy: Strategy = Strategy<String, String>.lines.pullback { string in
      let htmlData = try! string.data(
        from: NSRange(location: 0, length: string.length),
        documentAttributes: [.documentType: NSAttributedString.DocumentType.html]
      )
      return String(data: htmlData, encoding: .utf8)!
    }
    strategy.pathExtension = "html"
    return strategy
  }
}

assertSnapshot(matching: string, as: .html)

You may like the output of that snapshot a lil better than the .dump.

But the main point is that you create lots of different snapshot strategies for your types, and you can snapshot a single value in multiple ways. It's really powerful! We will probably even add these strategies to this library soon (PR's welcome if you want to give it a shot).

Sorry for the long reply, but this was helpful for me to get out as I write documentation. Let me know if anything was confusing so that I can improve the documentation as I go.

from swift-snapshot-testing.

loudmouth avatar loudmouth commented on July 30, 2024

After doing some digging, I realize that implementing conformance might be tricky, and not something I have time for at the moment. I think conformance for NSAttributedString would be sufficient for my own use-case and if #52 is to be seen as a feature roadmap, it looks like it will be done in the future. If #52 is the feature roadmap, feel free to close this issue

from swift-snapshot-testing.

mbrandonw avatar mbrandonw commented on July 30, 2024

After doing some digging, I realize that implementing conformance might be tricky, and not something I have time for at the moment. I think conformance for NSAttributedString would be sufficient for my own use-case and if #52 is to be seen as a feature roadmap, it looks like it will be done in the future. If #52 is the feature roadmap, feel free to close this issue

Yeah attributed strings are definitely on our roadmap. The code I posted above is essentially what we'll be adding to the library, but right now we are heads down for the next week to get the 1.0 release of this library ready. We will get to it soon after that, or if you wanted to give it a shot that'd be great too!

from swift-snapshot-testing.

loudmouth avatar loudmouth commented on July 30, 2024

Wowzas, thanks for the ultra-comprehensive response.

Since I'm rendering to an NSAttributedString with custom attributes, i.e. attributes that are not native, but implemented by me, it turns out that using the .dump strategy is perfect. It gives me the ability to snapshot all the attributes at each respective range of characters.

I'm going to close this for now, as this issue was more of a forum-style question/answer.

Keep up the good work with this lib and thanks for the help!

from swift-snapshot-testing.

mbrandonw avatar mbrandonw commented on July 30, 2024

@loudmouth that's great to hear! we would love to see how you end up using this if it's open source.

from swift-snapshot-testing.

loudmouth avatar loudmouth commented on July 30, 2024

Well it is open-source ;-)

here is the test code from my PR.

and here is an example snapshot of a view.

Now, the one thing I don't understand is why my test target renders the view differently than when the view is rendered in the main target, but I think that issue is something to do with my heavy usage of TextKit and not your library

As a last sidenote, I have been a fan of KIF since I first found out about it and I think it pairs nicely with snapshot testing as you can easily "wait" until views with the relevant accessibility identifiers are displayed. You can see usage of that in my PR.

from swift-snapshot-testing.

AgapovOne avatar AgapovOne commented on July 30, 2024

Current possible way of adding snapshotting support for NSAttributedString:

extension Snapshotting where Value == NSAttributedString, Format == UIImage {
    public static var image: Snapshotting {
        Snapshotting<UIView, UIImage>.image.pullback { (attributedString: NSAttributedString) in
            let textView = UITextView()
            textView.attributedText = attributedString
            return textView
        }
    }
}

from swift-snapshot-testing.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.