Skip to content
Advertisement

Jest redux saga API call with response image

I’m trying to test a fetch that responds with a readable stream for an image, but I’m stuck and not sure how to approach this specific case. Is there a simple, easy way to mock the call’s response?

Any help would be appreciated 😀

The generator function looks like the following:

export function* getImageSaga () {

    try {
        const headers = {
            Accept: 'image/jpeg',
        };
        const options = {
            headers,
            method: 'GET',
        };

        const response = yield call(fetch, GET_IMAGE_API, options);
        const blob = yield response.blob();
        const url = URL.createObjectURL(blob);
        yield put(getImageSuccess(url));
    } catch (error) {
        yield put(getImageError(error));
    }
}

Advertisement

Answer

You can use testing the saga generator function step-by-step approach.

Before testing the saga generator function, you need to be aware of these things:

  1. jsdom doesn’t support fetch yet, see issue#1724

  2. jsdom doesn’t support URL.createObjectURL API yet, see issue#1721

  3. By default, jestjs uses jsdom as a test environment to simulate the browser-like environment.

So I will use isomorphic-fetch polyfill for fetch, and mock URL.createObjectURL() API and its return value. Besides, you can also use the Response() constructor to create your own custom Response object:

const response = new Response();

We will use this custom response object as the mock return value of fetch.

The test will be:

index.ts:

import { call, put } from 'redux-saga/effects';

export const getImageSuccess = (payload) => ({ type: 'GET_IMAGE_SUCCESS', payload });
export const getImageError = (payload) => ({ type: 'GET_IMAGE_ERROR', payload });
export const GET_IMAGE_API = 'http://localhost:3000/api/image';

export function* getImageSaga() {
  try {
    const headers = {
      Accept: 'image/jpeg',
    };
    const options = {
      headers,
      method: 'GET',
    };

    const response = yield call(fetch, GET_IMAGE_API, options);
    const blob = yield response.blob();
    const url = URL.createObjectURL(blob);
    yield put(getImageSuccess(url));
  } catch (error) {
    yield put(getImageError(error));
  }
}

index.test.ts:

import { call, put } from 'redux-saga/effects';
import { getImageSaga } from './';

describe('72521882', () => {
  test('should get image success', () => {
    const objectUrl = 'blob:https://yari-demos.prod.mdn.mozit.cloud/8b065c5a-fd18-44d8-9ff5-5c29407a88b7';
    Object.defineProperty(window.URL, 'createObjectURL', { value: () => objectUrl });

    const gen = getImageSaga();

    expect(gen.next().value).toEqual(
      call(fetch, 'http://localhost:3000/api/image', {
        headers: {
          Accept: 'image/jpeg',
        },
        method: 'GET',
      }),
    );
    const mResponse = new Response();
    gen.next(mResponse);

    expect(gen.next().value).toEqual(put({ type: 'GET_IMAGE_SUCCESS', payload: objectUrl }));
  });
});

Test result:

 PASS   redux-saga-examples  packages/redux-saga-examples/src/stackoverflow/72521882/index.test.ts
  72521882
    ✓ should get image success (4 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   88.89 |      100 |   66.67 |   91.67 |                   
 index.ts |   88.89 |      100 |   66.67 |   91.67 | 22                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.648 s

jest.setup.js:

import 'isomorphic-fetch';

jest.setTimeout(10 * 1000);

jest.config.js:

{
  setupFilesAfterEnv: ['./jest.setup.js']
}
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement