1 import React from 'react';
3 import { fireEvent, render, screen, waitFor } from '@testing-library/react';
4 import { verifyAllWhenMocksCalled, when } from 'jest-when';
6 import useApi from '@proton/components/hooks/useApi';
7 import localStorageWithExpiry from '@proton/shared/lib/api/helpers/localStorageWithExpiry';
8 import { DRIVE_SIGNIN, DRIVE_SIGNUP } from '@proton/shared/lib/drive/urls';
9 import { API_CUSTOM_ERROR_CODES } from '@proton/shared/lib/errors';
10 import { replaceUrl } from '@proton/shared/lib/helpers/browser';
12 import usePublicToken from '../../../hooks/drive/usePublicToken';
13 import { PUBLIC_SHARE_REDIRECT_PASSWORD_STORAGE_KEY } from '../../../utils/url/password';
14 import { SignupFlowModal } from './SignupFlowModal';
16 jest.mock('@proton/components/hooks/useApi');
17 const mockedUseApi = jest.mocked(useApi);
19 jest.mock('@proton/shared/lib/helpers/browser');
20 const mockedReplaceUrl = jest.mocked(replaceUrl);
22 jest.mock('../../../hooks/drive/usePublicToken');
23 const mockUrlPassword = 'mockUrlPassword';
24 const mockToken = 'mockToken';
26 jest.mocked(usePublicToken).mockReturnValue({
28 urlPassword: mockUrlPassword,
31 const ResizeObserverMock = jest.fn(() => ({
32 disconnect: jest.fn(),
37 const locationMock = {
38 pathname: '/urls/mockpath',
43 describe('SignupFlowModal', () => {
44 let assignMock = jest.fn();
45 const originalWindowLocation = window.location;
46 const originalResizeObserver = window.ResizeObserver;
49 Object.defineProperty(window, 'ResizeObserver', {
50 value: ResizeObserverMock,
53 Object.defineProperty(window, 'location', {
60 localStorageWithExpiry.deleteData(PUBLIC_SHARE_REDIRECT_PASSWORD_STORAGE_KEY);
61 assignMock.mockClear();
65 verifyAllWhenMocksCalled();
66 Object.defineProperty(window, 'ResizeObserver', {
67 value: originalResizeObserver,
70 Object.defineProperty(window, 'location', {
72 value: originalWindowLocation,
76 it('should open the modal and delete the password from localStorage on mount', () => {
77 render(<SignupFlowModal open onClose={() => {}} onExit={() => {}} />);
78 expect(localStorageWithExpiry.getData(PUBLIC_SHARE_REDIRECT_PASSWORD_STORAGE_KEY)).toEqual(null);
79 expect(screen.getByTestId('public-share-signup-modal-email')).toBeInTheDocument();
82 it('should handle email input change and validation', () => {
83 render(<SignupFlowModal open onClose={() => {}} onExit={() => {}} />);
84 const emailInput = screen.getByTestId<HTMLInputElement>('public-share-signup-modal-email');
86 fireEvent.change(emailInput, { target: { value: 'invalid-email' } });
87 expect(emailInput.value).toBe('invalid-email');
88 expect(screen.getByText('Email is not valid')).toBeInTheDocument();
91 it('should handle form submission and API responses correctly', async () => {
92 const mockApi = jest.fn();
93 mockedUseApi.mockReturnValue(mockApi);
94 mockApi.mockResolvedValue({ Code: 1000 });
95 const expectedReplaceUrl = DRIVE_SIGNUP.concat(
96 '?username=test@example.com%40returnUrl=%2Furls%2Fmockpath%23mockhash&returnUrlContext=public'
98 when(mockedReplaceUrl).expectCalledWith(expectedReplaceUrl);
100 render(<SignupFlowModal open onClose={() => {}} onExit={() => {}} />);
101 const emailInput = screen.getByTestId('public-share-signup-modal-email');
102 const submitButton = screen.getByText('Continue');
104 fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
105 fireEvent.click(submitButton);
107 await waitFor(() => {
108 expect(localStorageWithExpiry.getData(PUBLIC_SHARE_REDIRECT_PASSWORD_STORAGE_KEY)).toEqual(mockUrlPassword);
112 it('should redirect to SIGN_IN if email is already used', async () => {
113 const mockApi = jest.fn();
114 mockedUseApi.mockReturnValue(mockApi);
115 mockApi.mockRejectedValue({ data: { Code: API_CUSTOM_ERROR_CODES.ALREADY_USED, Error: 'test message' } });
116 const expectedReplaceUrl = DRIVE_SIGNIN.concat(
117 '?email=used@example.com%40returnUrl=%2Furls%2Fmockpath%23mockhash&returnUrlContext=public'
119 when(mockedReplaceUrl).expectCalledWith(expectedReplaceUrl);
121 render(<SignupFlowModal open onClose={() => {}} onExit={() => {}} />);
122 const emailInput = screen.getByTestId('public-share-signup-modal-email');
123 const submitButton = screen.getByText('Continue');
125 fireEvent.change(emailInput, { target: { value: 'used@example.com' } });
126 fireEvent.click(submitButton);
128 await waitFor(() => {
129 expect(localStorageWithExpiry.getData(PUBLIC_SHARE_REDIRECT_PASSWORD_STORAGE_KEY)).toEqual(mockUrlPassword);
133 it('should display an error message for other API errors', async () => {
134 const mockApi = jest.fn();
135 mockedUseApi.mockReturnValue(mockApi);
137 mockApi.mockRejectedValue({ data: { Code: '123456', Error: 'Some error occurred' } });
139 render(<SignupFlowModal open onClose={() => {}} onExit={() => {}} />);
140 const emailInput = screen.getByTestId('public-share-signup-modal-email');
141 const submitButton = screen.getByText('Continue');
143 fireEvent.change(emailInput, { target: { value: 'error@example.com' } });
144 fireEvent.click(submitButton);
146 await waitFor(() => {
147 expect(localStorageWithExpiry.getData(PUBLIC_SHARE_REDIRECT_PASSWORD_STORAGE_KEY)).toEqual(null);
148 expect(screen.getByText('Some error occurred')).toBeInTheDocument();