admin管理员组文章数量:1336398
I hope someone might help me understanding the interactivity of js prototypes and jest.spOn()
.
I have a small Example:
An example class in file TestObj.ts
:
export default class TestObj {
foo() {
// Do Something e.g.
console.log("Hello World!");
}
}
The following example Test Case is succeeding but the console.log
is never executed.
import TestObj from './TestObj';
const spyObj = jest.spyOn(TestObj.prototype, 'foo');
test('debug test', () => {
const obj = new TestObj();
obj.foo();
expect(spyObj).toHaveBeenCalled();
});
If I change the Example Test Case to the following, the test succeeds and the console.log
statement is called as expected.
import TestObj from './TestObj';
test('debug test', () => {
const spyObj = jest.spyOn(TestObj.prototype, 'foo');
const obj = new TestObj();
obj.foo();
expect(spyObj).toHaveBeenCalled();
});
Any idea why the version, using the global spyOn variable does not work as expected?
Edit:
It seems to be not related to prototypes.
The same Issue is there for a function without any kind of class,
editing the First Code snippet (TestObj.ts
) to this:
export foo() {
// Do Something e.g.
console.log("Hello World!");
};
We receve the same issue for the updated second snipped. (The test succeeds but the console log is never reached.)
import * as testlib from './TestObj';
const spyObj = jest.spyOn(testlib, 'foo');
test('debug test', () => {
testlib.foo();
expect(spyObj).toHaveBeenCalled();
});
However if we update the second snippet to the following the test succeeds and the console log is executed:
import * as testlib from './TestObj';
const spyObj: jest.SpyInstance;
beforeEach(() => {
spyObj = jest.spyOn(testlib, 'foo');
});
test('debug test', () => {
testlib.foo();
expect(spyObj).toHaveBeenCalled();
});
However I have still no clue why I discover this issue.
I hope someone might help me understanding the interactivity of js prototypes and jest.spOn()
.
I have a small Example:
An example class in file TestObj.ts
:
export default class TestObj {
foo() {
// Do Something e.g.
console.log("Hello World!");
}
}
The following example Test Case is succeeding but the console.log
is never executed.
import TestObj from './TestObj';
const spyObj = jest.spyOn(TestObj.prototype, 'foo');
test('debug test', () => {
const obj = new TestObj();
obj.foo();
expect(spyObj).toHaveBeenCalled();
});
If I change the Example Test Case to the following, the test succeeds and the console.log
statement is called as expected.
import TestObj from './TestObj';
test('debug test', () => {
const spyObj = jest.spyOn(TestObj.prototype, 'foo');
const obj = new TestObj();
obj.foo();
expect(spyObj).toHaveBeenCalled();
});
Any idea why the version, using the global spyOn variable does not work as expected?
Edit:
It seems to be not related to prototypes.
The same Issue is there for a function without any kind of class,
editing the First Code snippet (TestObj.ts
) to this:
export foo() {
// Do Something e.g.
console.log("Hello World!");
};
We receve the same issue for the updated second snipped. (The test succeeds but the console log is never reached.)
import * as testlib from './TestObj';
const spyObj = jest.spyOn(testlib, 'foo');
test('debug test', () => {
testlib.foo();
expect(spyObj).toHaveBeenCalled();
});
However if we update the second snippet to the following the test succeeds and the console log is executed:
import * as testlib from './TestObj';
const spyObj: jest.SpyInstance;
beforeEach(() => {
spyObj = jest.spyOn(testlib, 'foo');
});
test('debug test', () => {
testlib.foo();
expect(spyObj).toHaveBeenCalled();
});
However I have still no clue why I discover this issue.
Share Improve this question edited Sep 7, 2021 at 9:08 lubro asked Sep 6, 2021 at 17:24 lubrolubro 3561 gold badge4 silver badges11 bronze badges1 Answer
Reset to default 6who ever es across this post,
Problem explanation
I did a lot more of research(try&error, mdn, jest manpage and a lot of medium articles) and I guess that I found out the reason for the strange behavior. To understand this issue it is important to know a number of points:
- 1: JS prototypes are global variables, every object of the corresponding type relies on.
- 2: Jest does not reset global variables after every test, changes made before, or inside any test to a global variable will be kept for the whole test suite (file).
- 3: The jest spy on function is actually a mockup of the specified function with an implementation calling the function it self. e.g.:
jest.SpyOn(TestObj.prototype, 'foo');
actually is implemented as:TestObj.prototype.foo = new jest.fn().mockImplementation(()=>{original_TestObj.prototype.foo()});
This means spying on a function of a class prototype is actually changing a global variable. - 4: Depending on your jest config, there is the possibility to reset mockup functions before every test to the default value. But be careful the default function for
spyOn
seems to be the same as forjest.fn()
it self, an empty implementation, which means the mock-up is still callable but no code, especially not the original implementation is executed.
Solution
- avoid changing global variables, if you want your testcases independent from each other.
- avoid spying on prototypes, in test cases, if you require the spy only in a single test try to spy on the local object eg:
test('should foo', () => {
const testObj = new TestObj();
const spyOnFn = jest.spyOn(testObj, 'foo');
// Do anything
expect(spyOnFn).to//Have been anything
});
- if requiring
spyOn
implementations of the same function in more than one test try to create a global variable for the Test but use the before each functionality of jest to setup the Spy. This functionality is executed after the reset of all mocks (if enabled). e.g.:
let spyOnFunction1: jest.SpyInstance;
beforeEach(()=> {
spyOnFunction1 = jest.spyOn(TestObj.prototype, 'foo');
});
本文标签: javascriptglobal Jest SpyOn function doesen39t call the original functionStack Overflow
版权声明:本文标题:javascript - global Jest SpyOn function doesen't call the original function - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742375765a2463129.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论