Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(macOS): deterministically snapshot NSViews on any device #533

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

tillhainbach
Copy link

@tillhainbach tillhainbach commented Nov 6, 2021

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 tillhainbach#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

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.

@Jeehut
Copy link

Jeehut commented Jun 21, 2022

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?

Copy link
Member

@stephencelis stephencelis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good! Thanks for PRing and sorry for the long overdue review.

I've rebased things and gotten CI building again (we want to run against a matrix of Xcode versions, so it'll just be less reliable for now).

perceptualPrecision: Float = 1,
size: CGSize? = nil,
appearance: NSAppearance? = NSAppearance(named: .aqua),
windowForDrawing: GenericWindow? = nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions about this.

  • Any reason why this is nil by default and not a GenericWindow() that produces more deterministic snapshots? Is it just to keep compatibility with existing snaps? We're prepping a release soon that has other bug fixes that may break some existing snapshots, so we are OK making it quite clear in the release notes that upon upgrading, folks should regenerate and audit their snapshot suites.
  • Is it possible to make GenericWindow a private concern of the library and instead introduce options for backingScaleFactor and colorSpace? Would we be missing out on other options?
  • Alternately, could this be a more generic NSWindow and then we could default it to be the deterministic 2x scale and RGB color space?

@Obbut
Copy link

Obbut commented Mar 7, 2023

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
Copy link

Obbut commented Mar 7, 2023

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

@tillhainbach
Copy link
Author

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 🥲.

@brzzdev
Copy link

brzzdev commented Oct 23, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants