Reputation: 1362
I'm trying to test an async await function, however im getting an error.
● Should handle getGIF event › should handle getGIF event
expect(jest.fn()).toHaveBeenCalledTimes(1) Expected mock function to have been called one time, but it was called zero times.
I'm unsure how to test async await functions, so i was using this blog as an example https://medium.com/@rishabhsrao/mocking-and-testing-fetch-with-jest-c4d670e2e167
App.js
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import Card from './Card';
import PropTypes from "prop-types";
const Styles = {
marginTop: '100px',
inputStyle: {
borderRadius: '0px',
border: 'none',
borderBottom: '2px solid #000',
outline: 'none',
focus: 'none'
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
query: '',
title: undefined,
url: undefined
}
this.onChange = this.onChange.bind(this);
}
onChange(e) {
this.setState({query: e.target.value})
}
// testing this function
getGIY = async(e) => {
e.preventDefault();
const { query } = this.state;
await fetch(`http://api.giphy.com/v1/gifs/search?q=${query}&api_key=iBXhsCDYcnktw8n3WSJvIUQCXRqVv8AP&limit=5`)
.then(response => response.json())
.then(({ data }) => {
this.setState({
title: data[0].title,
url: data[0].images.downsized.url
});
})
.catch( (err) =>{
console.log(err)
});
}
render() {
return (
<div className="col-md-6 mx-auto" style={Styles}>
<h1 className="gif-title">Random GIF fetch</h1>
<form className="form-group" onSubmit={this.getGIY}>
<input
style={Styles.inputStyle}
className="form-control"
type="text"
value={this.state.query}
onChange={this.onChange}
placeholder="Search GIF..."/>
<button type="submit" className="btn btn-primary mt-4">Get GIF</button>
</form>
<Card title={this.state.title} url={this.state.url}/>
</div>
);
}
}
PropTypes.propTypes = {
onChange: PropTypes.func.isRequired,
getGIY:PropTypes.func.isRequired,
title:PropTypes.string.isRequired,
url:PropTypes.string.isRequired
}
export default App;
App.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import {shallow} from 'enzyme';
import App from './App';
describe('Should handle getGIF event', ()=> {
it('should handle getGIF event', done => {
const component = shallow(<App/>)
const mockSuccessResponse = {};
const mockJsonPromise = Promise.resolve(mockSuccessResponse);
const mockQuery = "Owl"
const mockFetchPromise = Promise.resolve({
json:() => mockJsonPromise,
});
jest.spyOn(global, 'fetch').mockImplementation(()=> mockFetchPromise);
expect(global.fetch).toHaveBeenCalledTimes(1);
expect(global.fetch).toHaveBeenCalledWith(`http://api.giphy.com/v1/gifs/search?q=${mockQuery}&api_key=iBXhsCDYcnktw8n3WSJvIUQCXRqVv8AP&limit=5`);
process.nextTick(() => { // 6
expect(component.state()).toEqual({
// ... assert the set state
});
global.fetch.mockClear(); // 7
done(); // 8
});
})
})
Upvotes: 2
Views: 1915
Reputation: 45780
You can test it like this:
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
describe('Should handle getGIF event', () => {
let mock, actualFetch;
beforeEach(() => {
mock = jest.fn();
actualFetch = global.fetch;
global.fetch = mock;
});
afterEach(() => {
global.fetch = actualFetch;
});
it('should handle getGIF event', async () => {
const component = shallow(<App />);
component.setState({ query: 'Owl' });
mock.mockResolvedValue({
json: () => Promise.resolve({
data: [{
title: 'the title',
images: { downsized: { url: 'the url' }}
}]
})
});
const form = component.find('form');
await form.props().onSubmit({ preventDefault: () => {} });
expect(mock).toHaveBeenCalledWith('http://api.giphy.com/v1/gifs/search?q=Owl&api_key=iBXhsCDYcnktw8n3WSJvIUQCXRqVv8AP&limit=5'); // Success!
expect(component.state('title')).toBe('the title'); // Success!
expect(component.state('url')).toBe('the url'); // Success!
});
});
Details
fetch
might not be defined in a Node.js environment so just grabbing whatever it was and replacing it with a mock, then restoring whatever it was is a good approach.
Use .setState
to set the component state.
Use .find
to get the form
and use .props
to access its props and call its onSubmit
function.
Use an async
test function and await
the Promise
returned by onSubmit
so it is completely done before continuing.
Use .state
to query the component state.
Upvotes: 1