From 0a029101672aeebf7cece576a42532a94024f324 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Thu, 17 Oct 2024 11:34:09 -0700 Subject: [PATCH] Add failing test cases for `onDismiss` bugs --- .../Internal/AssertEventually.swift | 17 +++++ .../CaseStudiesTests/PresentationTests.swift | 67 ++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/Examples/CaseStudiesTests/Internal/AssertEventually.swift b/Examples/CaseStudiesTests/Internal/AssertEventually.swift index e4c1120b4..c926ca601 100644 --- a/Examples/CaseStudiesTests/Internal/AssertEventually.swift +++ b/Examples/CaseStudiesTests/Internal/AssertEventually.swift @@ -1,6 +1,23 @@ import CustomDump import XCTest +@MainActor +func assertEventually( + _ expression: @autoclosure @escaping @MainActor () -> Bool, + timeout: TimeInterval = 1, + file: StaticString = #file, + line: UInt = #line +) async { + await _assertEventually( + expression(), + condition: { $0 }, + assert: XCTAssertTrue, + timeout: timeout, + file: file, + line: line + ) +} + @MainActor func assertEventuallyEqual( _ expression1: @autoclosure @escaping @MainActor () -> T, diff --git a/Examples/CaseStudiesTests/PresentationTests.swift b/Examples/CaseStudiesTests/PresentationTests.swift index 33b28506a..080d2b368 100644 --- a/Examples/CaseStudiesTests/PresentationTests.swift +++ b/Examples/CaseStudiesTests/PresentationTests.swift @@ -454,6 +454,71 @@ final class PresentationTests: XCTestCase { ) await assertEventuallyNotNil(vc.presentedChild) } + + @MainActor func testOnDismissCalledForInteractiveDismissal() async throws { + let vc = BasicViewController() + try await setUp(controller: vc) + + await assertEventuallyNil(vc.presentedViewController) + + withUITransaction(\.uiKit.disablesAnimations, true) { + vc.model.isPresented = true + } + await assertEventuallyNotNil(vc.presentedViewController) + await assertEventuallyEqual(vc.isPresenting, true) + + vc.presentedViewController!.dismiss(animated: false) + await assertEventuallyNil(vc.presentedViewController) + await assertEventuallyEqual(vc.isPresenting, false) + } + + @Observable + fileprivate final class Destinations: Identifiable { + @CasePathable + enum Destination { + case presentedA + case presentedB + } + var destination: Destination? + } + @MainActor func testOnDismissNotCalledForUnrelatedDismissal() async throws { + class A: ViewController {} + class B: ViewController {} + class VC: ViewController { + @UIBindable var model = Destinations() + var onDismissA: (() -> Void)? + var onDismissB: (() -> Void)? + override func viewDidLoad() { + super.viewDidLoad() + present(isPresented: UIBinding($model.destination.presentedA)) { [weak self] in + self?.onDismissA?() + } content: { + A() + } + present(isPresented: UIBinding($model.destination.presentedB)) { [weak self] in + self?.onDismissB?() + } content: { + B() + } + } + } + let vc = VC() + vc.onDismissB = { XCTFail() } + try await setUp(controller: vc) + + await assertEventuallyNil(vc.presentedViewController) + + withUITransaction(\.uiKit.disablesAnimations, true) { + vc.model.destination = .presentedA + } + await assertEventually(vc.presentedViewController is A) + + withUITransaction(\.uiKit.disablesAnimations, true) { + vc.model.destination = .presentedB + } + await assertEventually(vc.presentedViewController is B) + vc.onDismissB = nil + } } @Observable @@ -492,7 +557,7 @@ private class ViewController: UIViewController { private class BasicViewController: UIViewController { @UIBindable var model: Model - var isPresenting = false + private(set) var isPresenting = false init(model: Model = Model()) { self.model = model super.init(nibName: nil, bundle: nil)