pointfreeco / swift-snapshot-testing

📸 Delightful Swift snapshot testing.
https://www.pointfree.co/episodes/ep41-a-tour-of-snapshot-testing
MIT License
3.78k stars 580 forks source link

wait strategy not working. #717

Open marcelderkskarlmax opened 1 year ago

marcelderkskarlmax commented 1 year ago

Thanks for the good work. I really like the approach of snapshot testing and therefor I am a bit disappointed, that I am currently stuck at this place.

I am using the library like this

        let sutVC = IndexViewController()
        let sutViewModel = IndexViewModelImpl(
        coordinator: nil,
         categoryFilter: mockCategoryFilter,
            rootCategory: nil,
            initialSearch: nil)

        sutViewModel.loader = { completion in
            completion(true, categories, nil)
        }
        sutVC.viewModel = sutViewModel
        sutVC.beginAppearanceTransition(true, animated: false)
        sutVC.endAppearanceTransition()
        assertSnapshot(matching: sutVC, as: .wait(for: 5.0, on: .image(on: .iPhone13)))

I would expect, that the ViewController is loaded, and going through its normal lifecycle where I am doing further configuration of the view. Then after 5 seconds, the test would take the snapshot.

Instead, the 5 seconds wait time will happen before the view controller is loaded. The simulator screen stays black for 5 seconds. After that that view controller is loaded and doing its lifecycle.

Is there any other way to delay a snapshot, or do I get something wrong here ?

I already had a look for this in the issues board.

Testing for

assertSnapshot(matching: sutVC.view, as: .wait(for: 5, on: .image))

instead of the ViewController directly didn't help in my case.

Also as you can see I tried to mock some components already away, like network request, local data filters and so on. I could mock the whole view model, but I was hoping, that I can test the ViewController with its ViewModel as a pair.

Nevertheless I think the .wait strategy is not working as expected and some kind of Snapshot delaying would be helpful.

Thanks for your input :-)

markst commented 1 year ago

Noticed this yesterday, where by I was trying to make a long screenshot of my collection view which each had cell's loading remote images.

Now I'd never use remote images in real tests, I'm using a local Swift packages for my test assets which return local urls. (happy to share)

@marcelderkskarlmax my solution was to create a UIWindow and display the view controller prior to snapshotting with wait time.

However I have noticed even using local assets, the images sometimes fail to complete their loading. So it would be good if we could improve this library to somehow add a delay between the window display and rending to png's.

321 seems to be relevant here.

extension HomeSnapshotTests {
  func testHomeSnapshot() {
    let vc = HomeViewController(
      layoutProvider: MainLayoutProvider(),
      presenter: store
    )
    vc.loadViewIfNeeded()
    vc.view.frame = .init(x: 0, y: 0, width: 600, height: 10000)

    let window = UIWindow(frame: .init(x: 0, y: 0, width: 600, height: 10000))
    window.rootViewController = vc
    window.makeKeyAndVisible()

    snapshotOnDevice(
      matching: vc,
      record: true,
      wait: 10,
      config: .iPhone12,
      size: .init(width: 600, height: 10000)
    )
  }
markst commented 1 year ago

I guess the delay needs to be between the prepareView & renderer closure: https://github.com/pointfreeco/swift-snapshot-testing/blob/main/Sources/SnapshotTesting/Common/View.swift#L966

markst commented 1 year ago

Might be somewhat similar to #173