I am writing a react-redux
app and in one of my action creators I am making an api request via axios
Roughly, it looks something like this:
import axios from 'axios'
export function getStoredData(userInput) {
.
.
.
var url = generateURL(userInput);
var response = axios.get(url);
return {
type: GET_STORED_DATA
payload: repsonse;
};
}
I wanted to mock axios using axios-mock-adapter but I don't quite understand how to do that, especially since I wouldn't want to modify my action creator
for the test.
Please suggest any resources/guide to doing this...
You can use dependency injection to swap the http client, eg.
// your api module
var httpClient
export function getStoredData(userInput) {
.
.
.
var url = generateURL(userInput);
var response = httpClient.get(url);
return {
type: GET_STORED_DATA
payload: repsonse;
};
}
export default function init(client) {
httpClient = client
}
// init it when your program starts and the use it (should be a singleton instance in the app)
import Api, { getStoredData } from './api'
import axios from 'axios'
Api.init(axios)
getStoredData('user input')
//in your test
import Api, { getStoredData } from './api'
import axiosMock from 'axios-mock-adapter'
Api.init(axiosMock)
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import moxios from 'moxios';
import {
submitRegistrationStepOneForm, // <-- this is an action that returns returns a promise
} from '../RegistrationActions';
const USER_ID = 999;
const USER_EMAIL = 'lucky_star@milkyway.test';
const userDataForStepOne = { email: USER_EMAIL };
const responseForUserRequest = { content: { id: USER_ID } };
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
describe('Registration action tests for form', () => {
beforeEach(() => moxios.install());
afterEach(() => moxios.uninstall());
it('submitRegistrationStepOneForm success should trigger correct dispatches', () => {
const initialState = {};
const store = mockStore(initialState);
// simplest way is to use a regex to match url
moxios.stubRequest(/users.*/, {
status: 201, // <-- you can replace this with a 5xx to test failure cases
response: responseForUserRequest,
});
return store.dispatch(submitRegistrationStepOneForm({
userData: userDataForStepOne,
}))
.then(() => {
// in my case I used to run 2 dispatches on success call:
const actions = store.getActions();
expect(actions.length).toEqual(2);
expect(actions[0]).toEqual({ type: 'SUBMIT_REGISTRATION_FORM_DATA' });
expect(actions[1]).toEqual({
type: 'SUBMIT_REGISTRATION_STEP_ONE_SUCCESS',
payload: { userId: USER_ID },
});
// ... more tests here if needed
});
});
// ....
the submitRegistrationStepOneForm action:
export const submitRegistrationStepOneForm = ({ userData, sourceArticle }) => {
return (dispatch) => {
dispatch(submitRegistrationDataAction());
// signUpStepOne can be replaced directly with the axios promise
return signUpStepOne({ userData })
.then((body) => {
const { content: { id } } = body;
// ... some function calls and 2 dispatches here like:
// dispatch(registrationSuccess({ userId: id }));
})
.catch((error) => {
console.log('step one error', error); // eslint-disable-line
dispatch(registrationFailureAction());
});
};
};