Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / components / containers / payments / Payment.spec.tsx
blob4bd734e81d963c2fd9f9794832d59d6d0f0a2753
1 import { render, waitFor } from '@testing-library/react';
3 import type { ViewPaymentMethod } from '@proton/components/payments/client-extensions';
4 import type { CardFieldStatus } from '@proton/components/payments/react-extensions/useCard';
5 import type { CardModel, SavedPaymentMethod, SavedPaymentMethodInternal } from '@proton/payments';
6 import { MethodStorage, PAYMENT_METHOD_TYPES } from '@proton/payments';
7 import { ChargebeeEnabled } from '@proton/shared/lib/interfaces';
8 import { applyHOCs, withApi, withCache, withConfig } from '@proton/testing';
10 import { PaymentsNoApi } from './Payment';
12 let apiMock: jest.Mock;
13 jest.mock('../../hooks/useApi', () => {
14     let api = jest.fn();
15     apiMock = api;
17     return {
18         __esModule: true,
19         default: () => api,
20     };
21 });
23 const defaultCard: CardModel = {
24     number: '',
25     month: '',
26     year: '',
27     cvc: '',
28     zip: '',
29     country: 'US',
32 const cardFieldStatus: CardFieldStatus = {
33     number: false,
34     month: false,
35     year: false,
36     cvc: false,
37     zip: false,
38     country: false,
41 let paymentMethods: SavedPaymentMethod[];
42 let options;
44 let lastUsedMethod: ViewPaymentMethod;
46 let allMethods: ViewPaymentMethod[];
48 const PaymentContext = applyHOCs(withApi(), withConfig(), withCache())(PaymentsNoApi);
50 beforeEach(() => {
51     paymentMethods = [
52         {
53             ID: 'methodid1',
54             Type: PAYMENT_METHOD_TYPES.CARD,
55             Autopay: 1,
56             Order: 497,
57             Details: {
58                 Last4: '4242',
59                 Brand: 'Visa',
60                 ExpMonth: '01',
61                 ExpYear: '2025',
62                 Name: 'Arthur Morgan',
63                 Country: 'US',
64                 ZIP: '11111',
65             },
66             External: MethodStorage.INTERNAL,
67         },
68         {
69             ID: 'methodid2',
70             Type: PAYMENT_METHOD_TYPES.PAYPAL,
71             Order: 498,
72             Details: {
73                 BillingAgreementID: 'Billing1',
74                 PayerID: 'Payer1',
75                 Payer: 'buyer@example.com',
76             },
77             External: MethodStorage.INTERNAL,
78         },
79         {
80             ID: 'methodid3',
81             Type: PAYMENT_METHOD_TYPES.CARD,
82             Autopay: 0,
83             Order: 499,
84             Details: {
85                 Last4: '3220',
86                 Brand: 'Visa',
87                 ExpMonth: '11',
88                 ExpYear: '2030',
89                 Name: 'Arthur Morgan',
90                 Country: 'US',
91                 ZIP: '1211',
92             },
93             External: MethodStorage.INTERNAL,
94         },
95     ];
97     options = {
98         usedMethods: [
99             {
100                 icon: 'brand-visa',
101                 text: 'Visa ending in 4242',
102                 // some plausible value
103                 value: 'methodid1',
104                 // disabled: false,
105                 // custom: true,
106             },
107             {
108                 icon: 'brand-paypal',
109                 text: 'PayPal - someId',
110                 value: 'methodid2',
111                 // disabled: false,
112                 // custom: true,
113             },
114             {
115                 icon: 'brand-visa',
116                 text: 'Visa ending in 3220',
117                 value: 'methodid3',
118                 // disabled: false,
119                 // custom: true,
120             },
121         ] as ViewPaymentMethod[],
122         methods: [
123             {
124                 icon: 'credit-card',
125                 value: 'card',
126                 text: 'New credit/debit card',
127             },
128             {
129                 icon: 'money-bills',
130                 text: 'Cash',
131                 value: 'cash',
132             },
133         ] as ViewPaymentMethod[],
134     };
136     lastUsedMethod = options.usedMethods[options.usedMethods.length - 1];
137     allMethods = [...options.usedMethods, ...options.methods];
140 describe('Payment', () => {
141     beforeEach(() => {
142         apiMock.mockReset();
143     });
145     it('should render', () => {
146         const method = PAYMENT_METHOD_TYPES.CARD;
147         const savedMethodInternal = paymentMethods.find(({ ID }) => method === ID) as SavedPaymentMethodInternal;
149         render(
150             <PaymentContext
151                 type="subscription"
152                 onMethod={() => {}}
153                 method={method}
154                 amount={1000}
155                 card={defaultCard}
156                 cardErrors={{}}
157                 onCard={() => {}}
158                 paypal={{}}
159                 paypalCredit={{}}
160                 cardFieldStatus={cardFieldStatus}
161                 isAuthenticated={true}
162                 lastUsedMethod={lastUsedMethod}
163                 allMethods={allMethods}
164                 savedMethodInternal={savedMethodInternal}
165                 loading={false}
166                 currency="USD"
167                 iframeHandles={null as any}
168                 chargebeeCard={null as any}
169                 chargebeePaypal={null as any}
170                 bitcoinInhouse={null as any}
171                 bitcoinChargebee={null as any}
172                 hasSomeVpnPlan={false}
173                 paymentComponentLoaded={jest.fn()}
174                 isChargebeeEnabled={() => ChargebeeEnabled.INHOUSE_FORCED}
175                 user={undefined}
176                 paymentStatus={undefined}
177                 directDebit={
178                     {
179                         customer: {} as any,
180                         bankAccount: {} as any,
181                     } as any
182                 }
183             />
184         );
185     });
187     it('should render <Alert3DS> if the payment method is card', async () => {
188         let { container } = render(
189             <PaymentContext
190                 type="subscription"
191                 onMethod={() => {}}
192                 method={PAYMENT_METHOD_TYPES.CARD}
193                 amount={1000}
194                 card={defaultCard}
195                 cardErrors={{}}
196                 onCard={() => {}}
197                 paypal={{}}
198                 paypalCredit={{}}
199                 cardFieldStatus={cardFieldStatus}
200                 isAuthenticated={true}
201                 lastUsedMethod={lastUsedMethod}
202                 allMethods={allMethods}
203                 savedMethodInternal={undefined}
204                 loading={false}
205                 currency="USD"
206                 iframeHandles={null as any}
207                 chargebeeCard={null as any}
208                 chargebeePaypal={null as any}
209                 bitcoinInhouse={null as any}
210                 bitcoinChargebee={null as any}
211                 hasSomeVpnPlan={false}
212                 paymentComponentLoaded={jest.fn()}
213                 isChargebeeEnabled={() => ChargebeeEnabled.INHOUSE_FORCED}
214                 user={undefined}
215                 paymentStatus={undefined}
216                 directDebit={
217                     {
218                         customer: {} as any,
219                         bankAccount: {} as any,
220                     } as any
221                 }
222             />
223         );
225         await waitFor(() => {
226             expect(container).toHaveTextContent('We use 3-D Secure to protect your payments');
227         });
228     });
230     it('should not render <Alert3DS> if flow type is "signup"', async () => {
231         let { container } = render(
232             <PaymentContext
233                 onMethod={() => {}}
234                 type="signup"
235                 method={PAYMENT_METHOD_TYPES.CARD}
236                 amount={1000}
237                 card={defaultCard}
238                 cardErrors={{}}
239                 onCard={() => {}}
240                 paypal={{}}
241                 paypalCredit={{}}
242                 cardFieldStatus={cardFieldStatus}
243                 isAuthenticated={true}
244                 lastUsedMethod={lastUsedMethod}
245                 allMethods={allMethods}
246                 savedMethodInternal={undefined}
247                 loading={false}
248                 currency="USD"
249                 iframeHandles={null as any}
250                 chargebeeCard={null as any}
251                 chargebeePaypal={null as any}
252                 bitcoinInhouse={null as any}
253                 bitcoinChargebee={null as any}
254                 hasSomeVpnPlan={false}
255                 paymentComponentLoaded={jest.fn()}
256                 isChargebeeEnabled={() => ChargebeeEnabled.INHOUSE_FORCED}
257                 user={undefined}
258                 paymentStatus={undefined}
259                 directDebit={
260                     {
261                         customer: {} as any,
262                         bankAccount: {} as any,
263                     } as any
264                 }
265             />
266         );
268         await waitFor(() => {
269             expect(container).not.toHaveTextContent('We use 3-D Secure to protect your payments');
270         });
271     });
273     it('should render <Alert3DS> if user selected a perviously used credit card (customPaymentMethod)', async () => {
274         apiMock.mockImplementation((query) => {
275             if (query.url === 'payments/v4/methods') {
276                 return {
277                     PaymentMethods: [
278                         {
279                             ID: 'my-custom-method-123',
280                             Type: PAYMENT_METHOD_TYPES.CARD,
281                         },
282                     ],
283                 };
284             }
286             return {};
287         });
289         paymentMethods = [
290             {
291                 ID: 'my-custom-method-123',
292                 Type: PAYMENT_METHOD_TYPES.CARD,
293                 Autopay: 1,
294                 Order: 497,
295                 Details: {
296                     Last4: '4242',
297                     Brand: 'Visa',
298                     ExpMonth: '01',
299                     ExpYear: '2025',
300                     Name: 'Arthur Morgan',
301                     Country: 'US',
302                     ZIP: '11111',
303                 },
304                 External: MethodStorage.INTERNAL,
305             },
306         ];
308         let savedMethodInternal = paymentMethods[0] as SavedPaymentMethodInternal;
310         let { container } = render(
311             <PaymentContext
312                 onMethod={() => {}}
313                 type="subscription"
314                 method="my-custom-method-123"
315                 amount={1000}
316                 card={defaultCard}
317                 cardErrors={{}}
318                 onCard={() => {}}
319                 paypal={{}}
320                 paypalCredit={{}}
321                 cardFieldStatus={cardFieldStatus}
322                 isAuthenticated={true}
323                 lastUsedMethod={lastUsedMethod}
324                 allMethods={allMethods}
325                 savedMethodInternal={savedMethodInternal}
326                 loading={false}
327                 currency="USD"
328                 iframeHandles={{} as any}
329                 chargebeeCard={null as any}
330                 chargebeePaypal={null as any}
331                 bitcoinInhouse={null as any}
332                 bitcoinChargebee={null as any}
333                 hasSomeVpnPlan={false}
334                 paymentComponentLoaded={jest.fn()}
335                 isChargebeeEnabled={() => ChargebeeEnabled.INHOUSE_FORCED}
336                 user={undefined}
337                 paymentStatus={undefined}
338                 directDebit={
339                     {
340                         customer: {} as any,
341                         bankAccount: {} as any,
342                     } as any
343                 }
344             />
345         );
347         await waitFor(() => {
348             expect(container).toHaveTextContent('We use 3-D Secure to protect your payments');
349         });
350     });
352     it('should not render <Alert3DS> if user selected a perviously used method which is not a credit card', async () => {
353         apiMock.mockImplementation((query) => {
354             if (query.url === 'payments/v4/methods') {
355                 return {
356                     PaymentMethods: [
357                         {
358                             ID: 'my-custom-method-123',
359                             Type: PAYMENT_METHOD_TYPES.PAYPAL,
360                         },
361                     ],
362                 };
363             }
365             return {};
366         });
368         paymentMethods = [
369             {
370                 ID: 'my-custom-method-123',
371                 Type: PAYMENT_METHOD_TYPES.PAYPAL,
372                 Order: 497,
373                 Details: {
374                     BillingAgreementID: 'Billing1',
375                     PayerID: 'Payer1',
376                     Payer: '',
377                 },
378                 External: MethodStorage.INTERNAL,
379             },
380         ];
382         let savedMethodInternal: SavedPaymentMethodInternal = paymentMethods[0] as SavedPaymentMethodInternal;
384         let { container } = render(
385             <PaymentContext
386                 onMethod={() => {}}
387                 type="subscription"
388                 method="my-custom-method-123"
389                 amount={1000}
390                 card={defaultCard}
391                 cardErrors={{}}
392                 onCard={() => {}}
393                 paypal={{}}
394                 paypalCredit={{}}
395                 cardFieldStatus={cardFieldStatus}
396                 isAuthenticated={true}
397                 lastUsedMethod={lastUsedMethod}
398                 allMethods={allMethods}
399                 savedMethodInternal={savedMethodInternal}
400                 loading={false}
401                 currency="USD"
402                 iframeHandles={null as any}
403                 chargebeeCard={null as any}
404                 chargebeePaypal={null as any}
405                 bitcoinInhouse={null as any}
406                 bitcoinChargebee={null as any}
407                 hasSomeVpnPlan={false}
408                 paymentComponentLoaded={jest.fn()}
409                 isChargebeeEnabled={() => ChargebeeEnabled.INHOUSE_FORCED}
410                 user={undefined}
411                 paymentStatus={undefined}
412                 directDebit={
413                     {
414                         customer: {} as any,
415                         bankAccount: {} as any,
416                     } as any
417                 }
418             />
419         );
421         await waitFor(() => {
422             expect(container).not.toHaveTextContent('We use 3-D Secure to protect your payments');
423         });
424     });