swc: `Cannot redefine property` error when using `jest.spyOn` after v1.2.206
Describe the bug
SWC version v1.2.206 is causing our jest setup file to error out when calling jest.spyOn. v1.2.205 does not error out.
Input code
// jest.setup.ts
import * as cache from './packages/foo/src/common/cache'
const redis = new RedisMock(7481)
beforeEach(() => {
jest.spyOn(cache, 'getRedis').mockResolvedValue(redis)
})
// cache.ts
import memoize from 'p-memoize'
import { getConfig } from './config'
export const getRedis = memoize(async () => {
const config = await getConfig()
return new Redis(config.redisUrl)
})
Config
{
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true
},
"target": "es2021",
"keepClassNames": true
}
}
Playground link
No response
Expected behavior
jest.spyOn should stub cache.getRedis
Actual behavior
jest.spyOn fails with the following error:
TypeError: Cannot redefine property: getRedis
at Function.defineProperty (<anonymous>)
at ModuleMocker.spyOn (/home/circleci/project/node_modules/jest-mock/build/index.js:820:16)
at Object.spyOn (/home/circleci/project/jest.setup.ts:26:8)
at Promise.then.completed (/home/circleci/project/node_modules/jest-circus/build/utils.js:333:28)
at new Promise (<anonymous>)
at callAsyncCircusFn (/home/circleci/project/node_modules/jest-circus/build/utils.js:259:10)
at _callCircusHook (/home/circleci/project/node_modules/jest-circus/build/run.js:240:40)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at _runTest (/home/circleci/project/node_modules/jest-circus/build/run.js:202:5)
Version
v1.2.206+
Additional context
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 5
- Comments: 29 (19 by maintainers)
If this is truly a bugfix and not a bug, you should update the intro text here: https://swc.rs/docs/usage/jest
This is no longer a drop in replacement for ts-jest as reverting to ts-jest reverts to the previous behavior
When I set
module: commonjswhat does it mean? Do I getCJSorESM? Both, and neither.It is
CJS, because the output code hasexports/module.exports. It is notCJS, because it is transformed fromESM. Users are usingESMsyntax, such asexport default,export { foo }, etc. Users expectESMbehaviour, such as export is live-binding, export cannot be overwritten. These areESMfeatures. We simulateESMbehaviour inCJS.If the user expects
CJS, it is a misuse to use these syntaxes. There is no equivalent export syntax inESM. However, theexports.foo = exprsyntax still works, as will TS’sexport = expr.But what if the user really wants
ESMand wants to test in jest? This is jest’s problem, which is equivalent to how jest is used in anESMenvironment.@kdy1 I agree that the new behavior may not be a bug, but rather is fixing a previous bug, and the change results in a stricter / more correct adherence to the esm specification, but an argument can be made that this is a breaking change, and hence warrants a major version bump.
Furthermore, as @ldiqual said, I’m also using typescript, and our tsconfig.json has module set to CommonJS, module resolution to node, and target as es2020, so I’m not sure how esm is even coming into the picture.
@ldiqual If you do not expect an esm behaviour, do not use esm syntax. use CJS module.exports, or CTS export synatx.