Jest scope error in mocking Aws-sdk: ReferenceError: Cannot access 'variable_name' before initialization
Jest scope error in mocking Aws-sdk: ReferenceError: Cannot access 'variable_name' before initialization
我正在尝试使用 Jest 测试框架模拟 aws-sdk。
这是我要在 auth.js 文件中测试的代码:
...
const AWS = require('aws-sdk');
AWS.config.update({ region: config.awsConfig.region });
...
const cognito = new AWS.CognitoIdentityServiceProvider();
await cognito.confirmSignUp(params).promise();
....
这是我的 auth.spec.js 文件中的测试代码:
const mockConfirmSignUp = jest.fn((params) => {
return {
promise() {
return Promise.resolve('mock response');
}
};
});
jest.mock('aws-sdk', () => {
return {
CognitoIdentityServiceProvider: jest.fn(() => ({
confirmSignUp: mockConfirmSignUp
})),
config: {
update: jest.fn()
}
};
});
但是,当我测试代码时,我收到此错误:
ReferenceError: Cannot access 'mockConfirmSignUp' before initialization
我可以通过将 mockConfirmSignUp
实现移到 jest.mock
块中来使其工作,但是,我想在后续案例中将 mockConfirmSignUp
的实现修改为 return Promise.reject
开玩笑地使用 mockConfirmSignUp.mockImplementationOnce()
实用程序,用于测试失败案例,并将此功能移动到 jest.mock 块内会禁止我这样做。
我意识到这可能是 'hoisting' 问题,其中 jest.mock 被提升到文件的顶部,但是下面另一个类似的测试用例对我没有任何问题:
const mockSendEmail = jest.fn(() => {
return {
promise() {
return Promise.resolve('mock response');
}
};
});
jest.mock('aws-sdk', () => {
return {
SES: jest.fn(() => ({
sendEmail: mockSendEmail
})),
config: {
update: jest.fn()
}
};
});
后一个代码与前一个代码有何不同?
结果代码 jest.mock
被提升到相关的 auth.js import
之上,两者都在 const mockConfirmSignUp
变量声明之上。
第一个代码片段在调用 CognitoIdentityServiceProvider
时访问 mockConfirmSignUp
,这发生在导入 auth.js 和 mockConfirmSignUp
声明之前。第二个片段没有这样做。
这是the manual描述的情况:
A limitation with the factory parameter is that, since calls to jest.mock() are hoisted to the top of the file, it's not possible to first define a variable and then use it in the factory. An exception is made for variables that start with the word 'mock'. It's up to you to guarantee that they will be initialized on time!
避免此提升问题的安全方法是将间谍从外部范围移动到模拟导出,以便访问它以更改实现并断言它,这样就可以在模块对象上访问它:
import awssdk from 'awssdk';
jest.mock('aws-sdk', () => {
const mockConfirmSignUp = jest.fn(...);
return {
mockConfirmSignUp,
CognitoIdentityServiceProvider: jest.fn(() => ({
confirmSignUp: mockConfirmSignUp
})),
config: {
update: jest.fn()
}
};
});
...
expect(awssdk.mockConfirmSignUp).toBeCalledWith(...);
当提升没有问题但需要将可重复使用的模拟从jest.mock
移动到__mocks__
时也适用。
I can make it work by moving the mockConfirmSignUp implementation inside the jest.mock block, however, I want to modify the implementation of mockConfirmSignUp in a subsequent case to return Promise.reject using mockConfirmSignUp.mockImplementationOnce() utility in jest
如果一个模块需要使用不同的依赖项进行多次测试,auth.js 和 aws-sdk 导入可以从顶层移至测试。这样jest.mock
提升和mockConfirmSignUp
就没有问题了。重新导入还需要使用 jest.resetModules
或 jest.isolateModules`。
我创建了这段代码并且运行良好(非常简单):
const mockedApiPost = jest.fn();
jest.mock('../../services/api', () => ({
post: () => {
mockedApiPost.call(mockedApiPost);
},
}));
我正在尝试使用 Jest 测试框架模拟 aws-sdk。
这是我要在 auth.js 文件中测试的代码:
...
const AWS = require('aws-sdk');
AWS.config.update({ region: config.awsConfig.region });
...
const cognito = new AWS.CognitoIdentityServiceProvider();
await cognito.confirmSignUp(params).promise();
....
这是我的 auth.spec.js 文件中的测试代码:
const mockConfirmSignUp = jest.fn((params) => {
return {
promise() {
return Promise.resolve('mock response');
}
};
});
jest.mock('aws-sdk', () => {
return {
CognitoIdentityServiceProvider: jest.fn(() => ({
confirmSignUp: mockConfirmSignUp
})),
config: {
update: jest.fn()
}
};
});
但是,当我测试代码时,我收到此错误:
ReferenceError: Cannot access 'mockConfirmSignUp' before initialization
我可以通过将 mockConfirmSignUp
实现移到 jest.mock
块中来使其工作,但是,我想在后续案例中将 mockConfirmSignUp
的实现修改为 return Promise.reject
开玩笑地使用 mockConfirmSignUp.mockImplementationOnce()
实用程序,用于测试失败案例,并将此功能移动到 jest.mock 块内会禁止我这样做。
我意识到这可能是 'hoisting' 问题,其中 jest.mock 被提升到文件的顶部,但是下面另一个类似的测试用例对我没有任何问题:
const mockSendEmail = jest.fn(() => {
return {
promise() {
return Promise.resolve('mock response');
}
};
});
jest.mock('aws-sdk', () => {
return {
SES: jest.fn(() => ({
sendEmail: mockSendEmail
})),
config: {
update: jest.fn()
}
};
});
后一个代码与前一个代码有何不同?
结果代码 jest.mock
被提升到相关的 auth.js import
之上,两者都在 const mockConfirmSignUp
变量声明之上。
第一个代码片段在调用 CognitoIdentityServiceProvider
时访问 mockConfirmSignUp
,这发生在导入 auth.js 和 mockConfirmSignUp
声明之前。第二个片段没有这样做。
这是the manual描述的情况:
A limitation with the factory parameter is that, since calls to jest.mock() are hoisted to the top of the file, it's not possible to first define a variable and then use it in the factory. An exception is made for variables that start with the word 'mock'. It's up to you to guarantee that they will be initialized on time!
避免此提升问题的安全方法是将间谍从外部范围移动到模拟导出,以便访问它以更改实现并断言它,这样就可以在模块对象上访问它:
import awssdk from 'awssdk';
jest.mock('aws-sdk', () => {
const mockConfirmSignUp = jest.fn(...);
return {
mockConfirmSignUp,
CognitoIdentityServiceProvider: jest.fn(() => ({
confirmSignUp: mockConfirmSignUp
})),
config: {
update: jest.fn()
}
};
});
...
expect(awssdk.mockConfirmSignUp).toBeCalledWith(...);
当提升没有问题但需要将可重复使用的模拟从jest.mock
移动到__mocks__
时也适用。
I can make it work by moving the mockConfirmSignUp implementation inside the jest.mock block, however, I want to modify the implementation of mockConfirmSignUp in a subsequent case to return Promise.reject using mockConfirmSignUp.mockImplementationOnce() utility in jest
如果一个模块需要使用不同的依赖项进行多次测试,auth.js 和 aws-sdk 导入可以从顶层移至测试。这样jest.mock
提升和mockConfirmSignUp
就没有问题了。重新导入还需要使用 jest.resetModules
或 jest.isolateModules`。
我创建了这段代码并且运行良好(非常简单):
const mockedApiPost = jest.fn();
jest.mock('../../services/api', () => ({
post: () => {
mockedApiPost.call(mockedApiPost);
},
}));