None of the answers above solved my problem, so here’s my solution:
var mockMyMethod: jest.Mock;
jest.mock('some-package', () => ({
myMethod: mockMyMethod
}));
Something about using const before the imports feels weird to me. The thing is: jest.mock
is hoisted. To be able to use a variable before it you need to use var
, because it is hoisted as well. It doesn’t work with let
and const
because they aren’t.
answered Jun 21, 2021 at 19:31
4
The accepted answer does not handle when you need to spy on the const
declaration, as it is defined inside the module factory scope.
For me, the module factory needs to be above any import statement that eventually imports the thing you want to mock.
Here is a code snippet using a nestjs with prisma library.
// app.e2e.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import mockPrismaClient from './utils/mockPrismaClient'; // you can assert, spy, etc. on this object in your test suites.
// must define this above the `AppModule` import, otherwise the ReferenceError is raised.
jest.mock('@prisma/client', () => {
return {
PrismaClient: jest.fn().mockImplementation(() => mockPrismaClient),
};
});
import { AppModule } from './../src/app.module'; // somwhere here, the prisma is imported
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
)};
answered Apr 15, 2021 at 19:07
JasonJason
2744 silver badges5 bronze badges
3
To clarify what Jason Limantoro said, move the const
above where the module is imported:
const mockMethod1 = jest.fn(); // Defined here before import.
const mockMethod2 = jest.fn();
import MyClass from './my_class'; // Imported here.
import * as anotherClass from './another_class';
jest.mock('./my_class', () => {
return {
default: {
staticMethod: jest.fn().mockReturnValue(
{
method1: mockMethod1,
method2: mockMethod2,
})
}
}
});
answered May 19, 2021 at 0:49
MattMatt
4,1814 gold badges38 silver badges56 bronze badges
The problem that the documentation addresses is that jest.mock
is hoisted but const
declaration is not. This results in factory function being evaluated at the time when mocked module is imported and a variable being in temporal dead zone.
If it’s necessary to access nested mocked functions, they need to be exposed as a part of export object:
jest.mock('./my_class', () => {
const mockMethod1 = jest.fn();
const mockMethod2 = jest.fn();
return {
__esModule: true,
mockMethod1,
mockMethod2,
default: {
...
This also applies to manual mocks in __mocks__
where variables are accessible inside a mock only.
answered Jan 4, 2021 at 7:43
Estus FlaskEstus Flask
203k70 gold badges416 silver badges556 bronze badges
5
You should move your mocking above your imports; that could be the source of your issue. Imports are also hoisted, so multiple hoisted entries would be hoisted in order.
jest.mock('./my_class', () => {
const mockMethod = jest.fn()
const default = { staticMethod: jest.fn().mockReturnValue({ method: mockMethod }) };
return { default, mockMethod };
});
import MyClass, { mockMethod } from './my_class'; // will import your mock
import * as anotherClass from './another_class';
However, if you for some reason can’t do that, you could use doMock
to avoid hoisting behaviour. If this happens on the top of your file, it should be a 1 to 1 change.
const mockMyMethod = jest.fn();
jest.doMock('some-package', () => ({ myMethod: mockMyMethod }));
answered Aug 1, 2022 at 3:57
Ricardo NoldeRicardo Nolde
33.2k4 gold badges36 silver badges39 bronze badges
1
This solution works for me and it’s pretty easy for vuejs+ jest.
Two points to note:
- you should declare the absolute path and not ‘@/js/network/repositories’
- the getter helps to defer the instantiation
const mockGetNextStatuses = jest.fn();
const mockUpdatePrintingStatus = jest.fn();
jest.mock('../../../../../../src/js/network/repositories/index.js', () => {
return {
get printing() {
return {
getNextStatuses: mockGetNextStatuses,
updatePrintingStatus: mockUpdatePrintingStatus,
}
}
}
});
or
jest.mock('../../../../../../src/js/network/repositories/index.js', () => ({
printing: {
getNextStatuses: jest.fn(),
updatePrintingStatus: jest.fn()
}
}));
import { printing } from '../../../../../../src/js/network/repositories/index.js';
// and mock the module
printing.getNextStatuses.mockReturnValue(['XX','YY']);
answered Aug 12, 2022 at 12:33
Per this article… Anyone making it to this page may just be able to set the mocked function to a function returning a function call. As per the OP’s code:
import MyClass from './my_class';
import * as anotherClass from './another_class';
const mockMethod1 = jest.fn();
const mockMethod2 = jest.fn();
jest.mock('./my_class', () => {
return {
default: {
staticMethod: jest.fn().mockReturnValue(
{
method1: () => mockMethod1(), // <- function returning function call
method2: () => mockMethod2(),
})
}
}
});
answered Apr 5 at 15:14
daleyjemdaleyjem
2,2951 gold badge23 silver badges34 bronze badges
This solution worked for me:
jest.mock("../user/useCases/GetUserBalancesUseCase.js", () => {
return {
GetUserBalancesUseCase: {
create: jest.fn().mockReturnValue({
execute: jest
.fn()
.mockReturnValue(require("./fixtures/user/useCaseResponse.js").useCaseResponse),
}),
},
}
})
I couldn’t use the fixture importing it using ESM syntax in this implementation. So I tried using require and fixed the import reference error issue.
This kind of mocking though, is not reliable because bypasses some logic that I want to have covered by the unit test. In my case is necessary to avoid interacting with the infrastructure.
As a reference, I need to test the output of an useCase given an input:
test("Get User Balances", async () => {
const useCaseResponse = await getUserBalancesUseCase.execute({ account, USDPrices })
expect(useCaseResponse).toEqual(getUserBalancesUseCaseResponse)
})
answered Apr 28 at 14:12
Example of using TypeScript with Jest and mockDebug.js module
jest.mock('debug', () => {
global.mockDebug = jest.fn();
return () => global.mockDebug;
});
// usage
describe('xxx', () => {
test('xxx', () => {
expect(global.mockDebug.mock.calls.toString()).toContain('ccc');
})
});
node_modules
4,7406 gold badges21 silver badges37 bronze badges
answered Nov 9, 2022 at 15:17
1
The “cannot access before initialization” reference error occurs in JavaScript when you try to access a variable before it is declared with let
or const
and initialized in the same scope. To fix it, initialize the variables before accessing them.
Here are some examples of the error occurring:
// ❌ ReferenceError: Cannot access 'num' before initialization
console.log(num);
let num = 2;
// ❌ ReferenceError: Cannot access 'name' before initialization
console.log(name);
const name = 'Coding Beauty';
// ❌ ReferenceError: Cannot access 'arr' before initialization
arr = [7, 8, 9];
let arr = [3, 4, 5];
To solve the error, you need to initialize the variable before accessing it.
// ✅ No error
let num = 2;
console.log(num); // 2
// ✅ No error
const name = 'Coding Beauty';
console.log(name); // Coding Beauty
// ✅ No error
let arr = [3, 4, 5];
arr = [7, 8, 9];
var
vs let
The occurrence of this error shows an important difference between the var
and let
keywords. If you had declared the variable with var
, the error wouldn’t have occurred.
// No error
console.log(num); // undefined
var num = 2;
// No error
console.log(name); // undefined
var name = 'Coding Beauty';
// No error
arr = [7, 8, 9];
var arr = [3, 4, 5];
This happens because variables declared with the var
keyword are hoisted – they are moved by the JavaScript interpreter to the top of the current scope (to the top of the current script or current function).
Basically, this is what happens to our variables declared with var
:
var num;
var name;
var arr;
console.log(num); // undefined
num = 2;
console.log(name); // undefined
name = 'Coding Beauty';
arr = [7, 8, 9];
arr = [3, 4, 5];
Note: The declarations are hoisted, but the initializations are not.
Because of this hoisting, even when the variable is declared in a non-function block, like an if
block, the error will still not occur if you try to access the variable from outside the if
statement.
// No error!
console.log(num); // undefined
if (true) {
var num = 2;
}
Only the global scope and function scopes are used for hoisting, so like before, the variable declaration is moved to the top of the file.
var num;
console.log(num); // undefined
if (true) {
num = 2;
}
Every Crazy Thing JavaScript Does
A captivating guide to the subtle caveats and lesser-known parts of JavaScript.
Sign up and receive a free copy immediately.
Ayibatari Ibaba is a software developer with years of experience building websites and apps. He has written extensively on a wide range of programming topics and has created dozens of apps and open-source libraries.
Добрый день. Использую webpack+babel+vue.
У меня 2 файла app.js и methods.js
app.js содержит объект Vue и константу с объектом.
import {VUE_METHODS} from 'methods';
export const NDS = {
title: 'НДС 20%'
};
VUE_METHODS.methods.objectFreeze(NDS);
export let app = new Vue({
el : '#app',
mixins : [VUE_METHODS],
//бла бла бла дальше не важно
});
methods.js содержит примесь
import axios from 'axios';
import {NDS} from 'app';
export const VUE_METHODS = {
data : function () {
return {
nds: NDS
}
},
computed: {
//бла бла бла
},
methods : {
objectFreeze : function (_o, _property = null) {
//не важно
}
}
};
В файле сборки вызываю их так
import 'methods';
import 'app';
Все компилится но в браузере при использовании скомпилиного файла вылетает в консоли ошибка
Uncaught ReferenceError: Cannot access 'ne' before initialization
, где ne — это VUE_METHODS. А ругается на строке с
VUE_METHODS.methods.objectFreeze(NDS);
Как решить ошибку?
Comments
3 similar comments
1 similar comment
This was referenced
Dec 14, 2022
This was referenced
Mar 30, 2023
hyperupcall
added a commit
to fox-forks/OED
that referenced
this issue
Apr 3, 2023
Vite is more strict the `import`s it accepts. These imports are fixed. Additionally, the Redux store is now exported form a separate file (other than `index.tsx`. This was done to workaround vitejs/vite#3033. The circular imports and Redux store don't play nice, so the circular import was removed.
hyf0
linked a pull request
Apr 27, 2023
that will
close
this issue
9 tasks
hyperupcall
added a commit
to hyperupcall/OED
that referenced
this issue
May 19, 2023
Defining the Redux store in the same file as the app creates problems with Vite. There is some issue with circular imports not working properly with HMR (hot module replacement). Upstream tracks this issue at vitejs/vite#3033; a workaround is to define and export the Redux store from a different file. This commit does exactly that to circumvent the circular import issue.
In this article, we will delve into the intricacies of a common JavaScript error known as “ReferenceError: Cannot Access Before Initialization.”
We will explore the reasons behind this error and provide comprehensive solutions to help you resolve it effectively.
The “ReferenceError: Cannot access before initialization” error happens when a variable declared with let or const is accessed before it has been initialized within the scope.
Here is how this error occurs:
// 📌 ReferenceError: Cannot access 'arr' before initialization
arr = [3, 2, 1];
let arr = [1, 2, 3];
if (5 === 5) {
// 📌ReferenceError:
console.log(num);
const num = 100;
}
function example() {
// 📌ReferenceError:
console.log(str);
let str = 'bobbyhadz.com';
}
// 📌ReferenceError:
const result = sum(5, 10);
const sum = (a, b) => {
return a + b;
};
Potential causes of Referenceerror
A common reason for this error is connected to the variable scope.
When you use the let or const keywords to declare a variable inside a block or function, it becomes scoped to that block or function.
Thus, if you attempt to access the variable before declaring it within that scope, the error occurs.
Furthermore, in asynchronous JavaScript, like promises or async/await, the execution order can differ.
If you try to access a variable or function that depends on asynchronous operations before it’s initialized or resolved, an error may occur.
Meanwhile, in JavaScript, “hoisting” is when variable and function declarations are moved to the top during compilation.
Wherein Declarations are hoisted, but not initialization.
In addition, trying to access a variable before declaring it, even with hoisting, results in a “ReferenceError: Cannot Access Before Initialization” error.
Solutions – Referenceerror cannot access before initialization
Initialize the variable before accessing it
The first way to resolve the error is to make sure to initialize the variables before utilizing them.
// 📌 use the let keyword before accessing the variable
let arr = [10, 20, 30];
arr = [30, 20, 10];
if (10 === 10) {
// 📌 use the const keyword before accessing the variable
const num = 200;
console.log(num);
}
function example() {
// 📌 use the let keyword before accessing the variable
let str = 'itsourcecode.com';
console.log(str);
}
// 📌 Define a function with the function keyword instead
const result = sum(10, 20);
console.log(result); // 30
function sum(a, b) {
return a + b;
}
Variables declared with the keywords “let” and “const” are limited to the scope in which they are declared.
If you’re having trouble pinpointing the location of the error in your code, check the error message displayed in your browser’s console or Node.js terminal.
Move the variable declaration to the top
Another way to solve the error is to move the variable declaration to the top of the if block.
Here is how the error occurs:
const arr = ['car', 'ren', 'bea'];
if ('hi'.length === 2) {
// 📌 ReferenceError: Cannot access 'arr' before initialization
arr.push('test');
const arr = [10, 20, 30];
}
On line 1, we initialized the variable arr and attempted to add a value to the array within the if statement.
Unfortunately, there is a conflicting declaration of arr within the if block, resulting in an error.
The line arr.push(‘test’) in the if block is intended to add a value to the numeric array specifically declared within the if block.
To fix this we have to move the variable declaration to the top of the if block.
const arr = ['car', 'ren', 'bea'];
if ('hi'.length === 2) {
// 📌️ first declare the variable
const arr = [10, 20, 30];
// 📌️ access variable after
arr.push('test');
console.log(arr);
}
console.log(arr);
We resolved the problem by declaring the variable arr at the beginning of the if block.
It’s important to note that declaring a variable with the same name as one in the outer scope is generally discouraged.
Leverage Hoisting
While hoisting can be a source of errors, it can also be utilized to your advantage.
By declaring your variables and functions at the top of their respective scopes, you can leverage hoisting effectively and avoid encountering the “ReferenceError: Cannot Access Before Initialization” error.
// Good practice: Utilize hoisting by declaring variables at the top
function myFunction() {
let myVariable; // Declaration
// ... Code that uses myVariable ...
myVariable = 'Initialized'; // Initialization
}
Handle Asynchronous Operations Carefully
When dealing with asynchronous JavaScript, it is crucial to handle the order of execution properly.
Ensure that any dependent variables or functions are fully initialized or resolved before attempting to access them.
// Example: Handling asynchronous operations with Promises
function getData() {
return new Promise((resolve, reject) => {
// Simulating an asynchronous operation
setTimeout(() => {
const data = 'Initialized';
resolve(data); // Resolve the Promise
}, 1000);
});
}
// Usage of the asynchronous function
async function myFunction() {
const myData = await getData(); // Wait for data initialization
// ... Code that uses myData ...
}
Anyway besides this error, we also have here fixed errors that might help you when you encounter them.
- Uncaught referenceerror google is not defined
- Importerror: cannot import name ‘parse_rule’ from ‘werkzeug.routing’
Conclusion
In conclusion, the “ReferenceError: Cannot Access Before Initialization” error can be resolved by understanding the underlying causes and applying the appropriate solutions.
By following best practices such as declaring variables at the beginning of their respective scopes, leveraging hoisting effectively, and handling asynchronous operations carefully, you can ensure seamless execution of your JavaScript code.
I think that’s all for this error. I hope you have gained something to fix their issues.
Until next time! 😊