From f018d0a31685003244c2be677845c6195646f2bd Mon Sep 17 00:00:00 2001 From: Simone Busoli Date: Wed, 23 Oct 2019 22:46:05 +0200 Subject: [PATCH] feat: async refetch Fixes #51 --- index.d.ts | 2 +- src/index.js | 6 ++-- src/index.test.js | 87 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/index.d.ts b/index.d.ts index 2fb93d7b..7d719ef2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -34,7 +34,7 @@ export default function useAxios( options?: Options ): [ ResponseValues, - (config?: AxiosRequestConfig, options?: RefetchOptions) => void + (config?: AxiosRequestConfig, options?: RefetchOptions) => AxiosPromise ] export function loadCache(data: any[]): void diff --git a/src/index.js b/src/index.js index d7ed24c0..d2cd6b8f 100644 --- a/src/index.js +++ b/src/index.js @@ -95,13 +95,15 @@ async function request(config, dispatch) { dispatch({ type: actions.REQUEST_START }) const response = await axiosInstance(config) dispatch({ type: actions.REQUEST_END, payload: response }) + return response } catch (err) { dispatch({ type: actions.REQUEST_END, payload: err, error: true }) + throw err } } function executeRequestWithCache(config, dispatch) { - request({ ...config, adapter: cacheAdapter }, dispatch) + return request({ ...config, adapter: cacheAdapter }, dispatch) } function executeRequestWithoutCache(config, dispatch) { @@ -138,7 +140,7 @@ export default function useAxios(config, options) { React.useEffect(() => { if (!options.manual) { - executeRequest(config, options, dispatch) + executeRequest(config, options, dispatch).catch(() => {}) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [stringifiedConfig]) diff --git a/src/index.test.js b/src/index.test.js index 9e73d444..56d5beff 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -36,24 +36,25 @@ it('should set the response', async () => { }) it('should reset error when request completes and returns data', async () => { - axios.mockResolvedValueOnce({ data: 'whatever' }) + const error = new Error('boom') - const { result, waitForNextUpdate } = renderHook(() => useAxios('')) + axios.mockRejectedValue(error) - result.current[0].error = { - isAxiosError: true, - config: {}, - name: '', - message: '' - } + const { result, waitForNextUpdate } = renderHook(() => useAxios('')) await waitForNextUpdate() + expect(result.current[0].error).toBe(error) + + axios.mockResolvedValue({ data: 'whatever' }) + // Refetch act(() => { result.current[1]() }) + await waitForNextUpdate() + expect(result.current[0].error).toBe(null) }) @@ -85,6 +86,76 @@ it('should refetch', async () => { expect(axios).toHaveBeenCalledTimes(2) }) +describe('refetch', () => { + describe('when axios resolves', () => { + it('should resolve to the response by default', () => { + const response = { data: 'whatever' } + + axios.mockResolvedValue(response) + + const { + result: { + current: [, refetch] + } + } = renderHook(() => useAxios('')) + + act(() => { + expect(refetch()).resolves.toEqual(response) + }) + }) + + it('should resolve to the response when using cache', () => { + const response = { data: 'whatever' } + + axios.mockResolvedValue(response) + + const { + result: { + current: [, refetch] + } + } = renderHook(() => useAxios('')) + + act(() => { + expect(refetch({}, { useCache: true })).resolves.toEqual(response) + }) + }) + }) + + describe('when axios rejects', () => { + it('should reject with the error by default', () => { + const error = new Error('boom') + + axios.mockRejectedValue(error) + + const { + result: { + current: [, refetch] + } + } = renderHook(() => useAxios('')) + + act(() => { + expect(refetch()).rejects.toEqual(error) + }) + }) + + it('should reject with the error by when using cache', () => { + const error = new Error('boom') + + axios.mockRejectedValue(error) + + const { + result: { + current: [, refetch] + } + } = renderHook(() => useAxios('')) + + act(() => { + expect(refetch({}, { useCache: true })).rejects.toEqual(error) + }) + }) + }) +}) + it('should return the same reference to the fetch function', async () => { axios.mockResolvedValue({ data: 'whatever' })