import * as React from 'react'; import { useState, useEffect } from 'react'; import { render, act } from '@testing-library/react'; import expect from 'expect'; import { useDataProvider } from './useDataProvider'; import { CoreAdminContext } from '../core'; import { GetListResult } from '..'; const UseGetOne = () => { const [data, setData] = useState(); const [error, setError] = useState(); const dataProvider = useDataProvider(); useEffect(() => { dataProvider .getOne('posts', { id: 1 }) .then(res => setData(res.data)) .catch(e => setError(e)); }, [dataProvider]); if (error) return
{error.message}
; if (data) return
{JSON.stringify(data)}
; return
loading
; }; const UseGetList = () => { const [data, setData] = useState(); const [error, setError] = useState(); const dataProvider = useDataProvider(); useEffect(() => { dataProvider .getList('posts', { pagination: { page: 1, perPage: 10 }, sort: { field: 'id', order: 'ASC' }, filter: {}, }) .then(({ data, total }) => setData({ data, total })) .catch(e => setError(e)); }, [dataProvider]); if (error) return
{error.message}
; if (data) return
{JSON.stringify(data)}
; return
loading
; }; const UseGetCustom = () => { const [data, setData] = useState(); const [error, setError] = useState(); const dataProvider = useDataProvider(); useEffect(() => { dataProvider .getCustom('posts', { id: 1 }) .then(res => setData(res.result)) .catch(e => setError(e)); }, [dataProvider]); if (error) return
{error.message}
; if (data) return
{JSON.stringify(data)}
; return
loading
; }; describe('useDataProvider', () => { it('should return a way to call the dataProvider', async () => { const getOne = jest.fn(() => Promise.resolve({ data: { id: 1, title: 'foo' } }) ); const dataProvider = { getOne }; const { queryByTestId } = render( ); expect(queryByTestId('loading')).not.toBeNull(); await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(getOne).toBeCalledTimes(1); expect(queryByTestId('loading')).toBeNull(); expect(queryByTestId('data').textContent).toBe( '{"id":1,"title":"foo"}' ); }); it('should handle async errors in the dataProvider', async () => { jest.spyOn(console, 'error').mockImplementationOnce(() => {}); const getOne = jest.fn(() => Promise.reject(new Error('foo'))); const dataProvider = { getOne }; const { queryByTestId } = render( ); expect(queryByTestId('loading')).not.toBeNull(); await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(getOne).toBeCalledTimes(1); expect(queryByTestId('loading')).toBeNull(); expect(queryByTestId('error').textContent).toBe('foo'); }); it('should throw a meaningful error when the dataProvider throws a sync error', async () => { const c = jest.spyOn(console, 'error').mockImplementation(() => {}); const getOne = jest.fn(() => { throw new Error('foo'); }); const dataProvider = { getOne }; const r = () => render( ); expect(r).toThrow( new Error( 'The dataProvider threw an error. It should return a rejected Promise instead.' ) ); c.mockRestore(); }); it('should call custom verbs with standard signature (resource, payload, options)', async () => { const UseCustomVerbWithStandardSignature = () => { const [data, setData] = useState(); const [error, setError] = useState(); const dataProvider = useDataProvider(); useEffect(() => { dataProvider .customVerb('posts', { id: 1 }) .then(res => setData(res.data)) .catch(e => setError(e)); }, [dataProvider]); if (error) return
{error.message}
; if (data) return
{JSON.stringify(data)}
; return
loading
; }; const customVerb = jest.fn(() => Promise.resolve({ data: null })); const dataProvider = { customVerb }; render( ); // waitFor for the dataProvider to return await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(customVerb).toHaveBeenCalledWith('posts', { id: 1 }); }); it('should accept calls to custom verbs with no arguments', async () => { const UseCustomVerbWithNoArgument = () => { const [data, setData] = useState(); const [error, setError] = useState(); const dataProvider = useDataProvider(); useEffect(() => { dataProvider .customVerb() .then(res => setData(res.data)) .catch(e => setError(e)); }, [dataProvider]); if (error) return
{error.message}
; if (data) return
{JSON.stringify(data)}
; return
loading
; }; const customVerb = jest.fn(() => Promise.resolve({ data: null })); const dataProvider = { customVerb }; render( ); // waitFor for the dataProvider to return await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(customVerb).toHaveBeenCalledWith(); }); it('should accept custom arguments for custom verbs', async () => { const UseCustomVerb = () => { const [data, setData] = useState(); const [error, setError] = useState(); const dataProvider = useDataProvider(); useEffect(() => { dataProvider .customVerb({ id: 1 }, ['something']) .then(res => setData(res.data)) .catch(e => setError(e)); }, [dataProvider]); if (error) return
{error.message}
; if (data) return
{JSON.stringify(data)}
; return
loading
; }; const customVerb = jest.fn(() => Promise.resolve({ data: null })); const dataProvider = { customVerb }; render( ); // waitFor for the dataProvider to return await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(customVerb).toHaveBeenCalledWith({ id: 1 }, ['something']); }); it('should call getList and not show error', async () => { const getList = jest.fn(() => Promise.resolve({ data: [{ id: 1, title: 'foo' }], total: 1 }) ); const dataProvider = { getList }; const { queryByTestId } = render( ); expect(queryByTestId('loading')).not.toBeNull(); await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(getList).toBeCalledTimes(1); expect(queryByTestId('loading')).toBeNull(); expect(queryByTestId('data')?.textContent).toBe( '{"data":[{"id":1,"title":"foo"}],"total":1}' ); }); it('should call getList and show error', async () => { jest.spyOn(console, 'error').mockImplementation(() => {}); const getList = jest.fn(() => Promise.resolve({ data: [{ id: 1, title: 'foo' }] }) ); const dataProvider = { getList }; const { queryByTestId } = render( ); expect(queryByTestId('loading')).not.toBeNull(); await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(getList).toBeCalledTimes(1); expect(queryByTestId('loading')).toBeNull(); expect(queryByTestId('error')?.textContent).toBe( 'ra.notification.data_provider_error' ); }); it('should call custom and not show error', async () => { const getCustom = jest.fn(() => Promise.resolve({ result: [{ id: 1, title: 'foo' }] }) ); const dataProvider = { getCustom }; const { queryByTestId } = render( ); expect(queryByTestId('loading')).not.toBeNull(); await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(getCustom).toBeCalledTimes(1); expect(queryByTestId('loading')).toBeNull(); expect(queryByTestId('data')?.textContent).toBe( '[{"id":1,"title":"foo"}]' ); expect(queryByTestId('error')?.textContent).toBeUndefined(); }); it('should return array or object when 401', async () => { const results = [] as any[]; const doSomethingWithResult = (arg: any) => results.push(arg); const UseDataProvider = () => { const dataProvider = useDataProvider(); useEffect(() => { async function callDataProvider() { doSomethingWithResult( (await dataProvider.getList('posts', { filter: { id: 1 }, })) as any ); doSomethingWithResult( (await dataProvider.getMany('posts', { filter: { id: 1 }, })) as any ); doSomethingWithResult( (await dataProvider.getOne('posts', { filter: { id: 1 }, })) as any ); doSomethingWithResult( (await dataProvider.getManyReference('posts', { filter: { id: 1 }, })) as any ); } callDataProvider(); }, [dataProvider]); return
loading
; }; const dataProvider = { getMany: () => Promise.reject({ status: 401 }), getList: () => Promise.reject({ status: 401 }), getOne: () => Promise.reject({ status: 401 }), getManyReference: () => Promise.reject({ status: 401 }), }; render( Promise.reject(true), checkAuth: () => Promise.reject(true), logout: () => Promise.resolve(false), }} > ); // waitFor for the dataProvider to return await act(async () => { await new Promise(resolve => setTimeout(resolve)); }); expect(results).toEqual([ { data: [] }, { data: [] }, { data: {} }, { data: [] }, ]); }); });