Assert onBlur() funciton in functional component jest - reactjs

I wrote a test case to call onBlur method, but I'm getting an error when I try to assert it. Here is the above test case.
it("call the handlingBlurEmail method", () => {
const wrapper = mount(
<App childRef={() => {}} />
);
const comp = wrapper.find({ id: "email" }).first();
comp.prop("onBlur")({
target: { id: "email", value: "test#gmail.com" }
});
expect(
wrapper
.find("AccountForm")
.state()
.onBlur()
).toHaveBeenCalled();
});
and the function for which I'm writing test case is
mailReference = React.createRef();
handlingEmailBlur = events => {
this.mailReference.current.validate(events.target.value);
};
render = () {
......
return (
<div className="Form1">
onBlur={this.handlingEmailBlur}
</div>
)
.....
}
Please let me know how to add assert statement in order to call the onBlur() method in the above test case

Here is the unit testing solution:
index.tsx:
import React, { Component } from 'react';
class App extends Component {
mailReference = React.createRef();
handlingEmailBlur = (events) => {
this.mailReference.current.validate(events.target.value);
};
render() {
return (
<div className="Form1" onBlur={this.handlingEmailBlur}>
some component
</div>
);
}
}
export default App;
index.spec.tsx:
import App from './index';
import { mount } from 'enzyme';
import React from 'react';
describe('59455504', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('call the handlingBlurEmail method', () => {
const mailReference = { current: { validate: jest.fn() } };
jest.spyOn(React, 'createRef').mockReturnValue(mailReference);
const wrapper = mount(<App childRef={() => {}} />);
const mEvent = {
target: { id: 'email', value: 'test#gmail.com' },
};
wrapper.find('.Form1').prop('onBlur')(mEvent);
expect(mailReference.current.validate).toBeCalledWith(mEvent.target.value);
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/59455504/index.spec.jsx (8.328s)
59455504
✓ call the handlingBlurEmail method (40ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.jsx | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.769s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59455504

Related

Jest React: How to mock window eventListener set in componentDidMount

Here I need to add tests for handleBeforeUnload in window eventListener but I am getting error, How will I resolve it?
expect(jest.fn())[.not].toHaveBeenCalled()
Matcher error: received value must be a mock or spy function
Received has value: undefined
map.beforeunload();
expect(wrapper.handleBeforeUnload).toHaveBeenCalled();
My component
componentDidMount() {
window.addEventListener('beforeunload', (event) => {
this.handleBeforeUnload();
});
}
handleBeforeUnload () {
}
My test spec:
it('should call handleBeforeUnload', () => {
const historyMock = { listen: jest.fn(), replace: jest.fn() };
const map = {};
window.addEventListener = jest.fn((event, cb) => {
map[event] = cb;
});
const wrapper = shallow(
<AppRoutes history={historyMock} getDctkConfig={getDctkConfig} />,
);
map.beforeunload();
expect(wrapper.handleBeforeUnload).toHaveBeenCalled();
});
You didn't spy the.handleBeforeUnload() method of the component class. You can spy it through Component.prototype.handleBeforeUnload. Besides, you can mock the implementation of the .addEventListener() method and invoke the listener function manually.
index.tsx:
import React, { Component } from 'react';
export default class AppRoutes extends Component {
componentDidMount() {
window.addEventListener('beforeunload', (event) => {
this.handleBeforeUnload();
});
}
handleBeforeUnload() {}
render() {
return <div>app routes</div>;
}
}
index.test.tsx:
import { shallow } from 'enzyme';
import React from 'react';
import AppRoutes from './';
describe('69346085', () => {
afterEach(() => {
jest.restoreAllMocks();
});
test('should pass', () => {
const handleBeforeUnloadSpy = jest.spyOn(AppRoutes.prototype, 'handleBeforeUnload');
jest
.spyOn(window, 'addEventListener')
.mockImplementation((type: string, listener: EventListenerOrEventListenerObject) => {
typeof listener === 'function' && listener({} as Event);
});
shallow(<AppRoutes />);
expect(handleBeforeUnloadSpy).toHaveBeenCalled();
});
});
test result:
PASS examples/69346085/index.test.tsx (9.191 s)
69346085
✓ should pass (7 ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.tsx | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.814 s, estimated 10 s

Simulate change on input does not call a function

I learning to write unit tests in React. The test should check if an onChange function is called when there is a change in the input field. This is my simple search bar component:
import {Input} from './Input';
const SearchBar = (props) => {
return (
<Input
type="search"
data-test="search"
onChange={e => props.onSearch(e.target.value)} />
);
};
export default SearchBar;
The test I wrote is supposed to simulate a change on input field, what in turn should invoke a function call.
describe('Search', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('Should call onSearch function', () => {
const wrapper = mount(<SearchBar onSearch={onSearch}/>);
const searchBar = wrapper.find('[data-test=search]').at(0);
searchBar.simulate('change', {target: { 'test' }});
expect(onSearch).toBeCalledTimes(1);
});
});
Here, instead of being called 1 time, the function is not called at all. I cannot figure out why. Can you explain where am I making a mistake?
You should create a mocked onSearch using jest.fn(). The CSS selector should be '[data-test="search"]'.
E.g.
SearchBar.tsx:
import React from 'react';
function Input(props) {
return <input {...props} />;
}
const SearchBar = (props) => {
return <Input type="search" data-test="search" onChange={(e) => props.onSearch(e.target.value)} />;
};
export default SearchBar;
SearchBar.test.tsx:
import { mount } from 'enzyme';
import React from 'react';
import SearchBar from './SearchBar';
describe('Search', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('Should call onSearch function', () => {
const onSearch = jest.fn();
const wrapper = mount(<SearchBar onSearch={onSearch} />);
const searchBar = wrapper.find('[data-test="search"]').at(0);
searchBar.simulate('change', { target: { value: 'test' } });
expect(onSearch).toBeCalledTimes(1);
});
});
test result:
PASS examples/68669299/SearchBar.test.tsx (7.33 s)
Search
✓ Should call onSearch function (47 ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
SearchBar.tsx | 100 | 100 | 100 | 100 |
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.002 s, estimated 9 s

How to mock and test scrollBy with Jest and React-Testing-Library?

Given the following component:
import * as React from "react";
import "./styles.css";
export default function App() {
const scrollContainerRef = React.useRef<HTMLDivElement | null>(null);
const handleClick = () => {
scrollContainerRef?.current?.scrollBy({ top: 0, left: 100 });
};
return (
<div aria-label="wrapper" ref={scrollContainerRef}>
<button onClick={handleClick}>click</button>
</div>
);
}
How do I write a test using Jest and React Testing library to check that when the button is clicked, scrollBy is triggered on the wrapper?
I have tried the following and it doesn't seem to be working:
test('Clicking on button should trigger scroll',() => {
const myMock = jest.fn();
Object.defineProperty(HTMLElement.prototype, 'scrollBy', {
configurable: true,
value: myMock(),
})
render(<MyComponent />)
fireEvent.click(screen.getByText(/click/i))
expect(myMock).toHaveBeenCalledWith({top: 0, left: 100})
})
Since jsdom does NOT implements Element.scrollBy() method, see PR. We can create a mocked ref object with getter and setter to intercept React's assignment process to ref.current, and install spy or add mock in the process.
E.g.
App.tsx:
import * as React from 'react';
export default function App() {
const scrollContainerRef = React.useRef<HTMLDivElement | null>(null);
const handleClick = () => {
scrollContainerRef?.current?.scrollBy({ top: 0, left: 100 });
};
return (
<div aria-label="wrapper" ref={scrollContainerRef}>
<button onClick={handleClick}>click</button>
</div>
);
}
App.test.tsx:
import React, { useRef } from 'react';
import { render, screen, fireEvent } from '#testing-library/react';
import { mocked } from 'ts-jest/utils';
import App from './App';
jest.mock('react', () => {
return {
...jest.requireActual<typeof React>('react'),
useRef: jest.fn(),
};
});
const useMockRef = mocked(useRef);
describe('63702104', () => {
afterAll(() => {
jest.resetAllMocks();
});
test('should pass', () => {
const ref = { current: {} };
const mScrollBy = jest.fn();
Object.defineProperty(ref, 'current', {
set(_current) {
if (_current) {
_current.scrollBy = mScrollBy;
}
this._current = _current;
},
get() {
return this._current;
},
});
useMockRef.mockReturnValueOnce(ref);
render(<App />);
fireEvent.click(screen.getByText(/click/i));
expect(mScrollBy).toBeCalledWith({ top: 0, left: 100 });
});
});
test result:
PASS examples/63702104/App.test.tsx (9.436 s)
63702104
✓ should pass (33 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 75 | 100 | 100 |
App.tsx | 100 | 75 | 100 | 100 | 7
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.21 s

How to mock a React Component static method with Jest

This was really hard to find out how to do. I could not find any code to show you how to mock a static method in a React Component. This way worked for me.
// YourComponent.js
class YourComponent extends Component {
static getHelloWorld () {
return 'hello world';
}
render() {
return (
<div>{YourComponent.getHelloWorld()}</div>
)
}
}
export default YourComponent;
// YourComponent.test.js
import { mount } from 'enzyme';
import YourComponent from './YourComponent';
YourComponent.__proto__.getHelloWorld = jest.fn(() => { return 'Hello Universe' });
describe('YourComponent test for mocking static method', () => {
it('should render', () => {
const wrapper = mount(<YourComponent />);
expect(wrapper.text()).toEqual('Hello Universe');
});
});
Here is the solution:
index.js:
import { Component } from 'react';
class YourComponent extends Component {
static getHelloWorld() {
return 'hello world';
}
render() {
return <div>{YourComponent.getHelloWorld()}</div>;
}
}
export default YourComponent;
index.test.js:
import { mount } from 'enzyme';
import YourComponent from './';
describe('YourComponent test for mocking static method', () => {
it('should render', () => {
YourComponent.getHelloWorld = jest.fn(() => {
return 'Hello Universe';
});
const wrapper = mount(<YourComponent />);
expect(wrapper.text()).toEqual('Hello Universe');
});
});
unit test result with coverage report:
PASS stackoverflow/61022182/index.test.js (8.455s)
YourComponent test for mocking static method
✓ should render (30ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 88.89 | 100 | 66.67 | 87.5 |
index.js | 88.89 | 100 | 66.67 | 87.5 | 5
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.327s

e.target.parentNode.getAttribute("id") / e.targe.getAttribute("id") unit test jest enzyem

Does anyone have a jest/enzyme test example for event.target.getAttribute?
handleButtonsClicks = () => {
if(e.target.parentNode.getAttribute("id")=== "id1") {
//
} else if (e.target.getAttribute("id") === "id2") {
//
}
}
<Button id="id1" onClick={handleButtonsClicks}/>
<Button id="id2" onClick={handleButtonsClicks}/>
Thanks
Here is a completed demo:
index.tsx:
import React, { Component } from 'react';
class SomeComponent extends Component {
constructor(props) {
super(props);
this.handleButtonsClicks = this.handleButtonsClicks.bind(this);
}
handleButtonsClicks(e) {
if (e.target.parentNode.getAttribute('id') === 'id1') {
console.log('do something');
} else if (e.target.getAttribute('id') === 'id2') {
console.log('do another thing');
}
}
render() {
return (
<div>
<button id="id1" onClick={this.handleButtonsClicks}>
Button 1
</button>
<button id="id2" onClick={this.handleButtonsClicks}>
Button 2
</button>
</div>
);
}
}
export default SomeComponent;
index.spec.tsx:
import React from 'react';
import { shallow } from 'enzyme';
import SomeComponent from './';
describe('SomeComponent', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<SomeComponent></SomeComponent>);
jest.restoreAllMocks();
});
test('should handle button click', () => {
const logSpy = jest.spyOn(console, 'log');
expect(wrapper.find('button')).toHaveLength(2);
const mEvent = { target: { parentNode: { getAttribute: jest.fn().mockReturnValueOnce('id1') } } };
wrapper.find('#id1').simulate('click', mEvent);
expect(logSpy).toBeCalledWith('do something');
expect(mEvent.target.parentNode.getAttribute).toBeCalledWith('id');
});
test('should handle button click', () => {
const logSpy = jest.spyOn(console, 'log');
expect(wrapper.find('button')).toHaveLength(2);
const mEvent = {
target: {
getAttribute: jest.fn().mockReturnValueOnce('id2'),
parentNode: { getAttribute: jest.fn() }
}
};
wrapper.find('#id1').simulate('click', mEvent);
expect(logSpy).toBeCalledWith('do another thing');
expect(mEvent.target.getAttribute).toBeCalledWith('id');
});
});
Unit test result:
PASS src/stackoverflow/58457004/index.spec.tsx
SomeComponent
✓ should handle button click (16ms)
✓ should handle button click (3ms)
console.log node_modules/jest-mock/build/index.js:860
do something
console.log node_modules/jest-mock/build/index.js:860
do another thing
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 83.33 | 100 | 100 | |
index.tsx | 100 | 83.33 | 100 | 100 | 12 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.139s, estimated 8s

Resources