diff --git a/CHANGELOG.md b/CHANGELOG.md index f258c5a..94e27fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [3.0.6](https://github.com/Workiva/w_module/compare/3.0.5...3.0.6) + +_March 4, 2024_ + +- **Bug Fix:** A child module which loads during the unload of the parent + may cause BadState exceptions. + ## [3.0.0](https://github.com/Workiva/w_module/compare/2.0.5...3.0.0) _August 18, 2023_ diff --git a/lib/src/lifecycle_module.dart b/lib/src/lifecycle_module.dart index 217e7c9..b383829 100644 --- a/lib/src/lifecycle_module.dart +++ b/lib/src/lifecycle_module.dart @@ -507,6 +507,14 @@ abstract class LifecycleModule extends SimpleModule with Disposable { final completer = Completer(); onWillLoadChildModule(childModule).then((_) async { + // It is possible to reach this point due to the asynchrony of onWillLoadChildModule. + // In that case, simply do not load the child module and instead dispose it. + if (isUnloaded || isUnloading) { + await childModule.dispose(); + completer.complete(); + return; + } + _willLoadChildModuleController.add(childModule); final childModuleWillUnloadSub = listenToStream( diff --git a/test/lifecycle_module_test.dart b/test/lifecycle_module_test.dart index a819918..55e4f40 100644 --- a/test/lifecycle_module_test.dart +++ b/test/lifecycle_module_test.dart @@ -1756,6 +1756,29 @@ void runTests(bool runSpanTests) { childModule.eventList, equals(['willLoad', 'onLoad', 'didLoad'])); }); + test('followed by parent unload causes child to dispose and never load', + () async { + parentModule.eventList?.clear(); + final load = parentModule.loadChildModule(childModule); + + await parentModule.unload(); + await load; + + expect( + parentModule.eventList, + equals([ + 'onWillLoadChildModule', + 'onShouldUnload', + 'willUnload', + 'onUnload', + 'didUnload', + 'onDispose' + ]), + ); + + expect(childModule.eventList, equals(['onDispose'])); + }); + test('should emit lifecycle log events', () async { expect( Logger.root.onRecord,