关于javascript:如何在Jest中测试axios?

How do I test axios in Jest?

我在React中有这个动作:

1
2
3
4
5
6
7
export function fetchPosts() {
    const request = axios.get(`${WORDPRESS_URL}`);
    return {
        type: FETCH_POSTS,
        payload: request
    }
}

在这种情况下如何测试Axios?

Jest在他们的网站上有一个用于使用仿函数的异步代码的用例,但是我可以使用Axios吗?

参考:异步示例

到目前为止,我已经进行了测试以测试它是否返回了正确的类型:

1
2
3
4
5
it('should dispatch actions with the correct type', () => {
    store.dispatch(fetchPosts());
    let action = store.getActions();
    expect(action[0].type).toBe(FETCH_POSTS);
});

如何传递模拟数据并测试其返回?


不使用任何其他库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import * as axios from"axios";

// Mock out all top level functions, such as get, put, delete and post:
jest.mock("axios");

// ...

test("good response", () => {
  axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
  // ...
});

test("bad response", () => {
  axios.get.mockImplementation(() => Promise.reject({ ... }));
  // ...
});

可以指定响应代码:

1
axios.get.mockImplementation(() => Promise.resolve({ status: 200, data: {...} }));

可以根据以下参数更改模拟:

1
2
3
4
5
6
7
axios.get.mockImplementation((url) => {
    if (url === 'www.example.com') {
        return Promise.resolve({ data: {...} });
    } else {
        //...
    }
});

Jest v23引入了一些语法糖来嘲笑Promises:

1
axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));

可以简化为

1
axios.get.mockResolvedValue({ data: {...} });

被拒绝的承诺也有一个等效项:mockRejectedValue

进一步阅读:

  • 开玩笑的嘲笑文档
  • GitHub上的讨论,它解释了jest.mock("axios")行的范围。
  • 我的另一个答案是解决将上述技术应用于Axios请求拦截器的问题。

我使用了axios-mock-adapter。
在这种情况下,服务在./chatbot中描述。
在模拟适配器中,您指定使用API??端点时返回的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import chatbot from './chatbot';

describe('Chatbot', () => {
    it('returns data when sendMessage is called', done => {
        var mock = new MockAdapter(axios);
        const data = { response: true };
        mock.onGet('https://us-central1-hutoma-backend.cloudfunctions.net/chat').reply(200, data);

        chatbot.sendMessage(0, 'any').then(response => {
            expect(response).toEqual(data);
            done();
        });
    });
});

您可以在此处看到整个示例:

服务:
https://github.com/lnolazco/hutoma-test/blob/master/src/services/chatbot.js

测试:
https://github.com/lnolazco/hutoma-test/blob/master/src/services/chatbot.test.js


我可以按照以下步骤进行操作:

  • 创建一个文件夹__mocks __ /(由@Januartha评论指出)
  • 实现一个axios.js模拟文件
  • 在测试中使用我实现的模块
  • 模拟将自动发生

    模拟模块示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    module.exports = {
        get: jest.fn((url) => {
            if (url === '/something') {
                return Promise.resolve({
                    data: 'data'
                });
            }
        }),
        post: jest.fn((url) => {
            if (url === '/something') {
                return Promise.resolve({
                    data: 'data'
                });
            }
            if (url === '/something2') {
                return Promise.resolve({
                    data: 'data2'
                });
            }
        }),
        create: jest.fn(function () {
            return this;
        })
    };


    我已经用nock做到了,就像这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import nock from 'nock'
    import axios from 'axios'
    import httpAdapter from 'axios/lib/adapters/http'

    axios.defaults.adapter = httpAdapter

    describe('foo', () => {
        it('bar', () => {
            nock('https://example.com:443')
                .get('/example')
                .reply(200, 'some payload')

            // test...
        })
    })


    对于那些希望使用axios-mock-adapter来代替Redux文档中的嘲讽示例进行异步测试的人,我成功使用了以下内容:

    文件actions.test.js:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    describe('SignInUser', () => {
      var history = {
        push: function(str) {
            expect(str).toEqual('/feed');
        }
      }

      it('Dispatches authorization', () => {
        let mock = new MockAdapter(axios);
        mock.onPost(`${ROOT_URL}/auth/signin`, {
            email: '[email protected]',
            password: 'test'
        }).reply(200, {token: 'testToken' });

        const expectedActions = [ { type: types.AUTH_USER } ];
        const store = mockStore({ auth: [] });

        return store.dispatch(actions.signInUser({
            email: '[email protected]',
            password: 'test',
          }, history)).then(() => {
            expect(store.getActions()).toEqual(expectedActions);
      });

    });

    为了在文件actions / index.js中测试signInUser的成功案例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    export const signInUser = ({ email, password }, history) => async dispatch => {
      const res = await axios.post(`${ROOT_URL}/auth/signin`, { email, password })
        .catch(({ response: { data } }) => {
            ...
      });

      if (res) {
        dispatch({ type: AUTH_USER });                 // Test verified this
        localStorage.setItem('token', res.data.token); // Test mocked this
        history.push('/feed');                         // Test mocked this
      }
    }

    鉴于这是在开玩笑,因此必须模拟localstorage调用。这在文件src / setupTests.js中:

    1
    2
    3
    4
    5
    6
    7
    const localStorageMock = {
      removeItem: jest.fn(),
      getItem: jest.fn(),
      setItem: jest.fn(),
      clear: jest.fn()
    };
    global.localStorage = localStorageMock;