import * as React from 'react';
import expect from 'expect';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { onlineManager, QueryClient } from '@tanstack/react-query';
import { CoreAdminContext } from '../../core';
import {
ChoicesProps,
Form,
InputProps,
useChoices,
useChoicesContext,
useInput,
} from '../../form';
import { testDataProvider } from '../../dataProvider';
import { ReferenceInputBase } from './ReferenceInputBase';
import {
SelfReference,
QueryOptions,
Meta,
Offline,
} from './ReferenceInputBase.stories';
describe('', () => {
const defaultProps = {
reference: 'posts',
resource: 'comments',
source: 'post_id',
};
beforeAll(() => {
window.scrollTo = jest.fn();
});
beforeEach(() => {
onlineManager.setOnline(true);
});
it('should display an error if error is defined', async () => {
jest.spyOn(console, 'error')
.mockImplementationOnce(() => {})
.mockImplementationOnce(() => {});
/**
* For some reason, we cannot use the Error story for the test. Although it behaves correctly in storybook,
* it does not render the error message in the test.
*/
render(
Promise.reject(new Error('fetch error')),
})}
>
);
await waitFor(() => {
expect(screen.queryByText('fetch error')).not.toBeNull();
});
});
it('should pass the correct resource down to child component', async () => {
const MyComponent = () => {
const { resource } = useChoicesContext();
return
{resource}
;
};
const dataProvider = testDataProvider({
getList: () =>
// @ts-ignore
Promise.resolve({ data: [{ id: 1 }, { id: 2 }], total: 2 }),
});
render(
);
await waitFor(() => {
expect(screen.queryByText('posts')).not.toBeNull();
});
});
it('should provide a ChoicesContext with all available choices', async () => {
const Children = () => {
const { total } = useChoicesContext();
return {total}
;
};
const dataProvider = testDataProvider({
getList: () =>
// @ts-ignore
Promise.resolve({ data: [{ id: 1 }, { id: 2 }], total: 2 }),
});
render(
);
await waitFor(() => {
expect(screen.getByLabelText('total').innerHTML).toEqual('2');
});
});
it('should accept meta in queryOptions', async () => {
const getList = jest
.fn()
.mockImplementation(() => Promise.resolve({ data: [], total: 25 }));
const dataProvider = testDataProvider({
getList,
// @ts-ignore
getOne: () => Promise.resolve({ data: { id: 1 } }),
});
render();
await waitFor(() => {
expect(getList).toHaveBeenCalledWith('authors', {
filter: {},
pagination: { page: 1, perPage: 25 },
sort: { field: 'id', order: 'DESC' },
meta: { test: true },
signal: undefined,
});
});
});
it('should use meta when fetching current value', async () => {
const getList = jest
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ data: [], total: 25 })
);
const getMany = jest
.fn()
.mockImplementationOnce(() => Promise.resolve({ data: [] }));
const dataProvider = testDataProvider({ getList, getMany });
render(
);
await waitFor(() => {
expect(getMany).toHaveBeenCalledWith('posts', {
ids: [23],
meta: { foo: 'bar' },
signal: undefined,
});
});
});
it('should pass queryOptions to both queries', async () => {
render();
await waitFor(() => new Promise(resolve => setTimeout(resolve, 100)));
expect(screen.queryByDisplayValue('Tolstoy')).toBeNull();
fireEvent.click(screen.getByText('Toggle queryOptions'));
await waitFor(() => {
expect(screen.queryByDisplayValue('Tolstoy')).not.toBeNull();
});
});
it('should not throw an error on save when it is a self reference and the reference is undefined', async () => {
jest.spyOn(console, 'log').mockImplementationOnce(() => {});
jest.spyOn(console, 'error').mockImplementationOnce(() => {});
render();
fireEvent.click(await screen.findByLabelText('Self reference'));
await waitFor(() => {
expect(screen.getAllByRole('option')).toHaveLength(5);
});
const titleInput = await screen.findByDisplayValue('War and Peace');
fireEvent.change(titleInput, {
target: { value: 'War and Peace 2' },
});
screen.getByText('Save').click();
await screen.findByText('Proust', undefined, { timeout: 5000 });
});
it('should render the offline prop node when offline', async () => {
render();
fireEvent.click(await screen.findByText('Simulate offline'));
fireEvent.click(await screen.findByText('Toggle Child'));
await screen.findByText('You are offline, cannot load data');
fireEvent.click(await screen.findByText('Simulate online'));
await screen.findByText('lorem');
});
});
const AutocompleteInput = (
props: Omit &
Partial> &
ChoicesProps & { source?: string }
) => {
const { allChoices, error, source, setFilters } = useChoicesContext(props);
const { getChoiceValue, getChoiceText } = useChoices(props);
const { field } = useInput({ ...props, source });
if (error) {
return {error.message}
;
}
return (
{
const choice = allChoices?.find(
choice =>
getChoiceText(choice).toString() === e.target.value
);
if (choice) {
field.onChange(getChoiceValue(choice));
return;
}
setFilters({ q: e.target.value }, {}, true);
}}
/>
);
};