简体   繁体   中英

React Jest/Enzyme: Mock/Override a Response of ES6 Class Method

I wanted to write a unit test (using Jest/Enzyme ) for login page which is written in React and I tried to Mock the server response , so I can test if the login form works correctly.

I have a React class component like this:

// LoginPage.js

export class LoginPage extends Component {

    // ...

    handleClick = async () => {
        
        const username = this.state.username;
        const password = this.state.password;

        const result = await callServer(username, password); // "fetch" used here

        console.log('Server Response:', result);

        if (result) // redirect

    };

    render() {
        return (
            <Wrapper> // Styled Components
                
                <Input type="text" id="loginUsername" ... />
                <Input type="password" id="loginPassword" ... />

                <Button onClick={this.handleClick}>
                    Submit
                </Button>

            </Wrapper>
        )
    }

}

export default withRouter(MyClass);

And my test file:

// LoginPage-test.js

import React from 'react';
import {configure, shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

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

import {LoginPage} from './LoginPage';
import Input from './Input';
import Button from './Button';

it('test the login page', async () => {

    const wrapper = shallow(<LoginPage/>),
          inputUsername = wrapper.find(Input).findWhere(n => n.prop('id') === 'loginUsername'),
          inputPassword = wrapper.find(Input).findWhere(n => n.prop('id') === 'loginPassword'),
          loginButton = wrapper.find(Button).findWhere(n => n.prop('children') === 'Submit');

    inputUsername.simulate('change', { target: { name: 'loginUsername', value: 'test_user' } });
    inputPassword.simulate('change', { target: { name: 'loginPassword', value: 'test_pass' } });

    const result = await loginButton.props().onClick();
    wrapper.update();

});

With this test I can see the Server Response ( console.log ) and the test passed. But I don't want to call the real server (as it's not a good practice in testing), instead I wanted to Mock the handleClick response.

I tried many ways, with spyOn , mockImplementation and so on without success. These are some of my tries:

// ------------------ (1) ---------------------

jest.doMock('./LoginPage', () => {
    return jest.fn().mockImplementation(() => {
        return {
            __esModule: true,
            ...(jest.requireActual(LoginPage)),
            LoginPage: {
                handleClick: async () => {
                    console.log('MOCK_TEST');
                    return new Promise.resolve('MOCK_TEST');
                }
            }
        };
    });
});

it('test the login page', async () => { ... });

// ------------------ (2) ---------------------

it('test the login page', async () => {
    
    // ...

    inputUsername.simulate('change', { target: { name: 'loginUsername', value: 'test_user' } });

    jest.spyOn(wrapper.instance(), 'handleClick').mockImplementation(() => {
        console.log('MOCK_TEST');
        return 'MOCK_TEST';
    });
    wrapper.update();

    // ...

});

// ------------------ (3) ---------------------

jest.mock(LoginPage, jest.fn());
LoginPage.mockImplementation(
    () => ({
        handleClick: () => {
            console.log('MOCK_TEST');
            return 'MOCK_TEST';
        }
    })
)

it('test the login page', async () => { ... });

Try

const handleClick = jest.spyOn(LoginPage.prototype, 'handleClick).
mockImplementation(() => {
    //your mock
}

and

expect(handleClick).toHaveBeenCalled();

Remember that jest.spyOn works only with normal functions and NOT with arrow functions. Also, you should set the spy before mounting your test component.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM