@@ -2657,6 +2657,41 @@ final class PresentationReducerTests: BaseTCATestCase {
26572657 // XCTAssertNil(store.alert)
26582658 // }
26592659 #endif
2660+
2661+ @MainActor
2662+ func testPresentation_dismissWorksAfterParentEnumTransition( ) async {
2663+ let scheduler = DispatchQueue . test
2664+ let store = TestStore ( initialState: EnumTransitionParent . State. online ( . init( ) ) ) {
2665+ EnumTransitionParent ( )
2666+ } withDependencies: {
2667+ $0. mainQueue = scheduler. eraseToAnyScheduler ( )
2668+ }
2669+
2670+ // Present modal in .online state
2671+ await store. send ( . online( . presentModal) ) {
2672+ $0. online? . modal = . init( )
2673+ }
2674+
2675+ // Start timer that will dismiss
2676+ await store. send ( . online( . modal( . presented( . startTimer) ) ) )
2677+
2678+ // Transition to .offline (timer cancelled, modal stays presented)
2679+ await store. send ( . setOnline( false ) ) {
2680+ $0 = . offline( $0. online ?? . init( ) )
2681+ }
2682+
2683+ // Transition back to .online (modal still presented, timer restarts)
2684+ await store. send ( . setOnline( true ) ) {
2685+ $0 = . online( $0. offline ?? . init( ) )
2686+ }
2687+ await store. send ( . online( . modal( . presented( . startTimer) ) ) )
2688+
2689+ // Timer completes and dismiss should work
2690+ await scheduler. advance ( by: . milliseconds( 100 ) )
2691+ await store. receive ( \. online. modal. dismiss) {
2692+ $0. online? . modal = nil
2693+ }
2694+ }
26602695}
26612696
26622697@Reducer
@@ -2687,3 +2722,112 @@ private struct NestedDismissFeature {
26872722 }
26882723 }
26892724}
2725+
2726+ @Reducer
2727+ private struct EnumTransitionModal {
2728+ struct State : Equatable { }
2729+ enum Action {
2730+ case startTimer
2731+ }
2732+ @Dependency ( \. dismiss) var dismiss
2733+ @Dependency ( \. mainQueue) var mainQueue
2734+
2735+ var body : some Reducer < State , Action > {
2736+ Reduce { state, action in
2737+ switch action {
2738+ case . startTimer:
2739+ return . run { _ in
2740+ try await mainQueue. sleep ( for: . milliseconds( 100 ) )
2741+ await dismiss ( )
2742+ }
2743+ }
2744+ }
2745+ }
2746+ }
2747+
2748+ @Reducer
2749+ private struct EnumTransitionChild {
2750+ struct State : Equatable {
2751+ @PresentationState var modal : EnumTransitionModal . State ?
2752+ }
2753+ enum Action {
2754+ case presentModal
2755+ case modal( PresentationAction < EnumTransitionModal . Action > )
2756+ }
2757+ var body : some Reducer < State , Action > {
2758+ Reduce { state, action in
2759+ switch action {
2760+ case . presentModal:
2761+ state. modal = . init( )
2762+ return . none
2763+ case . modal:
2764+ return . none
2765+ }
2766+ }
2767+ . ifLet ( \. $modal, action: \. modal) {
2768+ EnumTransitionModal ( )
2769+ }
2770+ }
2771+ }
2772+
2773+ @Reducer
2774+ private struct EnumTransitionParent {
2775+ @ObservableState
2776+ enum State : Equatable {
2777+ case online( EnumTransitionChild . State )
2778+ case offline( EnumTransitionChild . State )
2779+
2780+ var online : EnumTransitionChild . State ? {
2781+ get {
2782+ guard case let . online( state) = self else { return nil }
2783+ return state
2784+ }
2785+ set {
2786+ guard let newValue else { return }
2787+ self = . online( newValue)
2788+ }
2789+ }
2790+
2791+ var offline : EnumTransitionChild . State ? {
2792+ get {
2793+ guard case let . offline( state) = self else { return nil }
2794+ return state
2795+ }
2796+ set {
2797+ guard let newValue else { return }
2798+ self = . offline( newValue)
2799+ }
2800+ }
2801+ }
2802+
2803+ enum Action {
2804+ case setOnline( Bool )
2805+ case online( EnumTransitionChild . Action )
2806+ case offline( EnumTransitionChild . Action )
2807+ }
2808+
2809+ var body : some Reducer < State , Action > {
2810+ Reduce { state, action in
2811+ switch action {
2812+ case . setOnline( true ) :
2813+ if case let . offline( offlineState) = state {
2814+ state = . online( offlineState)
2815+ }
2816+ return . none
2817+ case . setOnline( false ) :
2818+ if case let . online( onlineState) = state {
2819+ state = . offline( onlineState)
2820+ }
2821+ return . none
2822+ default :
2823+ return . none
2824+ }
2825+ }
2826+ . ifCaseLet ( \. online, action: \. online) {
2827+ EnumTransitionChild ( )
2828+ }
2829+ . ifCaseLet ( \. offline, action: \. offline) {
2830+ EmptyReducer ( )
2831+ }
2832+ }
2833+ }
0 commit comments