React hooks not setting state while testing using jest - reactjs

I have a react component
const Upload = (props) => {
const [fileName, setFileName] = useState("no file chosen")
function handleFile(e) {
const [sFile] = e.target.files;
setFileName(sFile.name);
}
const chooseFile = (
<label>
<input id="file-upload" type="file" accept=".pdf, application/pdf" onChange={handleFile} />
choose_file
</label>
<label className='file-text'>
{fileName}
</label>
);
return (
<React.Fragment>
{chooseFile}
</React.Fragment>
);
};
I have this test for checking the value change of state fileName, so that it displays the name of the file chosen
beforeEach(() => {
wrapper = shallow(<Upload />);
});
describe('Choose File', () => {
const mockedFile = 'application.pdf';
const event = {
target: {
files: [{ name: 'application.pdf' }]
}
};
it('displays the file name when a file is selected', () => {
wrapper.find('#file-upload').simulate('change', event);
wrapper.update();
expect(wrapper.find('label').at(1).text()).toEqual(mockedFile);
});
}
But the output is always "no file chosen". Any help would be appreciated.

Your code works fine for me.
index.tsx:
import React, { useState } from 'react';
export const Upload = props => {
const [fileName, setFileName] = useState('no file chosen');
function handleFile(e) {
const [sFile] = e.target.files;
setFileName(sFile.name);
}
return (
<React.Fragment>
<label>
<input id="file-upload" type="file" accept=".pdf, application/pdf" onChange={handleFile} />
choose_file
</label>
<label className="file-text">{fileName}</label>
</React.Fragment>
);
};
index.spec.tsx:
import React from 'react';
import { shallow } from 'enzyme';
import { Upload } from './';
let wrapper;
beforeEach(() => {
wrapper = shallow(<Upload />);
});
describe('Choose File', () => {
const mockedFile = 'application.pdf';
const event = {
target: {
files: [{ name: 'application.pdf' }]
}
};
it('displays the file name when a file is selected', () => {
wrapper.find('#file-upload').simulate('change', event);
wrapper.update();
expect(
wrapper
.find('label')
.at(1)
.text()
).toEqual(mockedFile);
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/58793061/index.spec.tsx
Choose File
✓ displays the file name when a file is selected (12ms)
-----------|----------|----------|----------|----------|-------------------|
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: 3.924s
dependencies versions:
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
"jest": "^24.9.0",
"jest-environment-enzyme": "^7.1.1",
"jest-enzyme": "^7.1.1",
"react": "^16.11.0",
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58793061

Related

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

React test onChange on input using react shallow-renderer

I'm trying to test searchForm component of React with onChange prop.
const SearchForm = () => {
const [value, setValue] = useState('');
return (
<form className={styles.searchForm}>
<input
value={value}
onChange={(e) => setValue(e.target.value)} // test this line
className={styles.searchForm__input}
/>
<button type="submit" aria-label="Search" className={styles.searchForm__button} />
</form>
);
};
Here is example of my test:
import React from 'react';
import ShallowRenderer from 'react-test-renderer/shallow';
import SearchForm from '../index';
const setUp = () => {
const renderer = new ShallowRenderer();
renderer.render(<SearchForm />);
return renderer.getRenderOutput();
};
describe('render form component', () => {
it('handle onChange in form input field', () => {
const result = setUp();
expect(result).toMatchSnapshot();
});
});
This test passes, but JEST says that this line of code (with onChange) is uncovered.
I found how to launch onChange:
result.props.children[0].props.onChange();
This launches original prop but i get error on e.target -- cannot read property of undefined.
I feel like i need to mock setValue somehow, but i can't figure out how. I'm new to JEST.
Maybe this may be done with just react-test-renderer in better way.
Here is the solution:
index.tsx:
import React, { useState } from 'react';
export const SearchForm = () => {
const [value, setValue] = useState('');
return (
<form>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<button type="submit" aria-label="Search" />
</form>
);
};
index.test.tsx:
import React from 'react';
import TestRenderer, { act } from 'react-test-renderer';
import ShallowRenderer from 'react-test-renderer/shallow';
import { SearchForm } from './';
describe('66907704', () => {
it('should handle onChange event', () => {
const testRenderer = TestRenderer.create(<SearchForm />);
const testInstance = testRenderer.root;
expect(testInstance.findByType('input').props.value).toEqual('');
const mEvent = { target: { value: 'teresa teng' } };
act(() => {
testInstance.findByType('input').props.onChange(mEvent);
});
expect(testInstance.findByType('input').props.value).toEqual('teresa teng');
});
it('should handle onChange event when use shallow render', () => {
const shallowRenderer = ShallowRenderer.createRenderer();
shallowRenderer.render(<SearchForm />);
let tree = shallowRenderer.getRenderOutput();
let input = tree.props.children[0];
const mEvent = { target: { value: 'teresa teng' } };
input.props.onChange(mEvent);
tree = shallowRenderer.getRenderOutput();
input = tree.props.children[0];
expect(input.props.value).toEqual('teresa teng');
});
});
unit test result:
PASS examples/66907704/index.test.tsx (6.636 s)
66907704
✓ should handle onChange event (10 ms)
✓ should handle onChange event when use shallow render (1 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: 2 passed, 2 total
Snapshots: 0 total
Time: 7.443 s
package versions:
"jest": "^26.6.3",
"react": "^16.14.0",

Assert onBlur() funciton in functional component jest

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

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

Failed React Jest Test when Expecting Mock Function to be called

Okay i've uploaded an even more straight forward example. I just can't get mock functions to be called when they are located inside of a helper function. Not sure what i'm doing wrong.
class TodoSearch extends Component {
handleSearch = () => {
const searchInput = this.searchInput.value;
// passed down from parent component
this.props.onSearch(searchInput);
};
handleCheckbox = e => {
const showCompleted = e.target.checked;
// passed down from parent component
this.props.onCheckbox(showCompleted);
};
render() {
return (
<form>
<FormGroup>
<FormControl
type="search"
className="todoSearchInput"
placeholder="Search"
inputRef={input => (this.searchInput = input)}
onChange={this.handleSearch}
/>
<Checkbox checked={this.props.checked} onChange={this.handleCheckbox}>
Show completed todos
</Checkbox>
</FormGroup>
</form>
);
}
}
export default TodoSearch;
So i'm using Jest and Enzyme as thus, the 'shallow'. This is what i've successful done so far
import React from 'react';
import { shallow } from 'enzyme';
import renderer from 'react-test-renderer';
import TodoSearch from './TodoSearch';
describe(TodoSearch, () => {
const searchText = 'Buy Milk';
const mockOnSearch = jest.fn();
const component = shallow(<TodoSearch onSearch={mockOnSearch} />);
it('should exist', () => {
const component = renderer.create(<TodoSearch />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
it('contains the form', () => {
expect(component.find('form')).toHaveLength(1);
expect(component.find('Checkbox')).toHaveLength(1);
expect(component.find('.todoSearchInput')).toHaveLength(1);
});
});
How can i test that onSearch inside the handleSearch is run? Tried a bunch of ways but just not getting it. Any help greatly appreciated.
Here is the solution, I simplify your component, remove the unrelated part.
dependencies:
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"jest": "^24.8.0",
"react": "^16.9.0",
TodoSearch.tsx:
import React, { Component } from 'react';
import console = require('console');
interface ITodoSearchProps {
onSearch(input): any;
onCheckbox(value): any;
}
class TodoSearch extends Component<ITodoSearchProps> {
private searchInput: HTMLInputElement | null = null;
constructor(props: ITodoSearchProps) {
super(props);
}
public handleSearch = () => {
if (this.searchInput) {
const searchInput = this.searchInput.value;
console.log('searchInput: ', searchInput);
// passed down from parent component
this.props.onSearch(searchInput);
}
}
public handleCheckbox = e => {
const showCompleted = e.target.checked;
// passed down from parent component
this.props.onCheckbox(showCompleted);
}
public render() {
return (
<form>
<input
type="search"
className="todoSearchInput"
placeholder="Search"
onChange={this.handleSearch}
ref={input => (this.searchInput = input)}
/>
</form>
);
}
}
export default TodoSearch;
TodoSearch.spec.tsx:
import React from 'react';
import TodoSearch from './TodoSearch';
import { mount } from 'enzyme';
describe('TodoSearch', () => {
const mockOnSearch = jest.fn();
const mockOnCheckbox = jest.fn();
it('should handle search correctly', () => {
const searchInput = 'jest';
const wrapper = mount(<TodoSearch onSearch={mockOnSearch} onCheckbox={mockOnCheckbox}></TodoSearch>);
(wrapper.find('input').instance() as any).value = searchInput;
wrapper.find('input').simulate('change');
expect(mockOnSearch).toBeCalledWith(searchInput);
});
});
Unit test result with coverage report:
PASS src/stackoverflow/47493126/TodoSearch.spec.tsx
TodoSearch
✓ should handle search correctly (50ms)
searchInput: jest
----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------------|----------|----------|----------|----------|-------------------|
All files | 90 | 75 | 83.33 | 88.89 | |
TodoSearch.tsx | 90 | 75 | 83.33 | 88.89 | 24,26 |
----------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.846s, estimated 6s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47493126

Resources