1+ import { Page } from '@playwright/test' ;
2+ import { BasePaymentProcessor } from "./base-payment-processor" ;
3+ import { PAYMENT_TEST_DATA } from "../../fixtures/payment-test-data" ;
4+
5+ export class PayPalProcessor extends BasePaymentProcessor {
6+
7+ // Locators
8+ readonly paypalContainerSelector = '#paypal-container' ;
9+ readonly emailInput = '#email' ;
10+ readonly passwordInput = '#password' ;
11+ readonly nextButton = '#btnNext'
12+ readonly loginButton = '#btnLogin' ;
13+ readonly submitButton = '[data-testid="submit-button-initial"]' ;
14+ readonly paymentConfirmationMessage = '.payment-confirmation' ;
15+ readonly errorMessage = '.paypal-error-message' ;
16+
17+ constructor ( page : Page ) {
18+ super ( page ) ;
19+ }
20+
21+ /**
22+ * Feature: PayPal payment processing
23+ * Scenario: User can pay with PayPal in block checkout
24+ * Given the user has selected PayPal payment method
25+ * When the user clicks the PayPal container
26+ * And is redirected to PayPal login
27+ * And enters valid credentials
28+ * And clicks submit button
29+ * Then the payment should be processed successfully
30+ *
31+ * Scenario: User can pay with PayPal in classic checkout
32+ * Given the user has selected PayPal payment method
33+ * When the user clicks process payment
34+ * And is redirected to PayPal login
35+ * And enters valid credentials
36+ * And clicks submit button
37+ * Then the payment should be processed successfully
38+ */
39+ async processPayment ( expectSuccess : boolean = true , preset : string = 'success' ) {
40+ const paypalDetails = PAYMENT_TEST_DATA . paypal [ preset ] ;
41+
42+ await this . page . waitForTimeout ( 1000 ) ;
43+ const paypalContainer = await this . page . $ ( this . paypalContainerSelector ) ;
44+
45+ if ( paypalContainer ) {
46+ console . log ( 'Block checkout detected - clicking PayPal container' ) ;
47+ await this . page . click ( this . paypalContainerSelector ) ;
48+ } else {
49+ console . log ( 'Classic checkout detected - clicking process payment button' ) ;
50+ await this . clickWooSubmitButton ( ) ;
51+ }
52+
53+ await this . handlePayPalLogin ( paypalDetails ) ;
54+
55+ if ( expectSuccess ) {
56+ await this . page . waitForNavigation ( { waitUntil : 'networkidle' } ) ;
57+ }
58+ }
59+
60+ /**
61+ * Feature: PayPal login with retry logic
62+ * Scenario: User login credentials may need to be entered twice
63+ * Given the user is on PayPal login page
64+ * When the user enters credentials
65+ * And sometimes needs to retry entering credentials
66+ * Then the user should be able to login successfully
67+ */
68+ private async handlePayPalLogin ( paypalDetails : { user : string ; pw : string } ) {
69+ await this . page . waitForSelector ( this . emailInput , { timeout : 10000 } ) ;
70+
71+ const maxRetries = 2 ;
72+ let attempt = 0 ;
73+
74+ while ( attempt < maxRetries ) {
75+ attempt ++ ;
76+ console . log ( `PayPal login attempt ${ attempt } /${ maxRetries } ` ) ;
77+
78+ try {
79+ await this . page . fill ( this . emailInput , paypalDetails . user ) ;
80+ await this . page . waitForTimeout ( 500 ) ;
81+ await this . page . click ( this . nextButton ) ;
82+ await this . page . fill ( this . passwordInput , paypalDetails . pw ) ;
83+ await this . page . waitForTimeout ( 500 ) ;
84+
85+ await this . page . click ( this . loginButton ) ;
86+ await this . page . waitForTimeout ( 2000 ) ;
87+
88+ const stillOnLoginPage = await this . page . $ ( this . emailInput ) ;
89+
90+ if ( ! stillOnLoginPage ) {
91+ console . log ( 'Login successful, proceeding to payment confirmation' ) ;
92+ break ;
93+ } else if ( attempt < maxRetries ) {
94+ console . log ( 'Still on login page, retrying credentials...' ) ;
95+ // Clear the fields before retry
96+ await this . page . fill ( this . emailInput , '' ) ;
97+ await this . page . fill ( this . passwordInput , '' ) ;
98+ await this . page . waitForTimeout ( 1000 ) ;
99+ } else {
100+ console . log ( 'Max login attempts reached' ) ;
101+ }
102+
103+ } catch ( error ) {
104+ console . log ( `Login attempt ${ attempt } failed:` , error . message ) ;
105+ if ( attempt >= maxRetries ) {
106+ throw error ;
107+ }
108+ }
109+ }
110+
111+ await this . page . waitForSelector ( this . submitButton , { timeout : 10000 } ) ;
112+ await this . page . click ( this . submitButton ) ;
113+ }
114+
115+ /**
116+ * Feature: PayPal login error handling
117+ * Scenario: User enters invalid PayPal credentials
118+ * Given the user is on the PayPal login page
119+ * When the user enters invalid credentials
120+ * Then an error message should be displayed
121+ */
122+ async handleLoginError ( invalidCredentials : {
123+ user : string ;
124+ pw : string ;
125+ } ) {
126+ await this . page . waitForSelector ( this . emailInput ) ;
127+
128+ await this . page . fill ( this . emailInput , invalidCredentials . user ) ;
129+ await this . page . fill ( this . passwordInput , invalidCredentials . pw ) ;
130+ await this . page . click ( this . loginButton ) ;
131+
132+ const errorSelector = '#errorSection' ;
133+ await this . page . waitForSelector ( errorSelector ) ;
134+ return this . page . textContent ( errorSelector ) ;
135+ }
136+
137+ /**
138+ * Feature: PayPal payment cancellation
139+ * Scenario: User cancels PayPal payment
140+ * Given the user is on the PayPal payment confirmation page
141+ * When the user clicks the cancel link
142+ * Then they should be redirected back to the merchant site
143+ */
144+ async cancelPayment ( ) {
145+ const cancelLinkSelector = '#cancelLink' ;
146+ await this . page . waitForSelector ( cancelLinkSelector ) ;
147+ await this . page . click ( cancelLinkSelector ) ;
148+ await this . page . waitForNavigation ( { waitUntil : 'networkidle' } ) ;
149+ }
150+
151+ /**
152+ * Feature: PayPal error handling
153+ * Scenario: PayPal payment fails
154+ * Given the user has initiated a PayPal payment
155+ * When there's an error processing the payment
156+ * Then an error message should be displayed
157+ */
158+ async handlePaymentError ( ) {
159+ await this . page . waitForSelector ( this . errorMessage ) ;
160+ return this . page . textContent ( this . errorMessage ) ;
161+ }
162+ }
0 commit comments