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: commonjs
what does it mean? Do I getCJS
orESM
? Both, and neither.It is
CJS
, because the output code hasexports
/module.exports
. It is notCJS
, because it is transformed fromESM
. Users are usingESM
syntax, such asexport default
,export { foo }
, etc. Users expectESM
behaviour, such as export is live-binding, export cannot be overwritten. These areESM
features. We simulateESM
behaviour inCJS
.If the user expects
CJS
, it is a misuse to use these syntaxes. There is no equivalent export syntax inESM
. However, theexports.foo = expr
syntax still works, as will TS’sexport = expr
.But what if the user really wants
ESM
and wants to test in jest? This is jest’s problem, which is equivalent to how jest is used in anESM
environment.@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.