Comments (7)
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 UIView
s into UIImage
s, 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.
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.
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.
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.
@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.
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.
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)
- Undefined symbols Linker command failed with exit code 1. HOT 1
- Snapshot adds imported module's name that fails match with reference shapshot
- Deadlock in inline snapshot testing HOT 4
- What's the way to use `assertSnapshot` in async test? HOT 3
- How to snapshot on special iOS version? HOT 1
- Optimizing Image Handling in Swift Snapshot Testing
- Snapshot of table view with combine receiver happens too late HOT 1
- swift-syntax 510.0.0 update not possible HOT 1
- How to generate iPhone 15 Snapshots with Xcode 15, as view.swift doesn't contain those dimensions HOT 1
- I get "Process completed with exit code 65" when I use "assertSnapshot(of: vc, as: .image)" function on GitHub Actions.
- `diffTool` have a Swift 6 warning on Xcode 15.3 with Strict Concurrency Checking set to Complete HOT 3
- Privacy manifest for AppStore releases HOT 1
- "The file “...” couldn’t be opened because you don’t have permission to view it" after switching branch
- Privacy manifest file / Privacy Rules HOT 1
- Blank diff snapshot
- Use keyboardLayoutGuide HOT 1
- 1.17.0 doesn't compile on Xcode 16 Beta 3 HOT 1
- UIViewRepresentable that wraps a TextKit 1 UITextView gives a blank snapshot. HOT 1
- Crash `Current context must not be nil` in `recordSnapshot` HOT 4
- swift 6 build fails due to Snapshotting not conforming to sendable HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swift-snapshot-testing.