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

Parameterizing `scale` of image strategies

Open nevillco opened this issue 5 years ago • 7 comments

I'm really enjoying adding Snapshot testing to a side project of mine. So far I just have a dozen or so, all of the form: assertSnapshot(matching: vc, as: .image(on: .iPhoneX)), so I was surprised when I found all of my tests failing because I had switched the target device that was running the tests, as I would not expect the fact that my tests are running on an iPhone 8 to matter for a snapshot specifying iPhone X. The source is:

public static func image(precision: Float) -> Diffing {
    return Diffing(
        toData: { $0.pngData()! },
        fromData: { UIImage(data: $0, scale: UIScreen.main.scale)! }
        ...
    )
}

I would suggest updating the function signature to public static func image(precision: Float, scale: CGFloat = UIScreen.main.scale) -> Diffing, and allow ViewImageConfigs such as iPhoneX to pass their native scale. Happy to open a PR - I just wanted to open an issue first to see if this is a change you agree with, since it would in theory break consumers' tests that already have snapshots recorded at the wrong device scale.

nevillco avatar Jul 28 '19 00:07 nevillco

+1 I've run into the same unexpected issue with switching sims.

proxi avatar Sep 26 '19 07:09 proxi

From the README: ⚠️ Warning: Snapshots must be compared using a simulator with the same OS, device gamut, and scale as the simulator that originally took the reference to avoid discrepancies between images.

hollanderbart avatar Sep 26 '19 08:09 hollanderbart

True that, I was aware of this, but if scale could be overriden, just like nevillco said, so that on: device would run in device's native scale, overriding it would be a more sane choice. It seems like (on: iPhoneX) producing an image not matching iPhoneX scale is never a desired behaviour.

If it's not possible to override scale, perhaps trying to use device config of different scale than current device should fail?

proxi avatar Sep 26 '19 08:09 proxi

Better yet, have an option to override scale or use simulator scale. e.g. assertSnapshot(...., overrideScale: true) With the list of devices, we could provide the scale variable

hollanderbart avatar Sep 26 '19 08:09 hollanderbart

any updates here or a PR? Happy to help if needed, but I think this would be a very good addition.

graemerycyk avatar Mar 16 '20 15:03 graemerycyk

Seems like parametrizing scale wouldn't work either. I tried that and rendering of same fonts is still slightly different between 2x and 3x devices. Seems like it is because rasterizing of fonts is slightly different in two cases. I guess it is controlled by the selected simulator's runtime, either for 2x or 3x simulator and I didn't find a way to parametrize that in UIGraphicsImageRenderer which is doing the actual rendering of a layer into UIImage.

What would probably work in this case is rendering views' layers into a UIGraphicsPDFRenderer instead because it doesn't rasterize font while creating PDF. But then we have to support PDF diffing for that. UPD: doesn't work with UIGraphicsPDFRenderer too, because texts are also rasterized in PDF

kirillsh avatar Apr 09 '20 10:04 kirillsh

hey @kirillsh, did you have any progress on it? I’m using the last release where it’s possible to pass the scale to create the images, but I’m facing the same issues you pointed here, since the images are scaled correctly, but when it has any text in it there are some diffs on the fonts when testing devices with a different scale. I played with some options, mainly on the properties regarding to fonts inside CGContext, but without success

roveabruno avatar May 25 '21 06:05 roveabruno