swift-snapshot-testing icon indicating copy to clipboard operation
swift-snapshot-testing copied to clipboard

feat(macOS): deterministically snapshot `NSView`s on any device

Open tillhainbach opened this issue 2 years ago • 5 comments

Deterministically snapshot NSViews on any device

Summary

This PR builds upon #412 but maintains compatibility with existing API-behaviour. Additionally to fixing backingScaleFactor issues, it also fixes the color space issues discussed in #477. Therefore all relevant rendering parameters can be set in a deterministic way allowing macOS snapshot test to run on any device including CI.

In Detail

As far as I can tell from experimenting, the rendering of NSView is determined by its .size, .appearance .window.backingScaleFactor, and window.colorSpace. This PR tackles the later two and adds a GenericWindow subclass of NSWindow which can be configured with a specific backingScaleFactor and colorSpace. The .image snapshot strategy on NSView is extended to allow the caller to optionally set a specific NSAppearance and to render the view in a GenericWindow. This window can be configure to use CI compatible values (eg. backingScaleFactor: 1.0 and colorSpace: .genericRGB). There is even a handy preconfigured static instance GenericWindow.ci.

Added Tests

Two tests are added to showcase the CI-compatibility. These are the CI-compatible version of pre-existing macOS NSView tests:

  • testNSViewCICompatible
  • testNSViewWithLayerCICompatible

For passing tests see https://github.com/tillhainbach/swift-snapshot-testing/pull/3

Caveats/Gotchas

The current implementation for .image for NSView has side-effect on the view which are not undone. This means that the calling order for .image and .recursiveDescription strategy matters. I added a note to the doc comment.

Minor Fixes along the way

I noticed some test failures on my local machine that where:

  • related to light/dark mode setting on test machine. I refactor the failing tests to explicitly use .aqua (light mode) appearance (the one used for provided target snapshot)
  • related to number formatting using localised formatting (decimal separator in my case). I changed the number formatter to use the a . as the decimal separator.

Other

This PR adds an additional step to the GitHub actions which uploads any failing snapshot artefacts. This is great for debugging failures on CI.

Related PRs and Issues

  • closes #412
  • fixes issues with #477. Supporting SwiftUI, however, could be simplified to just pullback to NSView.
  • closes #428
  • closes #313
  • closes #305

PS: I left the WIP and intermediate commits to improve comprehensibility for review but will squash them once this PR is approved to reduce the noise.

tillhainbach avatar Nov 06 '21 19:11 tillhainbach

What's the state of this? Is there any plan to getting this merged? Looks like there's no SwiftUI support on macOS yet. With Apple getting serious with SwiftUI on macOS now with Ventura (the new Settings app was written with SwiftUI it looks like), I'd love to see proper support for SwiftUI in this lib as well. Are there any blockers right now?

Jeehut avatar Jun 21 '22 18:06 Jeehut

Are there any plans to get this merged?

For anyone finding and needing this before it is merged, I created a branch in fork which basically combines this PR as well as #477: https://github.com/Obbut/swift-snapshot-testing/tree/updated-swiftui-macos

Obbut avatar Mar 07 '23 13:03 Obbut

If the comments from @stephencelis are blocking to get this merged, I'd be happy to create a new PR with that feedback implemented

Obbut avatar Mar 07 '23 13:03 Obbut

If the comments from @stephencelis are blocking to get this merged, I'd be happy to create a new PR with that feedback implemented

Would be great if you can take over. I was wanting to address this but I can't find the time since I haven't been working on anything swift related 🥲.

tillhainbach avatar Mar 07 '23 19:03 tillhainbach

@Obbut Did you ever get the time to look at this? These look like great changes

brzzdev avatar Oct 23 '23 11:10 brzzdev