import * as React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import expect from 'expect'; import { Route } from 'react-router-dom'; import { createMemoryHistory } from 'history'; import { useResourceDefinitions } from './useResourceDefinitions'; import { CoreAdminContext } from './CoreAdminContext'; import { CoreAdminRoutes } from './CoreAdminRoutes'; import { Resource } from './Resource'; import { CustomRoutes } from './CustomRoutes'; import { CoreLayoutProps } from '../types'; import { AuthProvider, ResourceProps } from '..'; const ResourceDefinitionsTestComponent = () => { const definitions = useResourceDefinitions(); if (!definitions) return null; return ( ); }; const MyLayout = ({ children }: CoreLayoutProps) => ( <> {children} ); const CatchAll = () =>
; const Loading = () => <>Loading; const Ready = () => <>Ready; const TestedComponent = ({ role }) => { const history = createMemoryHistory(); return ( {() => role === 'admin' ? [, ] : role === 'user' ? [] : [] } ); }; const TestedComponentReturningNull = ({ role }) => { const history = createMemoryHistory(); return ( {() => role === 'admin' ? [, ] : role === 'user' ? [] : null } ); }; const TestedComponentWithAuthProvider = ({ callback }) => { const history = createMemoryHistory(); const authProvider = { login: () => Promise.resolve(), logout: () => Promise.resolve(), checkAuth: () => Promise.resolve(), checkError: () => Promise.resolve(), getPermissions: () => Promise.resolve('admin'), }; return ( {callback} ); }; const ResourceWithPermissions = (props: ResourceProps) => ( ); ResourceWithPermissions.raName = 'Resource'; ResourceWithPermissions.registerResource = ( { create, edit, icon, list, name, options, show }: ResourceProps, permissions: any ) => ({ name, options, hasList: !!list && permissions && permissions[name]?.list, hasCreate: !!create && permissions && permissions[name]?.create, hasEdit: !!edit && permissions && permissions[name]?.edit, hasShow: !!show && permissions && permissions[name]?.show, icon, }); const TestedComponentWithPermissions = () => { const history = createMemoryHistory(); const authProvider: AuthProvider = { login: () => Promise.resolve(), logout: () => Promise.resolve(), checkAuth: () => Promise.resolve(), checkError: () => Promise.resolve(), getPermissions: () => Promise.resolve({ posts: { list: true, create: true, edit: true, show: true, }, comments: { list: true, create: false, edit: false, show: true, }, users: { list: true, create: false, edit: false, show: false, }, }), }; return ( } create={
} edit={
} show={
} /> } create={
} edit={
} show={
} /> } create={
} edit={
} show={
} /> ); }; const TestedComponentWithOnlyLazyCustomRoutes = ({ history }) => { const [lazyRoutes, setLazyRoutes] = React.useState(null); React.useEffect(() => { const timer = setTimeout( () => setLazyRoutes( Foo
} /> ), 500 ); return () => clearTimeout(timer); }, [setLazyRoutes]); return ( {lazyRoutes} ); }; const TestedComponentWithForcedRoutes = () => { const history = createMemoryHistory(); return ( } hasCreate hasEdit hasShow /> } /> {() => [} hasEdit />]} ); }; const expectResource = (resource: string) => expect(screen.queryByText(`"name":"${resource}"`, { exact: false })); const expectResourceView = ( resource: string, view: 'list' | 'create' | 'edit' | 'show' ) => expect( screen.queryByText( `"has${view.at(0).toUpperCase()}${view.substring(1)}":true`, { selector: `[data-resource=${resource}]`, exact: false, } ) ); describe('useConfigureAdminRouterFromChildren', () => { it('should always load static resources', async () => { render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); await waitFor(() => expectResource('posts').not.toBeNull()); expectResource('comments').not.toBeNull(); expectResource('user').toBeNull(); expectResource('admin').toBeNull(); }); it('should not call the children function until the permissions have been retrieved', async () => { const callback = jest.fn(() => Promise.resolve(resolve => setTimeout(resolve, 50)) ); render(); await waitFor(() => expect(callback).toHaveBeenCalled()); expect(callback).not.toHaveBeenCalledWith(undefined); }); it('should load dynamic resource definitions', async () => { render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResource('user').not.toBeNull(); expectResource('admin').not.toBeNull(); }); it('should accept function returning null', async () => { render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResource('user').not.toBeNull(); expectResource('admin').not.toBeNull(); }); it('should call registerResource with the permissions', async () => { render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResourceView('posts', 'list').not.toBeNull(); expectResourceView('posts', 'create').not.toBeNull(); expectResourceView('posts', 'edit').not.toBeNull(); expectResourceView('posts', 'show').not.toBeNull(); expectResourceView('comments', 'list').not.toBeNull(); expectResourceView('comments', 'create').toBeNull(); expectResourceView('comments', 'edit').toBeNull(); expectResourceView('comments', 'show').not.toBeNull(); expectResourceView('users', 'list').not.toBeNull(); expectResourceView('users', 'create').toBeNull(); expectResourceView('users', 'edit').toBeNull(); expectResourceView('users', 'show').toBeNull(); }); it('should allow adding new resource after the first render', async () => { const { rerender } = render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResource('posts').not.toBeNull(); expectResource('comments').not.toBeNull(); expectResource('user').not.toBeNull(); expectResource('admin').toBeNull(); rerender(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResource('posts').not.toBeNull(); expectResource('comments').not.toBeNull(); expectResource('user').not.toBeNull(); expectResource('admin').not.toBeNull(); }); it('should allow removing a resource after the first render', async () => { const { rerender } = render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResource('posts').not.toBeNull(); expectResource('comments').not.toBeNull(); expectResource('user').not.toBeNull(); expectResource('admin').not.toBeNull(); rerender(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResource('posts').not.toBeNull(); expectResource('comments').not.toBeNull(); expectResource('user').not.toBeNull(); expectResource('admin').toBeNull(); }); it('should allow dynamically loaded custom routes without any resources', async () => { const history = createMemoryHistory(); render(); expect(screen.queryByText('Ready')).not.toBeNull(); await new Promise(resolve => setTimeout(resolve, 1010)); expect(screen.queryByText('Ready')).toBeNull(); history.push('/foo'); expect(screen.queryByText('Foo')).not.toBeNull(); }); it('should support forcing hasEdit hasCreate or hasShow', async () => { render(); await waitFor(() => expect(screen.queryByText('Loading')).toBeNull()); expectResourceView('posts', 'list').not.toBeNull(); expectResourceView('posts', 'create').not.toBeNull(); expectResourceView('posts', 'edit').not.toBeNull(); expectResourceView('posts', 'show').not.toBeNull(); expectResourceView('comments', 'list').not.toBeNull(); expectResourceView('comments', 'create').toBeNull(); expectResourceView('comments', 'edit').toBeNull(); expectResourceView('comments', 'show').toBeNull(); expectResourceView('user', 'list').not.toBeNull(); expectResourceView('user', 'create').toBeNull(); expectResourceView('user', 'edit').not.toBeNull(); expectResourceView('user', 'show').toBeNull(); }); });