How do I make Sinon.JS callCount increment - javascript

So I've got a Chai/Mocha/Sinon test like this:
import sinon from 'sinon'
describe(`My Test`, () => {
it(`should track the number of calls`, () => {
function testMe() {
console.log(`test me`)
}
const spy = sinon.spy(testMe)
testMe()
console.log(spy.getCalls())
console.log(spy.callCount)
})
})
When the test runs, the following is logged:
test me
[]
0
This is baffling. What am I doing wrong?

If you want spy on regular functions, the only way you can track calls to that function is by calling the spy:
it(`should track the number of calls`, () => {
function testMe() {
console.log(`test me`)
}
const spy = sinon.spy(testMe)
spy()
console.log(spy.getCalls())
console.log(spy.callCount)
})
If testMe would have been a property of an object (or a method of a class), you could call the original, because in that situation Sinon can replace the original with the spied-on version. For instance:
describe(`My Test`, () => {
it(`should track the number of calls`, () => {
const obj = {
testMe() {
console.log(`test me`)
}
};
const spy = sinon.spy(obj, 'testMe')
obj.testMe();
console.log(spy.callCount)
})
})

Related

How to test if function passed as parameter was called in Jest

I have a function that receives another function as an argument. I would like to make sure it was called properly.
Function to be tested:
const loadNamespaces = (setNamespaces) => {
namespaceAPI.getNamespaces().then(namespaces => {
setNamespaces(namespaces);
});
}
My main goal here was to assert mockSetNamespaces was called.
I was able to mock and assert namespaceAPI.getNamespaces was called by using jest.spyOn method, but that didn't work for asserting if mockSetNamespaces was called:
test("loadNamespaces", () => {
const mockSetNamespaces = jest.fn();
const mockNamespaces = [
{ endpoint: "mock namespace 1", rooms: [] },
];
jest.spyOn(namespaceAPI, "getNamespaces").mockImplementation(() => {
return new Promise((resolve) => {
resolve(mockNamespaces);
});
});
SocketIOActions.loadNamespaces(mockSetNamespaces);
expect(namespaceAPI.getNamespaces).toHaveBeenCalled();
expect(mockSetNamespaces).toHaveBeenCalled();
});
Error message received from Jest:
● loadNamespaces
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
I've also tried to add setNamespaces to an object, so jest.spyOn method could be used, but also didn't assert method was called:
test("loadNamespaces", () => {
const mockObject = {
mockSetNamespaces: jest.fn(),
};
const mockNamespaces = [
{ endpoint: "mock namespace 1", rooms: [] },
];
jest.spyOn(namespaceAPI, "getNamespaces").mockImplementation(() => {
return new Promise((resolve) => {
resolve(mockNamespaces);
});
});
jest.spyOn(mockObject, "mockSetNamespaces").mockImplementation(() => {
console.log("Hello from spy function");
});
SocketIOActions.loadNamespaces(mockObject.mockSetNamespaces);
expect(namespaceAPI.getNamespaces).toHaveBeenCalled();
expect(mockObject.mockSetNamespaces).toHaveBeenCalled();
});
Proof that mock function was actually called:
console.log
Hello from spy function
Is this the expected behavior from Jest? I would be glad to know if there is a cleaner way to do this.
Using spyOn when you need to mock specific function from the module instead of mocking all.
I would do in this way.
// this will help you auto mock all namespaceAPI function. If you just need to mock "getNamespaces" then you stick with spyOn
jest.mock('namespaceAPI')
test("loadNamespaces", () => {
// you can directly mock implementation in jest function, dont need to spy it again.
const mockSetNamespaces = jest.fn().mockImplementation(() => {
console.log("Hello from spy function");
});
SocketIOActions.loadNamespaces(mockSetNamespaces);
expect(namespaceAPI.getNamespaces).toHaveBeenCalled();
expect(mockSetNamespaces).toHaveBeenCalled();
});

mocking private methods to test an exported method fails in jest

