Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Jest commonjs gives ReferenceError: Cannot access before initialization when jest.mock and exported class #92

@smvv

Description

@smvv

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/core@1.3.95
@swc/jest@0.2.29
@swc/helpers@0.5.3
swc-loader@0.2.3
swc_mut_cjs_exports@0.86.17

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions