diff --git a/packages/template-retail-react-app/app/components/otp-auth/index.jsx b/packages/template-retail-react-app/app/components/otp-auth/index.jsx index 886c83ce52..0e36aceda2 100644 --- a/packages/template-retail-react-app/app/components/otp-auth/index.jsx +++ b/packages/template-retail-react-app/app/components/otp-auth/index.jsx @@ -12,6 +12,7 @@ import { Button, Input, SimpleGrid, + Spinner, Stack, Text, HStack, @@ -271,6 +272,17 @@ const OtpAuth = ({ ))} + {/* Loading spinner during verification */} + {isVerifying && ( + + )} + {/* Error message */} {error && ( diff --git a/packages/template-retail-react-app/app/components/otp-auth/index.test.js b/packages/template-retail-react-app/app/components/otp-auth/index.test.js index 06e2a2d049..d238c89e33 100644 --- a/packages/template-retail-react-app/app/components/otp-auth/index.test.js +++ b/packages/template-retail-react-app/app/components/otp-auth/index.test.js @@ -246,6 +246,41 @@ describe('OtpAuth', () => { await user.type(otpInputs[7], '8') expect(otpInputs[7]).toHaveFocus() }) + + test('shows spinner while OTP is being verified', async () => { + const deferred = {} + const verifyingPromise = new Promise((resolve) => { + deferred.resolve = resolve + }) + const mockVerify = jest.fn().mockReturnValue(verifyingPromise) + + const user = userEvent.setup() + renderWithProviders( + + ) + + expect(screen.queryByTestId('otp-verifying-spinner')).not.toBeInTheDocument() + + const otpInputs = screen.getAllByRole('textbox') + fireEvent.paste(otpInputs[0], { + clipboardData: {getData: () => '12345678'} + }) + + await waitFor(() => { + expect(screen.getByTestId('otp-verifying-spinner')).toBeInTheDocument() + }) + + deferred.resolve({success: true}) + await waitFor(() => { + expect(screen.queryByTestId('otp-verifying-spinner')).not.toBeInTheDocument() + }) + }) }) describe('Keyboard Navigation', () => {