@@ -708,158 +708,4 @@ public void Constructor_WorksCorrectly_ForPublicProperty()
708708 Assert . NotNull ( subscription ) ;
709709 subscription . Dispose ( ) ;
710710 }
711-
712- [ Fact ]
713- public async Task ComponentRecreation_PreservesPersistedState_WhenComponentIsRecreatedDuringNavigation ( )
714- {
715- // This test simulates the scenario where a component is destroyed and recreated (like during navigation)
716- // and verifies that the persisted state is correctly restored in the new component instance
717-
718- // Arrange
719- var appState = new Dictionary < string , byte [ ] > ( ) ;
720- var manager = new ComponentStatePersistenceManager ( NullLogger < ComponentStatePersistenceManager > . Instance ) ;
721- var serviceProvider = PersistentStateProviderServiceCollectionExtensions . AddSupplyValueFromPersistentComponentStateProvider ( new ServiceCollection ( ) )
722- . AddSingleton ( manager )
723- . AddSingleton ( manager . State )
724- . AddFakeLogging ( )
725- . BuildServiceProvider ( ) ;
726- var renderer = new TestRenderer ( serviceProvider ) ;
727- var provider = ( PersistentStateValueProvider ) renderer . ServiceProviderCascadingValueSuppliers . Single ( ) ;
728- var cascadingParameterInfo = CreateCascadingParameterInfo ( nameof ( TestComponent . State ) , typeof ( string ) ) ;
729-
730- // Setup initial persisted state
731- var component1 = new TestComponent { State = "initial-property-value" } ;
732- var componentId1 = renderer . AssignRootComponentId ( component1 ) ;
733- var componentState1 = renderer . GetComponentState ( component1 ) ;
734- var key = PersistentStateValueProviderKeyResolver . ComputeKey ( componentState1 , nameof ( TestComponent . State ) ) ;
735-
736- appState [ key ] = JsonSerializer . SerializeToUtf8Bytes ( "persisted-value-from-previous-session" , JsonSerializerOptions . Web ) ;
737- await manager . RestoreStateAsync ( new TestStore ( appState ) , RestoreContext . InitialValue ) ;
738-
739- // Act & Assert - First component instance should get the persisted value
740- await renderer . Dispatcher . InvokeAsync ( ( ) => renderer . RenderRootComponentAsync ( componentId1 , ParameterView . Empty ) ) ;
741- Assert . Equal ( "persisted-value-from-previous-session" , component1 . State ) ;
742-
743- // Simulate component destruction (like during navigation away)
744- renderer . RemoveRootComponent ( componentId1 ) ;
745-
746- // Simulate component recreation (like during navigation back) - NEW SUBSCRIPTION CREATED
747- var component2 = new TestComponent { State = "new-component-initial-value" } ;
748- var componentId2 = renderer . AssignRootComponentId ( component2 ) ;
749- var componentState2 = renderer . GetComponentState ( component2 ) ;
750-
751- // Verify the key is the same (important for components without @key)
752- var key2 = PersistentStateValueProviderKeyResolver . ComputeKey ( componentState2 , nameof ( TestComponent . State ) ) ;
753- Assert . Equal ( key , key2 ) ;
754-
755- // The state should still be available for restoration
756- await renderer . Dispatcher . InvokeAsync ( ( ) => renderer . RenderRootComponentAsync ( componentId2 , ParameterView . Empty ) ) ;
757-
758- // Assert - The new component instance should get the same persisted value
759- Assert . Equal ( "persisted-value-from-previous-session" , component2 . State ) ;
760- }
761-
762- [ Fact ]
763- public async Task ComponentRecreation_WithStateUpdates_PreservesCorrectValueTransitionSequence ( )
764- {
765- // This test simulates the full lifecycle with component recreation and state updates
766- // following the pattern from GetOrComputeLastValue_FollowsCorrectValueTransitionSequence
767- // but with subscription recreation between state restorations
768-
769- // Arrange
770- var appState = new Dictionary < string , byte [ ] > ( ) ;
771- var manager = new ComponentStatePersistenceManager ( NullLogger < ComponentStatePersistenceManager > . Instance ) ;
772- var serviceProvider = PersistentStateProviderServiceCollectionExtensions . AddSupplyValueFromPersistentComponentStateProvider ( new ServiceCollection ( ) )
773- . AddSingleton ( manager )
774- . AddSingleton ( manager . State )
775- . AddFakeLogging ( )
776- . BuildServiceProvider ( ) ;
777- var renderer = new TestRenderer ( serviceProvider ) ;
778- var provider = ( PersistentStateValueProvider ) renderer . ServiceProviderCascadingValueSuppliers . Single ( ) ;
779- var cascadingParameterInfo = CreateCascadingParameterInfo ( nameof ( TestComponent . State ) , typeof ( string ) ) ;
780-
781- // First component lifecycle
782- var component1 = new TestComponent { State = "initial-property-value" } ;
783- var componentId1 = renderer . AssignRootComponentId ( component1 ) ;
784- var componentState1 = renderer . GetComponentState ( component1 ) ;
785- var key = PersistentStateValueProviderKeyResolver . ComputeKey ( componentState1 , nameof ( TestComponent . State ) ) ;
786-
787- // Pre-populate with first persisted value
788- appState [ key ] = JsonSerializer . SerializeToUtf8Bytes ( "first-restored-value" , JsonSerializerOptions . Web ) ;
789- await manager . RestoreStateAsync ( new TestStore ( appState ) , RestoreContext . InitialValue ) ;
790-
791- await renderer . Dispatcher . InvokeAsync ( ( ) => renderer . RenderRootComponentAsync ( componentId1 , ParameterView . Empty ) ) ;
792-
793- // Act & Assert - First component gets restored value
794- Assert . Equal ( "first-restored-value" , component1 . State ) ;
795-
796- // Update component property
797- component1 . State = "updated-by-component-1" ;
798- Assert . Equal ( "updated-by-component-1" , provider . GetCurrentValue ( componentState1 , cascadingParameterInfo ) ) ;
799-
800- // Simulate component destruction and recreation (NEW SUBSCRIPTION CREATED)
801- renderer . RemoveRootComponent ( componentId1 ) ;
802-
803- var component2 = new TestComponent { State = "new-component-initial-value" } ;
804- var componentId2 = renderer . AssignRootComponentId ( component2 ) ;
805- var componentState2 = renderer . GetComponentState ( component2 ) ;
806-
807- // Restore state with a different value
808- appState . Clear ( ) ;
809- appState [ key ] = JsonSerializer . SerializeToUtf8Bytes ( "second-restored-value" , JsonSerializerOptions . Web ) ;
810- await manager . RestoreStateAsync ( new TestStore ( appState ) , RestoreContext . ValueUpdate ) ;
811-
812- await renderer . Dispatcher . InvokeAsync ( ( ) => renderer . RenderRootComponentAsync ( componentId2 , ParameterView . Empty ) ) ;
813-
814- // Assert - New component gets the updated restored value
815- Assert . Equal ( "second-restored-value" , component2 . State ) ;
816-
817- // Continue with property updates on the new component
818- component2 . State = "updated-by-component-2" ;
819- Assert . Equal ( "updated-by-component-2" , provider . GetCurrentValue ( componentState2 , cascadingParameterInfo ) ) ;
820- }
821-
822- [ Fact ]
823- public async Task ComponentRecreation_WithSkipNotifications_StillRestoresCorrectly ( )
824- {
825- // This test verifies that the fix works even when skipNotifications is true during component recreation,
826- // which is the core scenario that was broken before our fix
827-
828- // Arrange
829- var appState = new Dictionary < string , byte [ ] > ( ) ;
830- var manager = new ComponentStatePersistenceManager ( NullLogger < ComponentStatePersistenceManager > . Instance ) ;
831- var serviceProvider = PersistentStateProviderServiceCollectionExtensions . AddSupplyValueFromPersistentComponentStateProvider ( new ServiceCollection ( ) )
832- . AddSingleton ( manager )
833- . AddSingleton ( manager . State )
834- . AddFakeLogging ( )
835- . BuildServiceProvider ( ) ;
836- var renderer = new TestRenderer ( serviceProvider ) ;
837- var cascadingParameterInfo = CreateCascadingParameterInfo ( nameof ( TestComponent . State ) , typeof ( string ) ) ;
838-
839- // Setup persisted state
840- var component1 = new TestComponent { State = "component-initial-value" } ;
841- var componentId1 = renderer . AssignRootComponentId ( component1 ) ;
842- var componentState1 = renderer . GetComponentState ( component1 ) ;
843- var key = PersistentStateValueProviderKeyResolver . ComputeKey ( componentState1 , nameof ( TestComponent . State ) ) ;
844-
845- appState [ key ] = JsonSerializer . SerializeToUtf8Bytes ( "persisted-value" , JsonSerializerOptions . Web ) ;
846- await manager . RestoreStateAsync ( new TestStore ( appState ) , RestoreContext . InitialValue ) ;
847-
848- // First component gets the persisted value
849- await renderer . Dispatcher . InvokeAsync ( ( ) => renderer . RenderRootComponentAsync ( componentId1 , ParameterView . Empty ) ) ;
850- Assert . Equal ( "persisted-value" , component1 . State ) ;
851-
852- // Destroy and recreate component (simulating navigation or component without @key)
853- renderer . RemoveRootComponent ( componentId1 ) ;
854-
855- // Create new component instance - this will create a NEW SUBSCRIPTION
856- var component2 = new TestComponent { State = "different-initial-value" } ;
857- var componentId2 = renderer . AssignRootComponentId ( component2 ) ;
858-
859- // Render the new component - this should restore the persisted value even if skipNotifications is true
860- await renderer . Dispatcher . InvokeAsync ( ( ) => renderer . RenderRootComponentAsync ( componentId2 , ParameterView . Empty ) ) ;
861-
862- // Assert - The new component should get the persisted value, not its initial property value
863- Assert . Equal ( "persisted-value" , component2 . State ) ;
864- }
865711}
0 commit comments