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 :D
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));
}
}
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 support fetch
yet, see issue#1724
jsdom
doesn't support URL.createObjectURL
API yet, see issue#1721
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']
}