diff --git a/packages/ra-ui-materialui/src/field/ReferenceArrayField.spec.tsx b/packages/ra-ui-materialui/src/field/ReferenceArrayField.spec.tsx index d6e3526113f..b3ebad26d44 100644 --- a/packages/ra-ui-materialui/src/field/ReferenceArrayField.spec.tsx +++ b/packages/ra-ui-materialui/src/field/ReferenceArrayField.spec.tsx @@ -10,7 +10,7 @@ import SingleFieldList from '../list/SingleFieldList'; describe('', () => { afterEach(cleanup); - it('should render a loading indicator when related records are not yet fetched', () => { + it('should render a loading indicator when related records are not yet fetched and a second has passed', async () => { const { queryAllByRole } = render( ', () => { ); + + await new Promise(resolve => setTimeout(resolve, 1001)); expect(queryAllByRole('progressbar')).toHaveLength(1); }); diff --git a/packages/ra-ui-materialui/src/field/ReferenceArrayField.tsx b/packages/ra-ui-materialui/src/field/ReferenceArrayField.tsx index 5da928cb5ab..04a06a546cf 100644 --- a/packages/ra-ui-materialui/src/field/ReferenceArrayField.tsx +++ b/packages/ra-ui-materialui/src/field/ReferenceArrayField.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { Children, cloneElement, FC, memo, ReactElement } from 'react'; import PropTypes from 'prop-types'; -import { LinearProgress } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import { ListContextProvider, @@ -16,6 +15,7 @@ import { import { fieldPropTypes, PublicFieldProps, InjectedFieldProps } from './types'; import { ClassesOverride } from '../types'; import sanitizeFieldRestProps from './sanitizeFieldRestProps'; +import { LinearProgress } from '../layout'; /** * A container component that fetches records from another resource specified diff --git a/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx b/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx index b96098b7c41..a7e5a1fbffc 100644 --- a/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx +++ b/packages/ra-ui-materialui/src/field/ReferenceField.spec.tsx @@ -9,20 +9,43 @@ import TextField from './TextField'; describe('', () => { afterEach(cleanup); + const record = { id: 123, postId: 123 }; describe('Progress bar', () => { - it('should display a loader on mount if the reference is not in the store', () => { + it("should not display a loader on mount if the reference is not in the store and a second hasn't passed yet", async () => { const { queryByRole, container } = renderWithRedux( - - + + ); + await new Promise(resolve => setTimeout(resolve, 500)); + expect(queryByRole('progressbar')).toBeNull(); + const links = container.getElementsByTagName('a'); + expect(links).toHaveLength(0); + }); + it('should display a loader on mount if the reference is not in the store and a second has passed', async () => { + const { queryByRole, container } = renderWithRedux( + + + ); + await new Promise(resolve => setTimeout(resolve, 1001)); expect(queryByRole('progressbar')).not.toBeNull(); const links = container.getElementsByTagName('a'); expect(links).toHaveLength(0); @@ -32,7 +55,7 @@ describe('', () => { const { queryByRole, container } = renderWithRedux( ', () => { ', () => { // @ts-ignore-line ', () => { // @ts-ignore-line ', () => { const { container, getByText } = renderWithRedux( ', () => { ', () => { // @ts-ignore-line ', () => { const { container } = render( ', () => { it('should render no link when resourceLinkPath is not specified', () => { const { container } = render( only accepts a single child'); } - const { basePath, resource } = props; + const { basePath, resource, reference } = props; const resourceLinkPath = getResourceLinkPath({ ...props, resource, @@ -147,12 +147,13 @@ export const NonEmptyReferenceField: FC + = props => { ...rest } = props; const classes = useStyles(props); + if (!loaded) { return ; } diff --git a/packages/ra-ui-materialui/src/input/ReferenceArrayInput.spec.js b/packages/ra-ui-materialui/src/input/ReferenceArrayInput.spec.js index bdd0d2f9fbb..6b34638f6c0 100644 --- a/packages/ra-ui-materialui/src/input/ReferenceArrayInput.spec.js +++ b/packages/ra-ui-materialui/src/input/ReferenceArrayInput.spec.js @@ -15,7 +15,7 @@ describe('', () => { translate: x => `*${x}*`, }; - it('should render a progress bar if loading is true', () => { + it("should not render a progress bar if loading is true and a second hasn't passed", async () => { const MyComponent = () =>
MyComponent
; const { queryByRole, queryByText } = render( ', () => { ); + await new Promise(resolve => setTimeout(resolve, 250)); + expect(queryByRole('progressbar')).toBeNull(); + expect(queryByText('MyComponent')).toBeNull(); + }); + + it('should render a progress bar if loading is true and a second has passed', async () => { + const MyComponent = () =>
MyComponent
; + const { queryByRole, queryByText } = render( + + + + ); + await new Promise(resolve => setTimeout(resolve, 1001)); expect(queryByRole('progressbar')).not.toBeNull(); expect(queryByText('MyComponent')).toBeNull(); }); diff --git a/packages/ra-ui-materialui/src/input/ReferenceInput.spec.tsx b/packages/ra-ui-materialui/src/input/ReferenceInput.spec.tsx index 2133fc801f8..6d3a250f9df 100644 --- a/packages/ra-ui-materialui/src/input/ReferenceInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/ReferenceInput.spec.tsx @@ -59,7 +59,7 @@ describe('', () => { afterEach(cleanup); - it('should render a LinearProgress if loading is true', () => { + it('should render a LinearProgress if loading is true and a second has passed', async () => { const { queryByRole } = render( ', () => { ); + await new Promise(resolve => setTimeout(resolve, 1001)); expect(queryByRole('progressbar')).not.toBeNull(); }); + it("should not render a LinearProgress if loading is true and a second hasn't passed", async () => { + const { queryByRole } = render( + + + + ); + + await new Promise(resolve => setTimeout(resolve, 250)); + expect(queryByRole('progressbar')).toBeNull(); + }); + it('should not render a LinearProgress if loading is false', () => { const { queryByRole } = render( ({ @@ -24,18 +27,27 @@ const useStyles = makeStyles( * * @param {Object} classes CSS class names */ -const LinearProgress = props => { +const LinearProgress = ({ timeout = 1000, ...props }: LinearProgressProps) => { const { classes: classesOverride, className, ...rest } = props; const classes = useStyles(props); - return ( + const oneSecondHasPassed = useTimeout(timeout); + + return oneSecondHasPassed ? ( - ); + ) : null; }; + LinearProgress.propTypes = { classes: PropTypes.object, className: PropTypes.string, + timeout: PropTypes.number, }; + // wat? TypeScript looses the displayName if we don't set it explicitly LinearProgress.displayName = 'LinearProgress'; +export interface LinearProgressProps extends ProgressProps { + timeout?: number; +} + export default LinearProgress; diff --git a/packages/ra-ui-materialui/src/layout/index.ts b/packages/ra-ui-materialui/src/layout/index.ts index 10a4e673615..7ca62dcf6e8 100644 --- a/packages/ra-ui-materialui/src/layout/index.ts +++ b/packages/ra-ui-materialui/src/layout/index.ts @@ -9,7 +9,7 @@ import HideOnScroll, { HideOnScrollProps } from './HideOnScroll'; import Layout, { LayoutProps } from './Layout'; import Loading from './Loading'; import LoadingPage from './LoadingPage'; -import LinearProgress from './LinearProgress'; +import LinearProgress, { LinearProgressProps } from './LinearProgress'; import LoadingIndicator from './LoadingIndicator'; import Menu, { MenuProps } from './Menu'; import MenuItemLink, { MenuItemLinkProps } from './MenuItemLink'; @@ -57,6 +57,7 @@ export type { ErrorProps, HideOnScrollProps, LayoutProps, + LinearProgressProps, MenuItemLinkProps, MenuProps, ResponsiveProps,