add support for Explicit Resource Management to mocked functions#14895
add support for Explicit Resource Management to mocked functions#14895SimenB merged 15 commits intojestjs:mainfrom
Conversation
✅ Deploy Preview for jestjs ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
| if (!Symbol.dispose) { | ||
| Object.defineProperty(Symbol, 'dispose', { | ||
| get() { | ||
| return Symbol.for('nodejs.dispose'); |
There was a problem hiding this comment.
This is a bit weird, and the result of #14888 - usually, it should be possible to polyfill Symbol.dispose in any possible way, e.g. by doing Symbol.dispose ??= Symbol.for('dispose'), but because of #14888 it needs to explicitly be polyfilled with Symbol.for('nodejs.dispose').
I'm not sure if that change over there was a good idea, especially because that polyfill doesn't seem to be available in all scopes (that's why we need to polyfill here in the first place).
There was a problem hiding this comment.
I think that also explains the failing node16 tests.
There was a problem hiding this comment.
that's what the symbol is in a nodejs app, tho. so why would it be an issue?
But if we instead move the test to an e2e test as mentioned elsewhere, then we could just skip that tests on node versions which don't support it
There was a problem hiding this comment.
It was a bit irritating to me first because jest picks up Symbol.dispose as Symbol.for('nodejs.dispose'), while in the test itself was undefined, so it needed to be polyfilled to the same value (while in a normal application, you can polyfill it as pretty much anything and don't need to match the "outside runtime").
But I guess it makes sense that jest itself might see something different than the JestEnvironment itself.
| using mockedLog = jest.spyOn(console, 'log'); | ||
| expect(jest.isMockFunction(console.log)).toBeTruthy(); | ||
|
|
||
| console.log('test'); | ||
| expect(mockedLog).toHaveBeenCalled(); | ||
| } | ||
| expect(jest.isMockFunction(console.log)).toBeFalsy(); |
There was a problem hiding this comment.
This is a common usage:
using mockedLog = jest.spyOn(console, 'log'); is only mocked inside of the current scope, and as soon as the block is left, the mock is restored.
|
Generally, I don't really know what to make of these node16 failures, so I'd be happy for any feedback. As this feature is not available there, is it sensible to skip the tests there? |
Yes. Usually tests are skipped, if some feature is not supported. The jest/packages/test-utils/src/ConditionalTest.ts Lines 33 to 35 in 8bbe2a3 It would be good to mention the feature in documentation. That is a good place to clear out the requirements like Node.js or TypeScript versions. |
SimenB
left a comment
There was a problem hiding this comment.
super exciting stuff!
can you add a changelog entry as well?
tsconfig.json
Outdated
| "declaration": true, | ||
| "emitDeclarationOnly": true, | ||
| "stripInternal": true, | ||
| "lib": ["es2021", "ESNext.Disposable"], |
There was a problem hiding this comment.
do we need this with the inline <reference lib="ESNext.Disposable" />?
| using mockedLog = jest.spyOn(console, 'log'); | ||
| expect(jest.isMockFunction(console.log)).toBeTruthy(); | ||
|
|
||
| console.log('test'); | ||
| expect(mockedLog).toHaveBeenCalled(); | ||
| } | ||
| expect(jest.isMockFunction(console.log)).toBeFalsy(); |
phryneas
left a comment
There was a problem hiding this comment.
I moved the tests into an integration test - I think code-wise it's as clean as I can get it at this point.
I'll take another look at the docs.
|
I've also added some docs. I hope the place works, and if you have any suggestions for better examples, I'm very open to feedback. Good docs examples are not my biggest strength :) |
SimenB
left a comment
There was a problem hiding this comment.
thanks!
we're missing a file to actually run the new E2E test - but I'll fix that up myself 🙂
| const globalSymbol = global.Symbol as unknown as SymbolConstructor; | ||
| // @ts-expect-error - it's readonly - but we have checked above that it's not there | ||
| globalSymbol.asyncDispose = globalSymbol('nodejs.asyncDispose'); | ||
| globalSymbol.asyncDispose = globalSymbol.for('nodejs.asyncDispose'); |
|
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
This fixes #14294
Spied-on functions can now be instantiated with
usinginstead ofconstand they will be restored once the current scope is left.Test plan
I added a
test toan integration test.jest-mock