import * as React from 'react'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import expect from 'expect'; import { testDataProvider } from '../../dataProvider/testDataProvider'; import { CoreAdminContext } from '../../core'; import { useReferenceManyFieldController } from './useReferenceManyFieldController'; import { memoryStore } from '../../store'; import { Basic, defaultDataProvider, } from './useReferenceManyFieldController.stories'; const ReferenceManyFieldController = props => { const { children, page = 1, perPage = 25, ...rest } = props; const controllerProps = useReferenceManyFieldController({ page, perPage, ...rest, }); return children(controllerProps); }; describe('useReferenceManyFieldController', () => { it('should set isLoading to true when related records are not yet fetched', async () => { const ComponentToTest = ({ isLoading }: { isLoading?: boolean }) => { return
isLoading: {isLoading?.toString()}
; }; const dataProvider = testDataProvider({ getManyReference: () => Promise.resolve({ data: [], total: 0 }), }); render( {props => } ); expect(screen.queryByText('isLoading: true')).not.toBeNull(); await waitFor(() => { expect(screen.queryByText('isLoading: false')).not.toBeNull(); }); }); it('should set isLoading to false when related records have been fetched and there are results', async () => { const ComponentToTest = ({ isLoading }: { isLoading?: boolean }) => { return
isLoading: {isLoading?.toString()}
; }; const dataProvider = testDataProvider({ getManyReference: () => Promise.resolve({ data: [ { id: 1, title: 'hello' }, { id: 2, title: 'world' }, ], total: 2, }) as any, }); render( {props => } ); expect(screen.queryByText('isLoading: true')).not.toBeNull(); await waitFor(() => { expect(screen.queryByText('isLoading: false')).not.toBeNull(); }); }); it('should call dataProvider.getManyReferences on mount', async () => { const dataProvider = testDataProvider({ getManyReference: jest .fn() .mockResolvedValue({ data: [], total: 0 }), }); render( {() => 'null'} ); await waitFor(() => { expect(dataProvider.getManyReference).toHaveBeenCalledWith( 'books', { id: 123, target: 'author_id', pagination: { page: 1, perPage: 25 }, sort: { field: 'id', order: 'DESC' }, filter: {}, signal: undefined, } ); }); }); it('should pass data to children function', async () => { const children = jest.fn().mockReturnValue('children'); const dataProvider = testDataProvider({ getManyReference: () => Promise.resolve({ data: [ { id: 1, title: 'hello' }, { id: 2, title: 'world' }, ], total: 2, }) as any, }); render( {children} ); await waitFor(() => { expect(children).toHaveBeenCalledWith( expect.objectContaining({ data: [ { id: 1, title: 'hello' }, { id: 2, title: 'world' }, ], total: 2, hasPreviousPage: false, hasNextPage: false, }) ); }); }); it('should handle partial pagination', async () => { const children = jest.fn().mockReturnValue('children'); const dataProvider = testDataProvider({ getManyReference: () => Promise.resolve({ data: [ { id: 1, title: 'hello' }, { id: 2, title: 'world' }, ], pageInfo: { hasPreviousPage: false, hasNextPage: false, }, }) as any, }); render( {children} ); await waitFor(() => { expect(children).toHaveBeenCalledWith( expect.objectContaining({ total: undefined, hasPreviousPage: false, hasNextPage: false, }) ); }); }); it('should support custom source', async () => { const dataProvider = testDataProvider({ getManyReference: jest .fn() .mockResolvedValue({ data: [], total: 0 }), }); render( {() => 'null'} ); await waitFor(() => { expect(dataProvider.getManyReference).toHaveBeenCalledWith( 'books', { id: 'jamesjoyce256', target: 'author_id', pagination: { page: 1, perPage: 25 }, sort: { field: 'id', order: 'DESC' }, filter: {}, signal: undefined, } ); }); }); it('should call crudGetManyReference when its props changes', async () => { const dataProvider = testDataProvider({ getManyReference: jest .fn() .mockResolvedValue({ data: [], total: 0 }), }); const ControllerWrapper = props => ( {() => 'null'} ); const { rerender } = render(); expect(dataProvider.getManyReference).toBeCalledTimes(1); rerender(); await waitFor(() => { expect(dataProvider.getManyReference).toBeCalledTimes(2); expect(dataProvider.getManyReference).toHaveBeenCalledWith( 'books', { id: 123, target: 'author_id', pagination: { page: 1, perPage: 25 }, sort: { field: 'id', order: 'ASC' }, filter: {}, signal: undefined, } ); }); }); it('should take only last change in case of a burst of setFilters calls (case of inputs being currently edited)', async () => { const childFunction = ({ setFilters, filterValues }) => ( { setFilters({ q: event.target.value }, undefined, true); }} /> ); const dataProvider = testDataProvider({ getManyReference: jest .fn() .mockResolvedValue({ data: [], total: 0 }), }); render( {childFunction} ); const searchInput = screen.getByLabelText('search'); fireEvent.change(searchInput, { target: { value: 'hel' } }); fireEvent.change(searchInput, { target: { value: 'hell' } }); fireEvent.change(searchInput, { target: { value: 'hello' } }); await waitFor(() => new Promise(resolve => setTimeout(resolve, 600))); // Called twice: on load and on filter changes expect(dataProvider.getManyReference).toHaveBeenCalledTimes(2); expect(dataProvider.getManyReference).toHaveBeenCalledWith('books', { target: 'author_id', id: 123, filter: { q: 'hello' }, pagination: { page: 1, perPage: 25 }, sort: { field: 'id', order: 'DESC' }, meta: undefined, signal: undefined, }); }); it('should store selection state linked to referencing record', async () => { const store = memoryStore(); const setStore = jest.spyOn(store, 'setItem'); render( {({ onToggleItem }) => { return ( ); }} ); fireEvent.click(await screen.findByText('Toggle')); await waitFor(() => { expect(setStore).toHaveBeenCalledWith( 'authors.123.books.selectedIds', [456] ); }); }); it('should support custom storeKey', async () => { const store = memoryStore(); const setStore = jest.spyOn(store, 'setItem'); render( {({ onToggleItem }) => { return ( ); }} ); fireEvent.click(await screen.findByText('Toggle')); await waitFor(() => { expect(setStore).toHaveBeenCalledWith('customKey.selectedIds', [ 456, ]); }); }); describe('response metadata', () => { it('should return response metadata as meta', async () => { const dataProvider = testDataProvider({ getManyReference: () => Promise.resolve({ data: [ { id: 1, title: 'hello' }, { id: 2, title: 'world' }, ], total: 2, meta: { facets: [ { foo: 'bar', count: 1 }, { foo: 'baz', count: 2 }, ], }, }) as any, }); const ListMetadataInspector = () => { const listContext = useReferenceManyFieldController({ resource: 'authors', source: 'id', record: { id: 123, name: 'James Joyce' }, reference: 'books', target: 'author_id', }); return ( <> Response metadata:{' '}
{JSON.stringify(listContext.meta, null)}
); }; render( ); await screen.findByText( '{"facets":[{"foo":"bar","count":1},{"foo":"baz","count":2}]}' ); }); }); describe('onSelectAll', () => { it('should select all records', async () => { render(); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: []' ); }); fireEvent.click(await screen.findByText('Select All')); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: [0,1]' ); }); }); it('should select all records even though some records are already selected', async () => { render(); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: []' ); }); fireEvent.click(await screen.findByTestId('checkbox-1')); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: [1]' ); }); fireEvent.click(await screen.findByText('Select All')); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: [0,1]' ); }); }); it('should not select more records than the provided limit', async () => { const dataProvider = defaultDataProvider; const getManyReference = jest.spyOn( dataProvider, 'getManyReference' ); render(); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: []' ); }); fireEvent.click(await screen.findByText('Limited Select All')); await waitFor(() => { expect(screen.getByTestId('selected_ids').textContent).toBe( 'Selected ids: [0]' ); }); await waitFor(() => { expect(getManyReference).toHaveBeenCalledWith( 'books', expect.objectContaining({ pagination: { page: 1, perPage: 1 }, }) ); }); }); }); });