#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 . Это выполняет свою работу, но не идеально, поскольку я предпочитаю не использовать глобальное пространство имен, поэтому, если кто-нибудь знает способ получше, напишите подальше.