-
-
Notifications
You must be signed in to change notification settings - Fork 779
Description
Is your feature request related to a problem? Please describe.
I'm always frustrated when I have to remember to call sinon.restore() in test cleanup or risk memory leaks and test pollution. The current approach requires explicit cleanup in afterEach hooks or manual restoration, which is error-prone and leads to boilerplate code. With modern JavaScript's Explicit Resource Management (using/await using), we could leverage automatic cleanup at block scope end, making sandboxes potentially unnecessary for many use cases.
Describe the solution you'd like
I want all sinon primitives (spies, stubs, fakes, mocks, and sandboxes) to implement the Symbol.dispose method by default, enabling automatic cleanup when used with the using declaration. The disposal behavior should:
- Individual objects: Dispose only the specific spy/stub/fake/mock (equivalent to calling
.restore()on that instance) - Sandbox objects: Dispose all sinon objects within that sandbox (equivalent to calling
sandbox.restore()) - Multiple disposal calls: Be no-ops after the first call (idempotent behavior)
- Backward compatibility: No breaking changes - existing code works unchanged,
usingkeyword provides opt-in automatic cleanup
Example usage:
test('my test', function () {
using myFake = sinon.replace(ob, 'method', sinon.fake());
using mySpy = sinon.spy(obj, 'method');
using sandbox = sinon.createSandbox();
using stubFromSandbox = sandbox.stub(obj, 'otherMethod');
doSomething();
sinon.assert.called(myFake);
// All objects automatically restored when leaving scope
// sandbox disposal would also clean up stubFromSandbox
});Describe alternatives you've considered
- Manual
sinon.restore()calls inafterEachhooks (current approach - verbose and error-prone) - Wrapper functions that return disposable objects (would require maintaining separate wrapper library)
- Using try/finally blocks with manual cleanup (adds nesting and complexity)
- Test framework-specific plugins (not portable across different test runners)
- Custom DisposableStack implementations (more verbose than native
usingsyntax)
Additional context
This feature would leverage the TC39 Explicit Resource Management proposal (Stage 3) which is already supported in TypeScript 5.2+ and modern JavaScript engines. The implementation would require adding [Symbol.dispose]() { this.restore(); } to relevant prototypes, with idempotent behavior to handle multiple disposal calls gracefully.
This approach could make sandboxes less necessary for many use cases, as individual using declarations provide the same automatic cleanup benefits with more granular control. It would make sinon more ergonomic and significantly reduce the likelihood of test pollution due to forgotten cleanup.