3

I am writing test for my async action in react redux, for sake of addressing just the issue I simplified the code here. Here is my action function:

export function updateUserAuthenticationStatus(){
return function(dispatch){
   return axios.get(getLoginStatusUrl())
        .then(response => {
               const middlewares = [thunk];
               const mockStore = configureMockStore(middlewares);
               const store = mockStore();
    return store.dispatch(updateUserAuthenticationStatus()).then(()=>{
       //expect(store.getActions()[0]).to.eql(expectedActions);
    });
            });
        }).catch(function(response){
    });
  }
}

So the problem is the function getLoginStatusUrl() which does couple of checks in the cookie and return the appropriate url based on some conditions. So what I want is to mock this function to return for example test.com then I can test my action as follows:

it("", () => {
        **here I want to mock getLoginStatusUrl() to return test.com**
    nock("test.com")
        .get("/")
        .reply(200,"test detail");

})

How can I mock the getLoginStatusUrl() to return test.com in this scenario?

Hamed Minaee
  • 2,480
  • 4
  • 35
  • 63

2 Answers2

2

You don't need it to return test.com specifically. Use a library such as axios-mock-adapter. I haven't used it personaly but I'v used fetch-mock to mock fetch api requests so that concept should be exactly the same.

Lets say getLoginStatusUrl() returns /loginStatus, (because you haven't shown what it does return).

Example:

var axios = require('axios');
var MockAdapter = require('axios-mock-adapter');

// This sets the mock adapter on the default instance
var mock = new MockAdapter(axios);

// Mock any GET request to /users
// arguments for reply are (status, data, headers)
mock.onGet('/loginStatus').reply(200, {
  loginSuccess: true
});

axios.get('/loginStatus')
  .then(function(response) {
    console.log(response.data);
  });

The example code is untested but hopefuly you get the idea. Just read the library README.md.

In scenario's where you want to stub/mock out private imports that aren't used in axios requests like this you can use rewire or babel-plugin-rewire if you are using es6 syntax such as imports.

@HamedMinaee If you do not know the path at all, you can just do something like onGet('/'), it's all in the README.md. after the test I imagine their is a way to reset this so that not all tests using axios are affected by it.

afterEach(() => {
    // reset the axios mock here so that '/' doesn't affect all requests or something.
});
Martin Dawson
  • 7,455
  • 6
  • 49
  • 92
  • Thanks a lot for answering I will start looking into it and let you know about the result. Just a question: I have a function getLoginStatusUrl for getting the url and we do not know about the path at all but here in mock function we have onGet('/loginStatus') which we define the path '/loginStatus' how does it address this issue? – Hamed Minaee Aug 13 '17 at 18:45
  • Thanks a lot I am working on it and let you know about the result – Hamed Minaee Aug 13 '17 at 18:55
  • When I check the read me file for this: If you do not know the path at all, you can just do something like onGet('/') I cannot find anything. Am I missing sth? – Hamed Minaee Aug 13 '17 at 20:07
  • @HamedMinaee Or specify no path such as `onGet()`. That's in readme – Martin Dawson Aug 13 '17 at 20:13
2

Try this out with sinon.

import {getLoginStatusUrl} from './some/path.js'

let stub = sinon.stub(),
opts = { call: getLoginStatusUrl() };

stub.withExactArgs().returns("somePredefinedReturnValue")
Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
  • Thanks does this work if getLoginStatusUrl is a private function? – Hamed Minaee Aug 13 '17 at 18:46
  • export the function as an ES module like `export function getLoginStatusUrl() {...}`, then import it here. I assume that you do the same inside your action. – Ravindra Ranwala Aug 13 '17 at 18:48
  • Yeah but for sake of best practice in writing code is it a good idea to export a fuction because of test purpose? – Hamed Minaee Aug 13 '17 at 18:49
  • Normally we don't change the code just for testing. Are you calling a local function inside the action? If so you can export it as an ES module and import it in your test file. just add `export` at the beginning of the function definition. By the way if the function is local, then you can't even unit test it. – Ravindra Ranwala Aug 13 '17 at 18:51
  • @RavindraRanwala Instead of exporting it just use rewire which I linked in my answer if you are going to do this. – Martin Dawson Aug 13 '17 at 18:54
  • The best option is to pass it as props to the component. Then in your test you can pass props too like this. `_props = { prop1: 'value1', getLoginStatusUrl : (_spies.getLoginStatusUrl = sinon.spy()), } _wrapper = shallow()` – Ravindra Ranwala Aug 13 '17 at 19:01
  • @RavindraRanwala Can you please the the updated part: this is what I have in my test : return store.dispatch(updateUserAuthenticationStatus()).then(()=>{ //expect(store.getActions()[0]).to.eql(expectedActions); }); so if I use stub does it work on this part? – Hamed Minaee Aug 13 '17 at 19:12
  • question is not clear now. Why are you using mocks inside your actions? Please update the question so that I can understand your action and it's flow first. Did you try the suggested approach? – Ravindra Ranwala Aug 14 '17 at 03:06