|
4 | 4 | * SPDX-License-Identifier: BSD-3-Clause |
5 | 5 | * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause |
6 | 6 | */ |
7 | | -import React from 'react' |
| 7 | +import React, {useState} from 'react' |
8 | 8 | import {IntlProvider} from 'react-intl' |
9 | 9 | import {render, screen, waitFor} from '@testing-library/react' |
10 | 10 | import userEvent from '@testing-library/user-event' |
@@ -101,7 +101,8 @@ const setup = (overrides = {}) => { |
101 | 101 | isGuestCheckout: overrides.isGuestCheckout ?? false, |
102 | 102 | isDisabled: overrides.isDisabled ?? false, |
103 | 103 | onSavePreferenceChange: overrides.onSavePref ?? jest.fn(), |
104 | | - onRegistered: overrides.onRegistered ?? jest.fn() |
| 104 | + onRegistered: overrides.onRegistered ?? jest.fn(), |
| 105 | + onLoadingChange: overrides.onLoadingChange ?? jest.fn() |
105 | 106 | } |
106 | 107 |
|
107 | 108 | const utils = render( |
@@ -400,6 +401,151 @@ describe('UserRegistration', () => { |
400 | 401 | expect(props.onRegistered).not.toHaveBeenCalled() |
401 | 402 | }) |
402 | 403 |
|
| 404 | + test('shows loading overlay when guest user clicks registration checkbox', async () => { |
| 405 | + const user = userEvent.setup() |
| 406 | + const onLoadingChange = jest.fn() |
| 407 | + const {authorizePasswordlessLogin} = setup({ |
| 408 | + onLoadingChange, |
| 409 | + authorizeMutate: jest.fn().mockImplementation(() => { |
| 410 | + // Simulate async delay |
| 411 | + return new Promise((resolve) => setTimeout(() => resolve({}), 100)) |
| 412 | + }) |
| 413 | + }) |
| 414 | + |
| 415 | + const checkbox = screen.getByRole('checkbox', {name: /Create an account/i}) |
| 416 | + await user.click(checkbox) |
| 417 | + |
| 418 | + // Verify loading overlay appears |
| 419 | + await waitFor(() => { |
| 420 | + expect(screen.getByTestId('sf-otp-loading-overlay')).toBeInTheDocument() |
| 421 | + }) |
| 422 | + |
| 423 | + // Verify onLoadingChange was called with true |
| 424 | + expect(onLoadingChange).toHaveBeenCalledWith(true) |
| 425 | + |
| 426 | + // Wait for OTP modal to open (which clears loading state) |
| 427 | + await waitFor( |
| 428 | + () => { |
| 429 | + expect(screen.getByTestId('otp-guest')).toBeInTheDocument() |
| 430 | + }, |
| 431 | + {timeout: 2000} |
| 432 | + ) |
| 433 | + |
| 434 | + // Verify loading overlay disappears when OTP modal opens |
| 435 | + await waitFor(() => { |
| 436 | + expect(screen.queryByTestId('sf-otp-loading-overlay')).not.toBeInTheDocument() |
| 437 | + }) |
| 438 | + |
| 439 | + // Verify onLoadingChange was called with false when modal opens |
| 440 | + expect(onLoadingChange).toHaveBeenCalledWith(false) |
| 441 | + }) |
| 442 | + |
| 443 | + test('hides loading overlay when OTP authorization fails', async () => { |
| 444 | + const user = userEvent.setup() |
| 445 | + const onLoadingChange = jest.fn() |
| 446 | + // Make the error happen after a small delay to ensure overlay appears first |
| 447 | + const authorizeMutate = jest.fn().mockImplementation(() => { |
| 448 | + return new Promise((_, reject) => { |
| 449 | + setTimeout(() => reject(new Error('Authorization failed')), 50) |
| 450 | + }) |
| 451 | + }) |
| 452 | + setup({ |
| 453 | + onLoadingChange, |
| 454 | + authorizeMutate |
| 455 | + }) |
| 456 | + |
| 457 | + const checkbox = screen.getByRole('checkbox', {name: /Create an account/i}) |
| 458 | + await user.click(checkbox) |
| 459 | + |
| 460 | + // Verify loading overlay appears initially |
| 461 | + await waitFor(() => { |
| 462 | + expect(screen.getByTestId('sf-otp-loading-overlay')).toBeInTheDocument() |
| 463 | + }) |
| 464 | + expect(onLoadingChange).toHaveBeenCalledWith(true) |
| 465 | + |
| 466 | + // Wait for error to be handled |
| 467 | + await waitFor( |
| 468 | + () => { |
| 469 | + expect(screen.queryByTestId('sf-otp-loading-overlay')).not.toBeInTheDocument() |
| 470 | + }, |
| 471 | + {timeout: 2000} |
| 472 | + ) |
| 473 | + |
| 474 | + // Verify onLoadingChange was called with false on error |
| 475 | + expect(onLoadingChange).toHaveBeenCalledWith(false) |
| 476 | + // OTP modal should not open on error |
| 477 | + expect(screen.queryByTestId('otp-guest')).not.toBeInTheDocument() |
| 478 | + }) |
| 479 | + |
| 480 | + test('does not show loading overlay for registered users', async () => { |
| 481 | + const user = userEvent.setup() |
| 482 | + const onLoadingChange = jest.fn() |
| 483 | + setup({isGuest: false, onLoadingChange}) |
| 484 | + |
| 485 | + const checkbox = screen.getByRole('checkbox', {name: /Create an account/i}) |
| 486 | + await user.click(checkbox) |
| 487 | + |
| 488 | + // Loading overlay should not appear for registered users |
| 489 | + expect(screen.queryByTestId('sf-otp-loading-overlay')).not.toBeInTheDocument() |
| 490 | + expect(onLoadingChange).not.toHaveBeenCalled() |
| 491 | + }) |
| 492 | + |
| 493 | + test('clears loading state when checkbox is unchecked', async () => { |
| 494 | + const user = userEvent.setup() |
| 495 | + const onLoadingChange = jest.fn() |
| 496 | + const authorizeMutate = jest.fn().mockImplementation(() => { |
| 497 | + return new Promise((resolve) => setTimeout(() => resolve({}), 200)) |
| 498 | + }) |
| 499 | + |
| 500 | + // Wrapper to control the enableUserRegistration prop |
| 501 | + const TestWrapper = () => { |
| 502 | + const [enabled, setEnabled] = useState(false) |
| 503 | + return ( |
| 504 | + <IntlProvider locale="en-GB" messages={TEST_MESSAGES}> |
| 505 | + <UserRegistration |
| 506 | + enableUserRegistration={enabled} |
| 507 | + setEnableUserRegistration={setEnabled} |
| 508 | + onLoadingChange={onLoadingChange} |
| 509 | + /> |
| 510 | + </IntlProvider> |
| 511 | + ) |
| 512 | + } |
| 513 | + |
| 514 | + useCurrentBasket.mockReturnValue({ |
| 515 | + data: { |
| 516 | + basketId: 'basket-123', |
| 517 | + customerInfo: {email: 'test@example.com'}, |
| 518 | + productItems: [{productId: 'sku-1', quantity: 1}], |
| 519 | + shipments: [ |
| 520 | + {shippingAddress: {address1: '123 Main'}, shippingMethod: {id: 'Ground'}} |
| 521 | + ] |
| 522 | + } |
| 523 | + }) |
| 524 | + useCustomerType.mockReturnValue({isGuest: true}) |
| 525 | + mockAuthHelperFunctions[AuthHelpers.AuthorizePasswordless].mutateAsync = authorizeMutate |
| 526 | + |
| 527 | + render(<TestWrapper />) |
| 528 | + |
| 529 | + const checkbox = screen.getByRole('checkbox', {name: /Create an account/i}) |
| 530 | + |
| 531 | + // Check the checkbox |
| 532 | + await user.click(checkbox) |
| 533 | + |
| 534 | + // Wait for loading to start |
| 535 | + await waitFor(() => { |
| 536 | + expect(onLoadingChange).toHaveBeenCalledWith(true) |
| 537 | + }) |
| 538 | + |
| 539 | + // Uncheck the checkbox before OTP modal opens |
| 540 | + await user.click(checkbox) |
| 541 | + |
| 542 | + // Verify loading state is cleared |
| 543 | + await waitFor(() => { |
| 544 | + expect(onLoadingChange).toHaveBeenCalledWith(false) |
| 545 | + }) |
| 546 | + expect(screen.queryByTestId('sf-otp-loading-overlay')).not.toBeInTheDocument() |
| 547 | + }) |
| 548 | + |
403 | 549 | test('displays explanatory text when registration is enabled', () => { |
404 | 550 | // Test with registration disabled |
405 | 551 | const {utils} = setup({enable: false}) |
|
0 commit comments