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

Snapshot is different with what's in simulator window (even with delay)

Open MaximBazarov opened this issue 5 years ago • 6 comments

Hi there, first of thank you for making such an awesome library!

The issue I struggled with is that I can't understand why the snapshot is different from what is on the screen Heres the simulator's: Screen Shot 2020-02-11 at 11 46 52 AM

and here's the snapshot: testExample1 1

the only thing that makes a difference is that update

  DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
            self.contentView.backgroundColor = .red
            self.label.textColor = .yellow
            self.setNeedsDisplay()
            self.setNeedsLayout()
        }

Test


class SnapshotAfterUpdateTests: XCTestCase {
    private var sut = UIStoryboard(
        name: "Main",
        bundle: Bundle(for: ViewController.self)
        ).instantiateInitialViewController()!

    func testExample1() {
        delay(2) // here's a delay
        assertSnapshot(matching: sut, as: .image)
    }
}

func delay(_ second: TimeInterval) {
    let date = Date(timeIntervalSinceNow: second)
    RunLoop.current.run(until: date)
}

full project to reproduce: https://github.com/MaximBazarov/SnapshotAfterUpdate

MaximBazarov avatar Feb 11 '20 10:02 MaximBazarov

Have you tried using the "wait" strategy?

Instead of:

        delay(2) // here's a delay
        assertSnapshot(matching: sut, as: .image)

It would be (I think, no compiler helping here...):

        assertSnapshot(matching: sut, as: .wait(for: 2, on: .image))

Sherlouk avatar Feb 11 '20 12:02 Sherlouk

@Sherlouk thank you for the answer, I couldn't find that strategy though.

what fixed this for me is

sut.view.setNeedsDisplay()
delay(0.1)
assertSnapshot(matching: sut, as: .image)

but doesn't seem to be an elegant solution, also I don't think it's even a snapshot-testing framework problem, because when debug sut is in the state as on a screenshot, so somehow it doesn't get rendered by the time

MaximBazarov avatar Feb 11 '20 13:02 MaximBazarov

I couldn’t find that strategy though

Perhaps you are not on the latest version? Or it hasn’t been released in a tagged build (try using master rather than a version!)

Sherlouk avatar Feb 11 '20 23:02 Sherlouk

@Sherlouk yes, it's in master.

so the result is the same, but doesn't solve the problem alone

func testExample1() {
    sut.view.setNeedsDisplay() // that line has to be here, no idea why yet
    assertSnapshot(matching: sut, as: .wait(for: 2, on: .image))
}

MaximBazarov avatar Feb 12 '20 07:02 MaximBazarov

Not sure if I'm doing something wrong, but even when I use .wait, it only loads the viewController after the specified time interval.

Let's say I start an animation of 0.3 seconds in the viewDidAppear. How can I make the snapshot wait for this 0.3 seconds?

matheusalano avatar Apr 27 '20 14:04 matheusalano

@MaximBazarov I just ran into a similar issue and noticed that asserting using UIViewController will never update. No matter how long you tell the .wait expectation to wait. On the other hand, asserting using UIView works flawlessly. I tried your project and assertSnapshot(matching: sut.view, as: .wait(for: 2, on: .image)) generates the expected screenshot.

@matheusalano you'll find this approach useful as well. Assert the view controller's view using the .wait strategy and you should be fine.

marcosgriselli avatar Dec 01 '20 15:12 marcosgriselli