Typescript, тестирование вызовов Api в действиях Redux, имитирующий класс в Enzyme, Шутка

#reactjs #typescript #unit-testing #react-redux #jestjs

#reactjs #typescript #модульное тестирование #реагировать-redux #jestjs

Вопрос:

У меня проблема, из-за которой мне нужно издеваться над классом Api , который вызывается в моих действиях redux, этот класс вызывает axios get, post и т.д., Над которыми нужно издеваться. Я следовал этому руководству, объясняющему, как издеваться над axios, и этому руководству о том, как издеваться над классом, но, похоже, ни один из подходов не работает.

Теперь немного кода … вот пример типа действия, которое мне нужно протестировать.

 export const getAlldata = (id: string) => {
    return (dispatch: any) => {
        dispatch(beginAjaxRequest(id, types.BEGIN_GET_DATA_AJAX));
        return Api.get("/data/data").then((response: any) => {
            dispatch(getDataSuccess(response.data, id))
        }).catch((error) => {
            dispatch(handleAjaxError(id, new Alert({ id: id, title: "Error getting data", message: error.toString(), timestamp: Date.now(), error: true })));
        });
    }
}
  

и части Api этих вызовов.

 import axios from 'axios';

class Api {
    static get(path: string) {
        return axios({
            method: 'get',
            url: (global as any).apiDomain   path,
            headers: {
                Authorization: "Bearer "   (global as any).authentication.getToken(),
            "Content-Type": "application/json"
            }
        });
    }
}

export default Api;
  

Который я пытался имитировать в src / mocks / Api (два подчеркивания, следующие за и предшествующие mocks)

 import * as Promise from 'bluebird';
import { getTestData } from '../models/_tests/TestData';

class Api {
    static get(path: string) {
        switch (path) {
            case "/data/data":
                return Promise.resolve({
                    data: getTestData(3)
                });
            default:
                return {};
        }
    }
}

export default Api;
  

и настройка в моих setupTests.

 import * as Enzyme from 'enzyme';
import Api from './__mocks__/Api';
const Adapter = require("enzyme-adapter-react-16");

(global as any).Api = Api;

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

и вызывается в моем реальном тестировании…

 describe('thunk actions', () => {

    var middleware = [thunk];
    var mockStore = configureMockStore(middleware);
    afterAll(() => {
        cleanAll();
    });

    test('getAllData gets all data', (done: any) => {
        var store = mockStore({});
        jest.mock('../../api/Api'); // path to real Api
        var id = generateGuid();
        store.dispatch<any>((getAllData(id))).then(() => {
            done();
        });
    });
});
  

Очевидно, что на самом деле это ничего не тестирует, я просто пытаюсь заставить это работать, но я продолжаю получать ошибки в реальном Api вместо макета. Я также пробовал имитировать axios, но получаю ту же ошибку (не удается получить значение undefined), так что, похоже, это не заменяет ни axios, ни Api, кто-нибудь может увидеть, где я ошибаюсь?

Ответ №1:

Вы знаете, что облажались, когда отправляете вопрос в stackoverflow и получаете 0 ответов и 0 откликов в течение недели… Не идеально, но я нашел обходной путь для переопределения класса Api в моих thunk actions, вместо того, чтобы импортировать класс Api во все мои файлы действий и вызывать его напрямую, я теперь импортирую его только в корень моего проекта (App.tsx) и делаю его глобальным, как показано ниже (урезанный до минимума).

 import * as React from 'react';
import Api from './api/Api';

export interface State {

}

export interface Props {

}

export class App extends React.Component<Props, State> {

    state = {

    };

    componentWillMount = () => {
        (global as any).Api = Api;
    };





    public render() {
        return (
            <div>

            </div>
        );
    }
}


export default App;
  

… и затем вызываю Api для моих действий thunk, как показано ниже

 export const getAlldata = (id: string) => {
    return (dispatch: any) => {
        dispatch(beginAjaxRequest(id, types.BEGIN_GET_DATA_AJAX));
        return (global as any).Api.get("/data/data").then((response: any) => {
            dispatch(getDataSuccess(response.data, id))
        }).catch((error) => {
            dispatch(handleAjaxError(id, new Alert({ id: id, title: "Error getting data", message: error.toString(), timestamp: Date.now(), error: true })));
        });
    }
}
  

Затем просто переопределите это setupTests.ts

 import * as Enzyme from 'enzyme';
import Api from './__mocks__/Api';
const Adapter = require("enzyme-adapter-react-16");

(global as any).Api = Api;

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

… и тогда нет необходимости в jest mocks, просто вызывайте действия в ваших тестах и тестируйте.

Этот метод также будет работать за пределами Node, заменяя global на window . Это выполняет свою работу, но не идеально, поскольку я предпочитаю не использовать глобальное пространство имен, поэтому, если кто-нибудь знает способ получше, напишите подальше.