From 803da1c532ba21d557b651e59c6f01e7f3af5a11 Mon Sep 17 00:00:00 2001 From: Ayush Sharma Date: Fri, 1 Nov 2019 07:18:55 +0100 Subject: [PATCH] fix: adds unit tests for api service (#235) * refactor: adds unit tests for api service * refactor: fix test dummy url --- jest/setup.ts | 2 + src/utils/api.test.ts | 116 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/jest/setup.ts b/jest/setup.ts index 8d54e3d..293e0ef 100644 --- a/jest/setup.ts +++ b/jest/setup.ts @@ -15,6 +15,8 @@ global.__APP_VERSION__ = '1.0.0'; // @ts-ignore : Property '__VERDACCIO_BASENAME_UI_OPTIONS' does not exist on type 'Global'. global.__VERDACCIO_BASENAME_UI_OPTIONS = {}; +global.VERDACCIO_API_URL = 'https://verdaccio.tld'; + const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock; customGlobal.fetch = require('jest-fetch-mock'); customGlobal.fetchMock = customGlobal.fetch; diff --git a/src/utils/api.test.ts b/src/utils/api.test.ts index fb7aef6..3eb81ad 100644 --- a/src/utils/api.test.ts +++ b/src/utils/api.test.ts @@ -1,4 +1,4 @@ -import { handleResponseType } from '../../src/utils/api'; +import api, { handleResponseType } from '../../src/utils/api'; describe('api', () => { describe('handleResponseType', () => { @@ -29,4 +29,118 @@ describe('api', () => { expect(handled).toEqual([true, blob]); }); }); + + describe('api client', () => { + let fetchSpy; + + beforeEach(() => { + fetchSpy = jest.spyOn(window, 'fetch'); + }); + + afterEach(() => { + fetchSpy.mockRestore(); + }); + + test('when there is no VERDACCIO_URL is defined', () => { + const { VERDACCIO_API_URL } = window; + delete window.VERDACCIO_API_URL; + // @ts-ignore + window.VERDACCIO_API_URL = undefined; + + expect(() => { + api.request('https://verdaccio.tld'); + }).toThrow(new Error('VERDACCIO_API_URL is not defined!')); + + window.VERDACCIO_API_URL = VERDACCIO_API_URL; + }); + + test('when url is a resource url', async () => { + fetchSpy.mockImplementation(() => + Promise.resolve({ + headers: new Headers({ + 'Content-Type': 'application/json', + }), + ok: true, + json: () => ({ a: 1 }), + }) + ); + + const response = await api.request('/resource'); + + expect(fetchSpy).toHaveBeenCalledWith('https://verdaccio.tld/resource', { + credentials: 'same-origin', + headers: {}, + method: 'GET', + }); + expect(response).toEqual({ a: 1 }); + }); + + test('when there is token from storage', async () => { + jest.resetModules(); + jest.doMock('./storage', () => ({ getItem: () => 'token-xx-xx-xx' })); + + fetchSpy.mockImplementation(() => + Promise.resolve({ + headers: new Headers({ + 'Content-Type': 'application/json', + }), + ok: true, + json: () => ({ c: 3 }), + }) + ); + + const api = require('../../src/utils/api').default; + const response = await api.request('/resource', 'GET'); + + expect(fetchSpy).toHaveBeenCalledWith('https://verdaccio.tld/resource', { + credentials: 'same-origin', + headers: { + Authorization: 'Bearer token-xx-xx-xx', + }, + method: 'GET', + }); + expect(response).toEqual({ c: 3 }); + }); + + test('when url is a cross origin url', async () => { + fetchSpy.mockImplementation(() => + Promise.resolve({ + headers: new Headers({ + 'Content-Type': 'application/json', + }), + ok: true, + json: () => ({ b: 2 }), + }) + ); + + const response = await api.request('https://verdaccio.xyz/resource'); + expect(fetchSpy).toHaveBeenCalledWith('https://verdaccio.xyz/resource', { + credentials: 'same-origin', + headers: {}, + method: 'GET', + }); + expect(response).toEqual({ b: 2 }); + }); + + test('when api returns an error 3.x.x - 4.x.x', async () => { + fetchSpy.mockImplementation(() => + Promise.resolve({ + headers: new Headers({ + 'Content-Type': 'application/json', + }), + ok: false, + json: () => {}, + }) + ); + + await expect(api.request('/resource')).rejects.toThrow(new Error('something went wrong')); + }); + + test('when api returns an error 5.x.x', async () => { + const errorMessage = 'Internal server error'; + fetchSpy.mockImplementation(() => Promise.reject(new Error(errorMessage))); + + await expect(api.request('/resource')).rejects.toThrow(new Error(errorMessage)); + }); + }); });