samedi 24 février 2018

Jest - why mocked function still calls old function?

I've got a Todo React Component that does an API call inside componentDidMount and once the data is loaded, it will display it on the screen. While loading a text informing user about fetching will be shown.

Here is my todo.test.js:

import React from 'react';
import ReactDOM from 'react-dom';
import renderer from 'react-test-renderer';
import { mount, shallow, render } from 'enzyme';
import Todo from '../components/Todo';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import toJson from 'enzyme-to-json';
import {getTodos} from '../helpers/todo';

Enzyme.configure({ adapter: new Adapter() });

const mockTodos = { data: [{
    "id": 4404,
    "status": "active",
    "text": "Shopping List"
}]};

jest.mock('../helpers/todo', () => ({
    getTodos: jest.fn(() => {
        return Promise.resolve(mockTodos);
    })
}));

describe('Todo', () => {
    it('works', () => {
        const component = mount(<Todo timeout={2000} />);
        expect(toJson(component)).toMatchSnapshot();

        component.find("button").simulate("click");
        expect(toJson(component)).toMatchSnapshot();
    });
});

here is my helpers/todo.js:

const mockTodos = { data: [{
    "id": 7727,
    "status": "completed",
    "text": "Mocked Completed Todo"
}]};

export const getTodos = () => {
    console.log("[][] Get Todos");

    return new Promise((resolve, reject) => {
        resolve(mockTodos);
    });
};

and here is my todo.js component:

import React from 'react';
import PropTypes from 'prop-types';
import TodoItem from './TodoItem';
import {getTodos} from '../helpers/todo';

class Todo extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            todos: [],
            error: false,
            loading: true
        };
        this.cancelAjaxRequests = false;
        this.callApi = this.callApi.bind(this);
    }

    callApi() {
        getTodos().then((json) => {
            if (!this.cancelAjaxRequests) {
                this.setState({
                    todos: json.data,
                    loading: false
                });
            }
        });
    }

    componentDidMount() {
        getTodos().then((json) => {
            if (!this.cancelAjaxRequests) {
                this.setState({
                    todos: json.data,
                    loading: false
                });
            }
        });
    }

    componentWillUnmount() {
        this.cancelAjaxRequests = true;
    }

    render() {
        let content;

        // TODO: add error handling

        if (this.state.loading) {
            return (
                <div>
                    <div>
                        <button id="update-data" onClick={this.callApi}>Update State</button>
                    </div>
                    <p>Todos are being fetched...</p>
                </div>
            );
        }

        return (
            content ||
            <div>
                <div>
                    <button id="update-data" onClick={this.callApi}>Update State</button>
                </div>
                <p><b>{this.state.todos.length}</b> todos fetched so far</p>
                {this.state.todos.map(
                    (todo) => <TodoItem key={todo.id} id={todo.id} status={todo.status} text={todo.text} />)}
            </div>
        );
    }
}

Todo.proptypes = {
    timeout: PropTypes.number
};

export default Todo;

When running the tests the message from console.log("[][] Get Todos"); is displayed.

Aren't mocks supposed to actually mock the given function and not to call the original one? Why is it calling my getTodos function?

Shouldn't only stick to return Promise.resolve(mockTodos); from jest.mock ?

Aucun commentaire:

Enregistrer un commentaire