Michal Kurz
Michal Kurz

Reputation: 2094

How to avoid re-running asynchronous API call for each Jest test case?

I want to write a test for an async function that fetches data from an external API.

Jest documentation tells me to return a promise for the test case like so:

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter')
  })
})

My problem with this approach is that it makes a separate fetchData call for each test case. But there is no guarantee that two API calls will return the same data, thus each test case might be running over a different data set.

I would like to make the fetchData call once and then run all my tests on the same response data - something like this:

describe('fetchData works as expected', () => {
  fetchData().then(data => {

    // test1
    test('the data is peanut butter', () => {
      expect(data).toBe('peanut butter')
    })

    // test2
    test('the data is peanut butter', () => {
      expect(data).toBe('peanut butter')
    })
  })
})

How do I do that?

Upvotes: 1

Views: 602

Answers (2)

user874639
user874639

Reputation: 163

You can use the setupFiles or setupFilesAfterEnv configuration options to run a function before all tests in all test files.

{
...
setupFiles: ['putYourFunctionHereOrBelow'],
setupFilesAfterEnv: ['./src/services/test/getApiTestResponse.ts'],
testMatch: ['<rootDir>/src/**/*.spec.ts'],
... 

}

You can also make your getApiTestResponse a singleton so that it only calls the API once

let peanutButterData;

export const getApiTestResponse = async () => {
 if (!peanutButterData) {
   peanutButterData = await fetchData().then(data => data)
 }
 return Promise.resolve(peanutButterData);
}

If you want to run the code once in each test file you can structure your file as

beforeAll(() => {
 const myPeanutButterData = getApiTestResponse();
});

describe('it does peanut butter things', () => {
  ...
});

Upvotes: 1

Ankit Agarwal
Ankit Agarwal

Reputation: 30729

You need to add a beforeAll block that will run only once for all the test cases. Thus, you can add your fetchData() function in that block and assign the result of fetchData() in a global variable which can then be accessed by all the test cases. Something like:

let fetchData;
beforeAll(() => {
  return fetchData().then(data => {
    fetchData = data;
  })
});

// test1
test('the data is peanut butter', () => {
  expect(fetchData).toBe('peanut butter')
})

// test2
test('the data is peanut butter', () => {
  expect(fetchData).toBe('peanut butter')
})

Upvotes: 2

Related Questions