简体   繁体   中英

How to Inject multiple mock promises to unit test the fetch in JS?

I'm trying to setup unit tests for the api calls in my JS project. Able to set it up for a single API call, using the following format

describe('Token refresh success', () => {
  beforeAll(() => {
    global.fetch = () =>
      Promise.resolve({
        json: () => Promise.resolve(mockTokenCreateSuccess),
      })
  })

  afterAll(() => {
    global.fetch = unmockedFetch
  })

  test('testTokenRefreshSuccess', async () => {
    const tokenData = await c.tokenRefresh();
    expect(tokenData.access_token).toEqual('SYoHdm4yw');
    expect(tokenData.refresh_token).toEqual('QxJ3yEgX4NThbTE66u7lshWTpQkRBilq');
  });
})

Now this format works great, and I can create individual tests by injecting one promise.

Now, there is a case I want to unit test where a particular API call is made twice. I need to inject fail response the first time, and success response the second time.

I tried the following approach, but did not work:

describe('Token refresh trigger as expected on create token fail', () => {
  beforeAll(() => {
    global.fetch = () => [
      Promise.resolve({
        json: () => Promise.reject(mockError(400)),
      }),
      Promise.resolve({
        json: () => Promise.resolve(mockTokenCreateSuccess),
      })
    ] 
  })

  afterAll(() => {
    global.fetch = unmockedFetch
  })

  test('testTokenRefreshTriggerOnTokenCreateFail', async () => {
    const tokenData = await c.tokenRefresh();
    expect(tokenData.access_token).toEqual('jkhjk');
    expect(tokenData.refresh_token).toEqual('dfdfdf');
  });
})

and my tokenRefresh() function is supposed to get called 2 times if it gets 400 error.

async tokenRefresh(retryCount = 0) {
        console.log('tokenRefresh');

        const request = this.getTokenRefreshRequest();
        try {
            const response = await this.fetchData(request);
            console.log('token refresh success', response);
            return { access_token, refresh_token };
        } catch (err) {
            if ((err.status == 400 || err.status == 401) && retryCount < 2) {
                await this.tokenRefresh(retryCount++);
            } else {
                throw new Error(`unable to refresh a token from API ${err.status}`);
            }
        }
    };

I'm able to verify that by using single promise

  Promise.resolve({
    json: () => Promise.reject(mockError(400)),
  })

the tokenRefresh() gets called again as expected, but in the second time I could not figure out how to pass the success promise, at the moment it fails the second time too.

I was able to find a working combination

beforeAll(() => {
    global.fetch = fetchMock.mockRejectOnce(customError) // makes sure first api call fails
    .mockResponseOnce(JSON.stringify(successResponse)) // makes sure second api call succeeds
  })

This made my test pass

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM