Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue: two axios calls in tested function but only one (first) response ever can be referenced #58

Closed
barteklecki opened this issue Aug 19, 2020 · 2 comments

Comments

@barteklecki
Copy link

Hi guys, thanks for cool lib!

I'm trying to test async service that is returning response object and includes few intertwined API calls (axios with interceptors). Right now I'm using jest-mock-axios lib:

(I removed irrelevant parts of code, originally written in TS)

// services/persons.js
import personsAgent from '../agents/persons';
import places from './places';
[...]
const get = async ({ search = '', limit, offset }) => { 
  const places = await places.get({ search: '', limit: 1000, offset: 0 });  // api call to endpoint url '/places/'
  const params = {
    search: !!search.length ? search : null,
    limit,
    offset,
  };
  [...]
  return personsAgent.getAll({ ...params }).then(resp => {
    const results = sort(resp.data.results, .....).map((person, i) => {
      const place = places?.data?.results.filter(.....);

      return {
        id: person.id,
        name: person.first_name,
        surname: person.last_name,
        place,
      };
    });

    return {
      data: { ...resp.data, results },
      status: resp.status,
    };
  });
};
[....]
export default {
  get,
};
// agents/persons.js
import requests from '../utils/axios'; 
export default {
  getAll: (params: object) => requests.get('/persons/', { params }),
}
// services/persons.test.js
import mockAxios from 'jest-mock-axios';
import persons from './persons';

afterEach(() => {
  mockAxios.reset();
});

it('returns Persons data from API', async () => {
    let catchFn = jest.fn(),
      thenFn = jest.fn();

    persons
      .get({ search: '', limit: 10, offset: 0 })
      .then(thenFn)
      .catch(catchFn);

    expect(mockAxios.get).toHaveBeenCalledWith('/persons/', {
      params: { search: null, limit: 10, offset: 0 },
    }); // FAIL - received: '/places/', { search: null, limit: 1000, offset: 0 }

    let responseObj = {
      data: {
        results: ['test'],
      },
    };

    mockAxios.mockResponse(responseObj);

    expect(thenFn).toHaveBeenCalledWith({
      data: {
        results: ['test'],
      },
      status: 200,
    });

    expect(catchFn).not.toHaveBeenCalled();
  });

I'm using axios mock and for my others, simpler tests of services but without additional, internal calls and everything is working fine, but this one is problematic.
How to ignore or mock const places = await places.get() to focus on personsAgent.getAll()?
Issue right now is that I'm testing request for const places = await places.get() and there is no secondary request for personsAgent.getAll().
axios.getReqByUrl('/persons/') // = null

Any ideas? Thx in advance!

@kingjan1999
Copy link
Collaborator

kingjan1999 commented Aug 19, 2020

Hi,

thank you for reporting! It looks like this is a duplicate of #46 and #44, but I'll look deeper into this tomorrow on Friday and see what we can do about it, as it comes up regularly here.

@kingjan1999
Copy link
Collaborator

Hi,

so I looked further into this:

You need to mock a (dummy) response for the first request (places.get) as well. Obviously the code can't proceed further until there is some kind of result from this call as it might be needed for a subsequent call.

So modifying your code, this should work:

it('returns Persons data from API', async () => {
    let catchFn = jest.fn(),
      thenFn = jest.fn();

    persons
      .get({ search: '', limit: 10, offset: 0 })
      .then(thenFn)
      .catch(catchFn);

   mockAxios.mockResponse({data: '<whatever is needed here>'}); // mock first call
   // might need to flush promises here
    
    expect(mockAxios.get).toHaveBeenCalledWith('/persons/', {
      params: { search: null, limit: 10, offset: 0 },
    }); // FAIL - received: '/places/', { search: null, limit: 1000, offset: 0 }

    let responseObj = {
      data: {
        results: ['test'],
      },
    };

    mockAxios.mockResponse(responseObj);

    expect(thenFn).toHaveBeenCalledWith({
      data: {
        results: ['test'],
      },
      status: 200,
    });

    expect(catchFn).not.toHaveBeenCalled();
  });

Please test and report back; closing this for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants