Calling Jest spyOn on function passed as props - unit-testing

I have an onSubmit function passed as props to a child component.
How would I spy on it? This is one of the things I have tried
const onSubmitMock = jest.fn()
const wrapper = shallow(
<Form onSubmit={onSubmitMock} />
)
const spy = jest.spyOn(wrapper.instance(), onSubmitMock);
I get
Cannot spy the function mockConstructor() {return fn.apply(this, arguments);} property because it is not a function; undefined given instead
I tried
const spy = jest.spyOn(wrapper.instance(), 'onSubmit');
and the same thing happended.

You can use expect(onSubmitMock ).toHaveBeenCalled(); directly after simulating submit event.
You are getting error probably because spyOn returns jest.fn()
https://jestjs.io/docs/en/jest-object#jestspyonobject-methodname

Related

How to mock an imported constant with Jasmine?

A component is meant to behave differently based on a external variable, which is used as a kind of configuration. I would like to test all the possible behaviors, but I don't get how to mock a constant variable.
I tried to use spyOnProperty as in the code below, but an error occurs, stating that the variable is not declared configurable.
// constants.js
export const DEFAULT_STATUS = 'test';
// component.spec.js
import * as constants from './constants';
// here other stuff and component init
it('should change default class based on a constant', () => {
const tmpDefaultStatus = 'test1';
spyOnProperty(constants, 'DEFAULT_STATUS', 'get').and.returnValue(tmpDefaultStatus);
expect(component.className).toBe(tmpDefaultStatus)
});
Then this error is thrown:
Error: : DEFAULT_STATUS is not declared configurable.
Is it still possible to mock that variable, without changing constant.js content?
I don't think there is. I would do:
it('should change default class based on a constant', () => {
const oldState = constants.DEFAULT_STATUS;
const tmpDefaultStatus = 'test1';
constants.DEFAULT_STATUS = tmpDefaultStatus;
expect(component.className).toBe(tmpDefaultStatus);
constants.DEFAULT_STATUS = oldState;
});
I am not sure if that test will pass or not but the idea is to change the value and take it back to its original for each test.

jest.fn() v/s jest.mock()?

For mocking uuidv4, I am using this :
import { v4 as uuidv4 } from "uuid";
jest.mock("uuid");
uuidv4.mockReturnValue("uuid123");
And for mocking window.confirm, I am using this:
window.confirm = jest.fn().mockImplementation(() => true);
These both are working all right.
But when i try doing this i.e
const uuidv4 = jest.fn.mockImplementation(() => "uuid123");
I get this error
TypeError: jest.fn.mockImplementation is not a function
I am confused between jest.fn() and jest.mock().
Can someone please elaborate on which one to use and when to use, with suitable example?
Just a quick explanation for you:
jest.mock is to mock a certain module. Once you write jest.mock('uuid') then it means all exported things would be turned to a jest.Mock type, that's why you can mock v4 method: v4.mockReturnValue('yourV4Id');
jest.mock('aModule');
import {aMember} from "aModule";
// is now a jest mock type <=> jest.fn()
aMember.mockReturnValue('a value');
jest.fn is a function which returns a jest.Mock type which can be considered as an function to create whatever you want:
const aMock = jest.fn().mockReturnValue(1) // <=> const aMock = () => 1;
// The difference is jest mock type can be used to assert then. Most of cases is to check
// whether it gets called or not

use jest mock functions to test code that calls another server

Roughly, my JavaScript function that I want to unit-test looks like this:
const request = require('request-promise-native');
async function callServer() {
// Prepare parameters
// Call `request` with parameters
// Parse response JSON and return
}
Is there any way to unit-test this function without making an actual call to the real server? Can I use a jest mock function to somehow override request()? To do that, will I need to modify every function to take the request function as a parameter or there is another way?
You can mock imported module via jest.mock. https://jestjs.io/docs/en/api#requirerequiremockmodulename
describe('main description', () => {
it('description of test case', () => {
jest.mock('request-promise-native', () => {
return {}; // Return what the request-promise-native supposed to return
});
const result = callServer();
expect(result).toBe({});
});
});

jest.fn() not recognized by expect as a spy function?

Error:
The "actual" argument in expect(actual).toHaveBeenCalled() must be a spy
Minimal not-working example:
const mockFn = jest.fn();
mockFn();
expect(mockFn).toHaveBeenCalled();
Question: is jest.fn() not a spy?
I tried the below implementation which worked for me,
it("should call mock function when button is clicked", () => {
const mockFn = jest.fn();
const tree = shallow(<button name="button test" handleHandler={mockFn} />);
tree.simulate("click");
mockFn();
expect(mockFn).toHaveBeenCalled();
});

Node sinon stub a chained function

So i have a piece of code:
General.helpers.elementContains = function(selector, value) {
return driver.findElement(webdriver.By.css(selector)).getInnerHtml().then(function(contents) {
assert.equal(contents, value);
});
};
I would like to stub out the getInnerHtml function. I have currently stubbed out both the driver.findElement and the webdriver.By.css functions. My driver.findElement function returns a promise which i use the node module sinon-stub-promise.
sinon.stub(driver, 'findElement').returnsPromise();
sinon.stub(webdriver.By, 'css');
However when running the test as i am unsure of how to stub the .getInnerHtml function i get an error:
driver.findElement(...).getInnerHtml is not a function
I have tried changing the driver.findElement to return a getInnerHtml method which is stubbed and returns a value but i cannot seem to crack this one.
sinon.stub(driver.findElement).returns({getInnerHtml: sinon.stub().returns(value)})
Any help would be appreciated.
I have figured out a solution to this question:
Stub promise
promise = sinon.stub().returnsPromise();
sinon.stub(driver, 'findElement').returns({getInnerHtml: promise});
This works for me as getInnerHtml returns a promise and driver.findElement returns a object with getInnerHtml in which is a function which returns a promise.