i have an unit test to check if page is created well. But i have an problem. I define an empty array as users on constructor method and then assign an array with a method which is called on componentDidMount method. Everything works well when i test it myself on a device. But jest test throws error because of users array is undefined (i guess its impossible because i define it as [] at constructor method).
Part of Users.js;
export default class Users extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [],
firmId: 0,
key: 0,
isLoading: true,
};
}
componentDidMount() {
this.getData();
}
getData() {
return fetch("censored url" + this.state.firmId)
.then(response => response.json())
.then(responseJson => {
this.setState(
{
users: responseJson.users,
isLoading: false
},
function() {}
);
})
.catch(error => {
console.error(error);
});
}
Users.spec.js;
// other imports
import { users } from "../../jest/mock-data";
describe("<Users>", () => {
function func(){
return "2"
}
const navigation = { navigate: jest.fn(), getParam: func };
it('fetches data from server when server returns a successful response', done => { // 1
const mockSuccessResponse = users;
const mockJsonPromise = Promise.resolve(mockSuccessResponse); // 2
const mockFetchPromise = Promise.resolve({ // 3
json: () => mockJsonPromise,
});
jest.spyOn(global, 'fetch').mockImplementation(() => mockFetchPromise); // 4
const component = shallow(<Users navigation={navigation}/>); // 5
component.instance().setState({
users: [],
isLoading: false
});
expect(global.fetch).toHaveBeenCalledTimes(2); //success
expect(global.fetch).toHaveBeenCalledWith("censored url/2"); //success
process.nextTick(() => { // 6
expect(component.state()).toEqual({
users: users,
isLoading: false,
firmId: "2",
key: "2"
}); // THROWS ERROR
global.fetch.mockClear(); // 7
done(); // 8
});
});
});
I pointed the test which is throws error with THROWS ERROR comment.
Error on cmd;
● <Users> › fetches data from server when server returns a successful response
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
Object {
"firmId": "2",
"isLoading": false,
"key": "2",
- "users": Array [
- Object {
- "createdAt": 1547939031000,
- "email": "[email protected]",
- "firstName": "Test",
- "id": 5,
- "lastName": "User",
- "phone": "45454545454",
- "status": null,
- "updatedAt": 1547939031000,
- },
- ],
+ "users": undefined,
}
48 |
49 | process.nextTick(() => { // 6
> 50 | expect(component.state()).toEqual({
| ^
51 | users: users,
52 | isLoading: false,
53 | firmId: "2",
I guess component.instance().setState is not works well but i'm not sure. I will be glad if you know the answer and help me to fix that problem.
edit: I tried to add a new variable at setState function which is contains in test file. And when i test it on expect it worked well. So its just not working for users variable.
After setting the state we need to call the update on the instance so that it forces re render adn we have updated values in the state of the component.
component.instance().setState({
users: [],
isLoading: false
});
// Add this line
component.instance().update();
I solved that problem. Problem was about my mocking fetch way. I'm newbie and not good at mocking. I'm still not sure why but lifecycle methods was defining users variable as undefined. On this stackoverflow question's answer i saw and method to block lifecycle methods run when shallow function runs. So i used that method instead of mocking fetch and blocked lifecycle methods calls fetching function (i named it getData() on my project). And declared mocked data to users variable.
This is how to block lifecycle methods on shallow function;
const navigation = { navigate: jest.fn(), getParam: jest.fn() };
const component = shallow(<Users navigation={navigation}/>, { disableLifecycleMethods: true }); // 5
Navigation part is about to mocking react-navigation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With