Uh oh!
There was an error while loading. Please reload this page.
fix(test-adapter): use destructuring for createScope return value - #176
Conversation
createScope() returns a tuple [Scope, () => Future<void>], but accessing it via index notation (createScope()[0]) was causing runtime issues. Using destructuring (let [rootScope] = createScope()) properly extracts the first element while maintaining type safety. Fixes: thefrontside/inspector#patch
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughWhen no parent adapter exists, initialization now creates a root scope via Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error)
✅ Passed checks (3 passed)
✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
cowboyd
commented
Mar 5, 2026
The main problem I have with this is that it leaks the root test adapter scope, because the I recognize that this is a problem existing, but it would be really nice to fix it. |
taras
commented
Mar 5, 2026
Any ideas on how to solve it? |
jbolda
commented
Mar 5, 2026
Would |
cowboyd
commented
Mar 5, 2026
We need to run destroy when the test adapter is destroyed. In reality it is a small memory leak because it only applies to the top-level test adapter, and we're halting all the child tasks created from it, but it is a loophole through which bigger leaks can get through if we do more stuff with the scope in the future: We just need to make sure that if there is no parent adapter, then we destroy this scope as well. Something like this. *"@@init@@"(){if(scope){returnyield*scope.operation;}scope=withResolvers<Result<Scope>>();letparent: Result<Scope>;letdestroyRoot: (()=>Future<void>)|undefined=undefined;if(adapter.parent){parent=yield*adapter.parent["@@init@@"]();}else{let[rootScope,destroy]=createScope();rootDestroy=destroy;parent=Ok(rootScope);}if(!parent.ok){scope.resolve(parent);returnyield*scope.operation;}lettask=yield*parent.value.spawn(function*(){letinit=yield*box(function*(){for(letinitializerofadapter.setup.all){yield*initializer();}});if(!init.ok){scope?.resolve(init);}else{scope?.resolve(Ok(yield*useScope()));yield*suspend();}});destroy=function*destroy(){if(destroyRoot){yield*destroyRoot();}yield*task.halt();}returnyield*scope.operation;}, |
Apply Charles's recommended fix: capture the destroy function from createScope() and call it during adapter teardown. This prevents the root scope from leaking when the test adapter is destroyed. Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Motivation
The
createScope()function returns a tuple[Scope, () => Future<void>], but accessing it via index notation (createScope()[0]) was causing runtime issues when used in the inspector project. This was discovered via a pnpm patch applied in thefrontside/inspector.Approach
Changed from index access to destructuring assignment:
This properly extracts the first element of the tuple while maintaining type safety. The expanded if/else structure also improves readability.
Summary by CodeRabbit