diff --git a/src/lib/api.spec.ts b/src/lib/api.spec.ts index b553946d..9f9a3adc 100644 --- a/src/lib/api.spec.ts +++ b/src/lib/api.spec.ts @@ -1,30 +1,26 @@ -import nock from 'nock'; -import axios from 'axios'; +import nock from 'nock' +import axios from 'axios' -import { BaseAPI, RetryParams } from './api'; - -axios.defaults.adapter = require('axios/lib/adapters/http'); +import { BaseAPI, RetryParams } from './api' +axios.defaults.adapter = require('axios/lib/adapters/http') const urlTest = 'http://test.com' nock.disableNetConnect() describe('when making requests and the requests fail', () => { - beforeEach(() => { - nock(urlTest) .get('/test') .reply(500, {}) .defaultReplyHeaders({ - "Access-Control-Allow-Origin": "*" + 'Access-Control-Allow-Origin': '*' }) - }) describe('and there is one attempt left', () => { - let baseApi: BaseAPI; + let baseApi: BaseAPI beforeEach(() => { const retry: RetryParams = { attempts: 1, @@ -37,16 +33,18 @@ describe('when making requests and the requests fail', () => { .get('/test') .reply(500, {}) .defaultReplyHeaders({ - "Access-Control-Allow-Origin": "*" + 'Access-Control-Allow-Origin': '*' }) }) it('should retry 1 time and throw with the response error', async () => { - await expect(baseApi.request('get', '/test')).rejects.toThrowError("Request failed with status code 500") + await expect(baseApi.request('get', '/test')).rejects.toThrowError( + 'Request failed with status code 500' + ) expect(nock.isDone()).toBeTruthy() }) }) describe('and there are three attempts left', () => { - let baseApi: BaseAPI; + let baseApi: BaseAPI beforeEach(() => { const retry: RetryParams = { attempts: 3, @@ -60,16 +58,18 @@ describe('when making requests and the requests fail', () => { .times(3) .reply(500, {}) .defaultReplyHeaders({ - "Access-Control-Allow-Origin": "*" + 'Access-Control-Allow-Origin': '*' }) }) it('should retry 3 times and throw with the response error', async () => { - await expect(baseApi.request('get', '/test')).rejects.toThrowError("Request failed with status code 500") + await expect(baseApi.request('get', '/test')).rejects.toThrowError( + 'Request failed with status code 500' + ) expect(nock.isDone()).toBeTruthy() }) }) describe('and there are no attempts left', () => { - let baseApi: BaseAPI; + let baseApi: BaseAPI beforeEach(() => { const retry: RetryParams = { attempts: 0, @@ -80,12 +80,14 @@ describe('when making requests and the requests fail', () => { }) it('should throw an error', async () => { - await expect(baseApi.request('get', '/test')).rejects.toThrowError("Request failed with status code 500") + await expect(baseApi.request('get', '/test')).rejects.toThrowError( + 'Request failed with status code 500' + ) expect(nock.isDone()).toBeTruthy() }) }) describe('and there is one attempt left that succeeds', () => { - let baseApi: BaseAPI; + let baseApi: BaseAPI beforeEach(() => { const retry: RetryParams = { attempts: 1, @@ -98,18 +100,48 @@ describe('when making requests and the requests fail', () => { .get('/test') .reply(200, { data: 'my test data', ok: true }) .defaultReplyHeaders({ - "Access-Control-Allow-Origin": "*" + 'Access-Control-Allow-Origin': '*' }) }) it('should retry 1 time and resolve with the response data', async () => { - await expect(baseApi.request('get', '/test')).resolves.toEqual('my test data') + await expect(baseApi.request('get', '/test')).resolves.toEqual( + 'my test data' + ) expect(nock.isDone()).toBeTruthy() }) }) - describe('when making requests and the requests succeeds', () => { + describe('and send a retry on-demand in the request parameter', () => { + let baseApi: BaseAPI + let retry: RetryParams + + beforeEach(() => { + retry = { + attempts: 1, + delay: 10 + } + + baseApi = new BaseAPI(urlTest) + nock(urlTest) + .get('/test') + .reply(200, { data: 'my test data', ok: true }) + .defaultReplyHeaders({ + 'Access-Control-Allow-Origin': '*' + }) + }) + + it('should retry 1 time and resolve with the response data', async () => { + await expect( + baseApi.request('get', '/test', undefined, undefined, retry) + ).resolves.toEqual('my test data') + + expect(nock.isDone()).toBeTruthy() + }) + }) + + describe('when making requests and the requests succeeds', () => { let baseApi: BaseAPI beforeEach(() => { @@ -126,14 +158,15 @@ describe('when making requests and the requests fail', () => { .get('/test') .reply(201, { data: 'my test data', ok: true }) .defaultReplyHeaders({ - "Access-Control-Allow-Origin": "*" + 'Access-Control-Allow-Origin': '*' }) }) it('should resolve with the response data', async () => { - await expect(baseApi.request('get', '/test')).resolves.toEqual('my test data') + await expect(baseApi.request('get', '/test')).resolves.toEqual( + 'my test data' + ) expect(nock.isDone()).toBeTruthy() }) - }) }) diff --git a/src/lib/api.ts b/src/lib/api.ts index 4d936f05..3c0001df 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -34,8 +34,10 @@ export class BaseAPI { method: APIMethod, path: string, params: APIParam | null = null, - axiosRequestConfig: AxiosRequestConfig = {} + axiosRequestConfig: AxiosRequestConfig = {}, + retryParams?: RetryParams ) { + const retry = retryParams ?? this.retry let options: AxiosRequestConfig = { ...axiosRequestConfig, method, @@ -63,10 +65,10 @@ export class BaseAPI { `[API] HTTP request failed: ${error.message || ''}`, error ) - if (this.retry.attempts <= attempts) throw error + if (retry.attempts <= attempts) throw error attempts++ } - await this.sleep(this.retry.delay) + await this.sleep(retry.delay) } } diff --git a/src/lib/localStorage.spec.ts b/src/lib/localStorage.spec.ts index fa28e667..9687b667 100644 --- a/src/lib/localStorage.spec.ts +++ b/src/lib/localStorage.spec.ts @@ -5,27 +5,40 @@ import { getLocalStorage, getDefaultState } from './localStorage' -declare var global: any -let fakeStore = {} -global.window = {} describe('localStorage', function() { const migrations: Migrations = { 2: (data: any) => ({ ...data, data: 'new version' }) } + let fakeStore: Record + let localStorageSpy: jest.SpyInstance beforeEach(function() { fakeStore = {} - global.window['localStorage'] = { - getItem: (key: string) => fakeStore[key], - setItem: (key: string, value: string) => (fakeStore[key] = value), - removeItem: (key: string) => delete fakeStore[key] - } + + localStorageSpy = jest + .spyOn(global, 'localStorage', 'get') + .mockImplementation(() => { + return { + length: 0, + clear: () => {}, + key: (_index: number) => null, + getItem: (key: string) => fakeStore[key], + setItem: (key: string, value: string) => { + fakeStore[key] = value + }, + removeItem: (key: string) => delete fakeStore[key] + } + }) + }) + + afterEach(() => { + localStorageSpy.mockRestore() }) describe('hasLocalStorage', function() { it('should return false if localStorage is not available', function() { - delete global.window['localStorage'] + localStorageSpy.mockImplementation(() => null) expect(hasLocalStorage()).toBe(false) }) it('should return true if localStorage is available', function() {