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:
jsdom
doesn’t supportfetch
yet, see issue#1724jsdom
doesn’t supportURL.createObjectURL
API yet, see issue#1721By default,
jestjs
usesjsdom
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'] }