I have a component which behaves like the following.
- Render, showing the 'Loading'.
- Fetch some data.
- Once that's loaded, populate the state.
- Rerender, showing that the data loaded.
The code is like this:
import React from 'react';
class IpAddress extends React.Component {
state = {
ipAddress: null
};
constructor(props) {
super(props);
this.fetchData();
}
fetchData() {
return fetch(`https://jsonip.com`)
.then((response) => response.json())
.then((json) => {
this.setState({ ipAddress: json.ip });
});
}
render() {
if (!this.state.ipAddress) return <p class="Loading">Loading...</p>;
return <p>Pretty fly IP address you have there.</p>
}
}
export default IpAddress;
This works fine. The Jest test is a struggle though. Using jest-fetch-mock works well.
import React from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';
import IpAddress from './IpAddress';
it ('updates the text when an ip address has loaded', async () => {
fetch.mockResponse('{ "ip": "some-ip" }');
const address = mount(<IpAddress />);
await address.instance().fetchData();
address.update();
expect(address.text()).toEqual("Pretty fly IP address you have there.");
});
It's a bit sad that I have to call await address.instance().fetchData(), just to make sure that the update has happened. Without this, the promise from fetch or the async nature of setState (I'm not sure which) don't run until after my expect; the text is left as "Loading".
Is this the sane way to test code like this? Would you write this code completely differently?
My problem has since escalated. I'm using a high order component, which means I can no longer do .instance() and use the methods on it - I'm not sure how to get back to my unwrapped IpAddress. Using IpAddress.wrappedComponent doesn't give me back the original IpAddress, like I expected.
This fails with the following error message, which I unfortunately don't understand.
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `WrapperComponent`.
create-react-appproject.await, but doingawait address.childAt(0).instance().fetchData();should allow you to test with the HOC applied.