import fetch from '../fetch'; import FetchMockBuilder, { MockRequestOptions, MockResponseOptions } from '../../../test/FetchMockBuilder'; import { NetworkResponse, Serializable } from '../../types'; interface FetchMock { builder: FetchMockBuilder mock: jest.Mock } const originalFetch = window.fetch; function fetchMock(req: MockRequestOptions, res: MockResponseOptions): FetchMock { const builder = new FetchMockBuilder(req, res); const mock: jest.Mock = builder.build(); window.fetch = mock; return { builder, mock }; } function getResponse(result: NetworkResponse): Serializable | undefined { if (result.ok) { return result.response; } return undefined; } function getError(result: NetworkResponse): Serializable | undefined { if (result.ok === false) { return result.error; } return undefined; } describe('fetch utility', () => { afterEach(() => { window.fetch = originalFetch; }); it('should perform a simple request', async () => { const responseBody = { name: 'John Doe' }; const url = 'https://api.flow.io/users/1'; fetchMock({ url }, { status: 200, body: responseBody }); const result = await fetch({ url }); expect(result.ok).toEqual(true); expect(result.status).toEqual(200); expect(getResponse(result)).toEqual(responseBody); }); it('should send request headers', async () => { const responseBody = { name: 'John Doe' }; const headers = { 'X-flow-token': 'token', 'X-flow-request-id': '27', }; const url = 'https://api.flow.io/users/1'; fetchMock({ url, headers }, { status: 200, body: responseBody }); const result = await fetch({ url, headers }); expect(result.ok).toEqual(true); expect(result.status).toEqual(200); expect(getResponse(result)).toEqual(responseBody); }); it('should map data to query parameters for GET requests', async () => { const queryObject = { limit: '1', offset: '25' }; const responseBody = [{ name: 'John Doe' }]; const url = 'https://api.flow.io/users'; fetchMock( { url: `${url}?limit=1&offset=25` }, { status: 200, body: responseBody }, ); const result = await fetch({ url, data: queryObject, }); expect(result.ok).toEqual(true); expect(result.status).toEqual(200); expect(getResponse(result)).toEqual(responseBody); }); it('should map data to query parameters for HEAD requests', async () => { const queryObject = { limit: '1', offset: '25' }; const url = 'https://api.flow.io/users'; fetchMock( { url: `${url}?limit=1&offset=25`, method: 'HEAD' }, { status: 200, body: '' }, ); const result = await fetch({ url, method: 'HEAD', data: queryObject, }); expect(result.ok).toEqual(true); expect(result.status).toEqual(200); expect(getResponse(result)).toEqual(''); }); it('should send data as JSON for POST requests', async () => { const requestBody = { firstName: 'John', lastName: 'Doe' }; const responseBody = { name: 'John Doe' }; const url = 'https://api.flow.io/users'; fetchMock( { url, method: 'POST', headers: { 'Content-Type': 'application/json', }, body: requestBody, }, { status: 201, body: responseBody }, ); const result = await fetch({ url: 'https://api.flow.io/users', method: 'POST', data: requestBody, }); expect(result.ok).toEqual(true); expect(result.status).toEqual(201); expect(getResponse(result)).toEqual(responseBody); }); it('should decorate non 2XX responses', async () => { const responseBody = { code: 'ENOTFOUND', messages: ['Resource requested is not found'], }; const url = 'https://api.flow.io/users/1'; fetchMock( { url }, { status: 404, body: responseBody }, ); const result = await fetch({ url: 'https://api.flow.io/users/1', }); expect(result.ok).toEqual(false); expect(result.status).toEqual(404); expect(getError(result)).toEqual(responseBody); }); it('should send enveloped request with option.envelope', async () => { const responseBody = { id: '123124545', username: 'Maggie', }; const testHeaders = { blah: 'hell-yeah', }; const url = 'https://api.flow.io/users/1'; fetchMock( { url: `${url}?envelope=request`, method: 'POST', body: { method: 'PUT', headers: { blah: ['hell-yeah'] }, body: { some: 'data' }, }, // headers were moved to the body for envelope use case headers: {}, }, { status: 201, body: responseBody }, ); const result = await fetch({ url: 'https://api.flow.io/users/1', envelope: true, method: 'PUT', data: { some: 'data' }, headers: testHeaders, }); expect(result.ok).toEqual(true); expect(result.status).toEqual(201); expect(getResponse(result)).toEqual(responseBody); }); });