swc_mut_cjs_exports
swc_mut_cjs_exports copied to clipboard
Jest commonjs gives ReferenceError: Cannot access before initialization when jest.mock and exported class
I've read #79 but I think I'm seeing a related issue.
minimal reproducible code
There are two input source files:
// 1. application/web/foo.test.ts
const run = jest.fn()
const fakeBar = {
__esModule: true,
default: {
run,
},
}
jest.mock('./bar', () => fakeBar)
import bar from './bar'
describe('Test example', () => {
it('has a passing test', () => {
expect(bar.run).not.toBeCalled()
})
})
// 2. application/web/bar.ts
export default class Bar {
static run() {}
}
The swc config used for transforming TS to JS in jest is:
{
"$schema": "http://json.schemastore.org/swcrc",
"sourceMaps": true,
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"dynamicImport": true,
"decorators": true
},
"preserveAllComments": true,
"transform": null,
"target": "es2017",
"loose": false,
"externalHelpers": false,
"keepClassNames": false,
"experimental": {
"plugins": [
[
"swc_mut_cjs_exports",
{}
]
]
}
},
"module": {
"type": "commonjs"
}
}
The tsc config is:
{
"transpileOnly": true,
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"jsx": "react-jsx",
"esModuleInterop": true,
"sourceMap": false,
"allowJs": true
}
}
tsc transpiled
Test output:
+ TS_LOADER=tsc yarn -s test application/web/foo.test.ts
PASS application/web/foo.test.ts
Test example
✓ has a passing test (1 ms)
// tsc js output of foo.test.ts
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const run = jest.fn();
const fakeBar = {
__esModule: true,
default: {
run,
},
};
jest.mock("./bar", () => fakeBar);
const bar_1 = tslib_1.__importDefault(require("./bar"));
describe("Test example", () => {
it("has a passing test", () => {
expect(bar_1.default.run).not.toBeCalled();
});
});
// tsc js output of bar.ts
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Bar {
static run() {}
}
exports.default = Bar;
swc transpiled
Test output:
+ TS_LOADER=swc yarn -s test application/web/foo.test.ts
FAIL application/web/foo.test.ts
● Test suite failed to run
ReferenceError: Cannot access 'fakeBar' before initialization
7 | },
8 | }
> 9 | jest.mock('./bar', () => fakeBar)
| ^
10 |
11 | import bar from './bar'
12 |
at fakeBar (application/web/foo.test.ts:9:26)
at Object.<anonymous> (application/web/foo.test.ts:6:39)
// swc js output of foo.test.ts
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
const _bar = _interop_require_default(require("./bar"));
function _interop_require_default(obj) {
return obj && obj.__esModule
? obj
: {
default: obj,
};
}
const run = jest.fn();
const fakeBar = {
__esModule: true,
default: {
run,
},
};
jest.mock("./bar", () => fakeBar);
describe("Test example", () => {
it("has a passing test", () => {
expect(_bar.default.run).not.toBeCalled();
});
})
// swc js output of bar.ts
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
Object.defineProperty(exports, "default", {
enumerable: true,
get() {
return Bar;
},
set(v) {
Bar = v;
},
configurable: true,
});
var Bar;
Bar = class Bar {
static run() {}
};
Notes
SWC version info:
@swc/[email protected]
@swc/[email protected]
@swc/[email protected]
[email protected]
[email protected]
Tsc generates this import order:
jest.mock("./bar", () => fakeBar);
const bar_1 = tslib_1.__importDefault(require("./bar"));
while swc generates:
const _bar = _interop_require_default(require("./bar"));
function _interop_require_default(obj) { ... }
const run = jest.fn();
const fakeBar = { ... }
jest.mock("./bar", () => fakeBar);
Could that ordering be an issue that causes the runtime error?
I'm using the jest preset ts-jest
with a custom transformer (to allow switching at runtime using TS_LOADER
between tsc and swc).
Could a jest plugin like this hoisting of mock calls be related?
I hope this issue contains all the information. Let me know if a reproducible git repo would be helpful to narrow down the problem. Thank you!