I'm having an actual class like this
my-file.js
const methodA = () => { return 'output-from-methodA'; }
const methodB = () => { const b = methodA(); b.c = "out-put bind"; return b; }
module.exports = {
methodB
}
my-file.test.js
const { methodA, methodB } = require('./my-file.js');
describe('methodB testing', () => {
it('should call methodA', () => {
methodB();
expect(methodA).toHaveBeenCalled()
}
});
here methodA is private method, so it is not explicit to the test file, then how i ensure it is called or not in the test files
There is no way to test the private function, only the alternative way found is to test the outputs like
const { methodA, methodB } = require('./my-file.js');
describe('methodB testing', () => {
it('should call methodA', () => {
const result = methodB();
expect(result.b.c).toBe("out-put bind")
}
});

How to check if one function triggers another function with `Mocha`, `Chai`, `Sinon`

How to create test with Mocha, Chai, Sinon to check if one function triggers another function.
I would like to check if funcToTrigger triggers funcToSpy
import { expect } from 'chai';
import sinon from 'sinon';
it('one function should trigger other function', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const funcToTrigger = () => {
funcToSpy();
};
const spyFunc = sinon.spy(funcToSpy);
funcToTrigger();
expect(spyFunc.called).to.be.true;
});
When I test only one function it works fine:
it('function should be called', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const spyFunc = sinon.spy(funcToSpy);
spyFunc();
expect(spyFunc.called).to.be.true;
});
Based on documentation:
var spy = sinon.spy(myFunc);
Wraps the function in a spy. You can pass this spy where the original
function would otherwise be passed when you need to verify how the
function is being used.
Usage examples:
import { expect } from 'chai';
import sinon from 'sinon';
it('use Object', () => {
const Test = {
funcToSpy: () => {
console.log('I should be called');
},
};
const funcToTrigger = () => {
Test.funcToSpy();
};
const spyFunc = sinon.spy(Test, 'funcToSpy');
funcToTrigger();
expect(spyFunc.called).to.be.true;
});
it('use Function', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const spyFunc = sinon.spy(funcToSpy);
const funcToTrigger = () => {
spyFunc();
};
funcToTrigger();
expect(spyFunc.called).to.be.true;
});
it('use Function Argument', () => {
const funcToSpy = () => {
console.log('I should be called');
};
const funcToTrigger = (funcToSpy) => {
funcToSpy();
};
const spyFunc = sinon.spy(funcToSpy);
funcToTrigger(spyFunc);
expect(spyFunc.called).to.be.true;
});
Result:
$ npx mocha index.spec.js
I should be called
✓ use Object
I should be called
✓ use Function
I should be called
✓ use Function Argument
3 passing (3ms)
$
Your test fail because: funcToTrigger has defined and always calls the original funcToSpy.
In the 'use Object' case, funcToTrigger calls method inside object Test, which has been replaced by spy, which is wrapping funcToSpy.
In the 'use Function' case, funcToTrigger calls spy directly, and the spy is wrapping funcToSpy.
In the 'use Function Argument' case, funcToTrigger calls first argument which is a spy, which is wrapping funcToSpy.

How to jest spyOn a commonJS default export

Is it possible to jest.spyOn a default export so that I can call the mockImplementation method to change what the function does before each test?
// code.js
module.exports = () => {
// some irrelevant code I want to rewrite with a mock
};
// test
const code = require('./code.js');
const mockCode = jest.spyOn(code, 'default'); // this line doesn't work with the error: "Cannot spy the default property because it is not a function; undefined given instead"
it('some test', async () => {
mockCode.mockImplementationOnce(() => { console.log('test') });
});
I've also tried to use jest.mock() unsuccessfully:
const code = require('./code');
jest.mock('./code',
() => () => {
console.log('test');
}
);
it('some test', async () => {
code.mockImplementationOnce(() => { console.log('test2') }); // error
});

How to mock or test an async cb function with jest?

say I have this:
componentDidMount() {
window.Something.windowFunction(EVENT_HANDLER, this.myFunc)
}
myFunc() {
// test that this was called
}
how can I mock the window object to make sure that I get inside the myFunc
I've done this
const mockFn = jest.fn().mockImplementation((eventHandler, eventCallback) => {
return eventCallback()
})
global.Something = {
windowFunction: mockFn('event-handler', () => jest.fn()),
}
but it's never calling myFunc

Categories