From d1e3ce822554458a1c791591b369cb4d454d9eed Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Tue, 11 Jan 2022 09:17:56 +0000 Subject: [PATCH] [web] Add a delay before showing loading spinner while lazy-loading React components (#6262) GitOrigin-RevId: a77d11e980103de31a5bf1a19391874bea70cfec --- .../js/shared/components/loading-spinner.js | 28 +++++++++++++++++-- .../chat/components/chat-pane.test.js | 21 +++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/services/web/frontend/js/shared/components/loading-spinner.js b/services/web/frontend/js/shared/components/loading-spinner.js index f019c6715a..0828202cbf 100644 --- a/services/web/frontend/js/shared/components/loading-spinner.js +++ b/services/web/frontend/js/shared/components/loading-spinner.js @@ -1,14 +1,38 @@ import { useTranslation } from 'react-i18next' import Icon from './icon' +import { useEffect, useState } from 'react' +import PropTypes from 'prop-types' -function LoadingSpinner() { +function LoadingSpinner({ delay = 500 }) { const { t } = useTranslation() + + const [show, setShow] = useState(false) + + useEffect(() => { + const timer = window.setTimeout(() => { + setShow(true) + }, delay) + + return () => { + window.clearTimeout(timer) + } + }, [delay]) + + if (!show) { + return null + } + return (
- {` ${t('loading')}…`} +   + {t('loading')}…
) } +LoadingSpinner.propTypes = { + delay: PropTypes.number, +} + export default LoadingSpinner diff --git a/services/web/test/frontend/features/chat/components/chat-pane.test.js b/services/web/test/frontend/features/chat/components/chat-pane.test.js index b010cfd8bc..48a0b6de63 100644 --- a/services/web/test/frontend/features/chat/components/chat-pane.test.js +++ b/services/web/test/frontend/features/chat/components/chat-pane.test.js @@ -12,8 +12,21 @@ import { cleanUpContext, } from '../../../helpers/render-with-context' import { stubMathJax, tearDownMathJaxStubs } from './stubs' +import sinon from 'sinon' describe('', function () { + beforeEach(function () { + this.clock = sinon.useFakeTimers({ + toFake: ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval'], + }) + }) + + afterEach(function () { + this.clock.runAll() + this.clock.restore() + fetchMock.reset() + }) + const user = { id: 'fake_user', first_name: 'fake_user_first_name', @@ -78,10 +91,16 @@ describe('', function () { }) it('a loading spinner is rendered while the messages are loading, then disappears', async function () { - fetchMock.get(/messages/, []) + fetchMock.get(/messages/, [], { delay: 1000 }) renderWithChatContext(, { user }) + this.clock.tick(600) // wait for spinner to be displayed + + await screen.findByText('Loading…') + + this.clock.tick(1000) // wait for response to be received + await waitForElementToBeRemoved(() => screen.getByText('Loading…')) })