Skip to content

Commit ff92692

Browse files
authored
Convert shopper checkout purchase with UPE tests to Playwright (#10203)
1 parent 5a68b21 commit ff92692

11 files changed

+495
-334
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: dev
3+
4+
Convert shopper checkout with UPE methods E2E test to Playwright, split saving card tests to separate file

tests/e2e-pw/config/default.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,35 @@ export const config = {
7474
7575
},
7676
},
77+
'upe-customer': {
78+
billing: {
79+
be: {
80+
firstname: 'I am',
81+
lastname: 'Customer',
82+
company: 'Automattic',
83+
country: 'Belgium',
84+
addressfirstline: 'Rue de l’Étuve, 1000',
85+
addresssecondline: 'billing-be',
86+
city: 'Bruxelles',
87+
postcode: '1000',
88+
phone: '123456789',
89+
90+
},
91+
de: {
92+
firstname: 'I am',
93+
lastname: 'Customer',
94+
company: 'Automattic',
95+
country: 'Germany',
96+
addressfirstline: 'Petuelring 130',
97+
addresssecondline: 'billing-de',
98+
city: 'München',
99+
postcode: '80809',
100+
state: 'DE-BY',
101+
phone: '123456789',
102+
103+
},
104+
},
105+
},
77106
'subscriptions-customer': {
78107
billing: {
79108
firstname: 'I am',
@@ -125,11 +154,11 @@ export const config = {
125154
basic3: {
126155
number: '378282246310005',
127156
expires: {
128-
month: '11',
157+
month: '12',
129158
year: '45',
130159
},
131160
cvc: '1234',
132-
label: 'Amex ending in 0005',
161+
label: 'American Express ending in 0005',
133162
},
134163
'3ds': {
135164
number: '4000002760003184',
@@ -272,4 +301,9 @@ export const config = {
272301
},
273302
};
274303

275-
export type CustomerAddress = typeof config.addresses.customer.billing;
304+
export type CustomerAddress = Omit<
305+
typeof config.addresses.customer.billing,
306+
'state'
307+
> & {
308+
state?: string;
309+
};
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import test, { Page, expect } from '@playwright/test';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import {
10+
activateMulticurrency,
11+
addCurrency,
12+
deactivateMulticurrency,
13+
disablePaymentMethods,
14+
enablePaymentMethods,
15+
restoreCurrencies,
16+
} from '../../utils/merchant';
17+
import { getShopper, getMerchant } from '../../utils/helpers';
18+
import {
19+
disableCardTestingProtection,
20+
enableCardTestingProtection,
21+
} from '../../utils/devtools';
22+
import {
23+
addToCartFromShopPage,
24+
changeAccountCurrency,
25+
emptyCart,
26+
expectFraudPreventionToken,
27+
fillBillingAddress,
28+
focusPlaceOrderButton,
29+
placeOrder,
30+
} from '../../utils/shopper';
31+
import { config } from '../../config/default';
32+
import { goToCheckout, goToShop } from '../../utils/shopper-navigation';
33+
34+
test.describe( 'Enable UPE with deferred intent creation', () => {
35+
let wasMultiCurrencyEnabled = false;
36+
let merchantPage: Page, shopperPage: Page;
37+
test.beforeAll( async ( { browser } ) => {
38+
// Open browsers.
39+
merchantPage = ( await getMerchant( browser ) ).merchantPage;
40+
shopperPage = ( await getShopper( browser ) ).shopperPage;
41+
42+
// Prepare merchant side of tests.
43+
wasMultiCurrencyEnabled = await activateMulticurrency( merchantPage );
44+
await addCurrency( merchantPage, 'EUR' );
45+
await enablePaymentMethods( merchantPage, [ 'bancontact' ] );
46+
// Prepare shopper side of tests.
47+
await changeAccountCurrency(
48+
shopperPage,
49+
config.addresses.customer.billing,
50+
'EUR'
51+
);
52+
await emptyCart( shopperPage );
53+
} );
54+
55+
test.afterAll( async () => {
56+
// Restore shopper side of tests.
57+
await emptyCart( shopperPage );
58+
59+
// Restore merchant side of tests
60+
await disablePaymentMethods( merchantPage, [ 'bancontact' ] );
61+
await restoreCurrencies( merchantPage );
62+
if ( ! wasMultiCurrencyEnabled ) {
63+
await deactivateMulticurrency( merchantPage );
64+
}
65+
} );
66+
67+
const testBancontactOrder = async (
68+
cardTestingPreventionState: boolean
69+
) => {
70+
await goToShop( shopperPage );
71+
await addToCartFromShopPage( shopperPage, 'Beanie' );
72+
await goToCheckout( shopperPage );
73+
await fillBillingAddress(
74+
shopperPage,
75+
config.addresses[ 'upe-customer' ].billing.be
76+
);
77+
await shopperPage.waitForLoadState( 'networkidle' );
78+
await expectFraudPreventionToken(
79+
shopperPage,
80+
cardTestingPreventionState
81+
);
82+
await shopperPage.getByText( 'Bancontact' ).click();
83+
await focusPlaceOrderButton( shopperPage );
84+
await placeOrder( shopperPage );
85+
await shopperPage.waitForLoadState( 'networkidle' );
86+
await shopperPage
87+
.getByRole( 'link', {
88+
name: 'Authorize Test Payment',
89+
} )
90+
.click();
91+
await expect(
92+
shopperPage.getByText( 'Order received' ).first()
93+
).toBeVisible();
94+
};
95+
96+
test.describe( 'Card testing prevention enabled', () => {
97+
test.beforeAll( async () => {
98+
await enableCardTestingProtection( merchantPage );
99+
} );
100+
test.afterAll( async () => {
101+
await disableCardTestingProtection( merchantPage );
102+
} );
103+
test( 'should successfully place order with Bancontact', async () => {
104+
await testBancontactOrder( true );
105+
} );
106+
} );
107+
108+
test.describe( 'Card testing prevention disabled', () => {
109+
test( 'should successfully place order with Bancontact', async () => {
110+
await testBancontactOrder( false );
111+
} );
112+
} );
113+
} );
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import test, { Page, expect } from '@playwright/test';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import { config } from '../../config/default';
10+
import { goToMyAccount, goToShop } from '../../utils/shopper-navigation';
11+
import { getAnonymousShopper } from '../../utils/helpers';
12+
import {
13+
addSavedCard,
14+
confirmCardAuthentication,
15+
deleteSavedCard,
16+
placeOrder,
17+
placeOrderWithOptions,
18+
selectSavedCardOnCheckout,
19+
setDefaultPaymentMethod,
20+
setupProductCheckout,
21+
} from '../../utils/shopper';
22+
import RestAPI from '../../utils/rest-api';
23+
24+
const cards = {
25+
basic: config.cards.basic,
26+
'3ds': config.cards[ '3ds' ],
27+
'3ds2': config.cards[ '3ds2' ],
28+
} as { [ key: string ]: typeof config.cards.basic };
29+
30+
test.describe( 'Shopper can save and delete cards', () => {
31+
let timeAdded: number;
32+
// Use cards different than other tests to prevent conflicts.
33+
const card2 = config.cards.basic3;
34+
let shopperPage: Page = null;
35+
const customerBillingConfig =
36+
config.addresses[ 'subscriptions-customer' ].billing;
37+
38+
test.beforeAll( async ( { browser }, { project } ) => {
39+
// Delete the user, if present, and create a new one with a new order.
40+
// This is required to avoid running this test on a customer that already has a saved card.
41+
const restApi = new RestAPI( project.use.baseURL );
42+
await restApi.deleteCustomerByEmailAddress(
43+
customerBillingConfig.email
44+
);
45+
46+
shopperPage = ( await getAnonymousShopper( browser ) ).shopperPage;
47+
await placeOrderWithOptions( shopperPage, {
48+
billingAddress: customerBillingConfig,
49+
createAccount: true,
50+
} );
51+
} );
52+
53+
async function waitTwentySecondsSinceLastCardAdded( page: Page ) {
54+
// Make sure that at least 20s had already elapsed since the last card was added.
55+
// Otherwise, you will get the error message,
56+
// "You cannot add a new payment method so soon after the previous one."
57+
// Source: /docker/wordpress/wp-content/plugins/woocommerce/includes/class-wc-form-handler.php#L509-L521
58+
const timeTestFinished = Date.now();
59+
const elapsedWaitTime = timeTestFinished - timeAdded;
60+
const remainingWaitTime =
61+
20000 > elapsedWaitTime ? 20000 - elapsedWaitTime : 0;
62+
63+
await page.waitForTimeout( remainingWaitTime );
64+
}
65+
66+
// No need to run this test for all card types.
67+
test( 'prevents adding another card for 20 seconds after a card is added', async () => {
68+
await goToMyAccount( shopperPage, 'payment-methods' );
69+
// Take note of the time when we added this card
70+
await addSavedCard( shopperPage, config.cards.basic, 'US', '94110' );
71+
timeAdded = +Date.now();
72+
73+
// Try to add a new card before 20 seconds have passed
74+
await addSavedCard( shopperPage, config.cards.basic2, 'US', '94110' );
75+
76+
// Verify that the card was not added
77+
await expect(
78+
shopperPage.getByText(
79+
'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.'
80+
)
81+
).toBeVisible();
82+
83+
await expect(
84+
shopperPage.getByText( 'Payment method successfully added' )
85+
).not.toBeVisible();
86+
87+
await expect(
88+
shopperPage.getByText(
89+
`${ config.cards.basic2.expires.month }/${ config.cards.basic2.expires.year }`
90+
)
91+
).not.toBeVisible();
92+
93+
await waitTwentySecondsSinceLastCardAdded( shopperPage );
94+
// cleanup for the next tests
95+
await goToMyAccount( shopperPage, 'payment-methods' );
96+
await deleteSavedCard( shopperPage, config.cards.basic );
97+
} );
98+
99+
Object.entries( cards ).forEach( ( [ cardName, card ] ) => {
100+
test.describe( 'Testing card: ' + cardName, () => {
101+
test( `should add the ${ cardName } card as a new payment method`, async () => {
102+
await goToMyAccount( shopperPage, 'payment-methods' );
103+
await addSavedCard( shopperPage, card, 'US', '94110' );
104+
// Take note of the time when we added this card
105+
timeAdded = +Date.now();
106+
107+
if ( cardName === '3ds' || cardName === '3ds2' ) {
108+
await confirmCardAuthentication( shopperPage );
109+
}
110+
111+
await shopperPage.waitForURL( /\/my-account\/payment-methods/, {
112+
waitUntil: 'load',
113+
} );
114+
115+
// Verify that the card was added
116+
await expect(
117+
shopperPage.getByText(
118+
'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.'
119+
)
120+
).not.toBeVisible();
121+
122+
await expect(
123+
shopperPage.getByText( 'Payment method successfully added' )
124+
).toBeVisible();
125+
126+
await expect(
127+
shopperPage.getByText(
128+
`${ card.expires.month }/${ card.expires.year }`
129+
)
130+
).toBeVisible();
131+
132+
await waitTwentySecondsSinceLastCardAdded( shopperPage );
133+
} );
134+
135+
test( `should be able to purchase with the saved ${ cardName } card`, async () => {
136+
await goToShop( shopperPage );
137+
await setupProductCheckout( shopperPage );
138+
await selectSavedCardOnCheckout( shopperPage, card );
139+
if ( cardName === 'basic' ) {
140+
await placeOrder( shopperPage );
141+
} else {
142+
await shopperPage
143+
.getByRole( 'button', { name: 'Place order' } )
144+
.click();
145+
await confirmCardAuthentication( shopperPage );
146+
}
147+
148+
await shopperPage.waitForURL( /\/order-received\//, {
149+
waitUntil: 'load',
150+
} );
151+
await expect(
152+
shopperPage.getByRole( 'heading', {
153+
name: 'Order received',
154+
} )
155+
).toBeVisible();
156+
} );
157+
158+
test( `should be able to set the ${ cardName } card as default payment method`, async () => {
159+
await goToMyAccount( shopperPage, 'payment-methods' );
160+
await addSavedCard( shopperPage, card2, 'US', '94110' );
161+
// Take note of the time when we added this card
162+
timeAdded = +Date.now();
163+
164+
await expect(
165+
shopperPage.getByText( 'Payment method successfully added' )
166+
).toBeVisible();
167+
await expect(
168+
shopperPage.getByText(
169+
`${ card2.expires.month }/${ card2.expires.year }`
170+
)
171+
).toBeVisible();
172+
await setDefaultPaymentMethod( shopperPage, card2 );
173+
// Verify that the card was set as default
174+
await expect(
175+
shopperPage.getByText(
176+
'This payment method was successfully set as your default.'
177+
)
178+
).toBeVisible();
179+
} );
180+
181+
test( `should be able to delete ${ cardName } card`, async () => {
182+
await goToMyAccount( shopperPage, 'payment-methods' );
183+
await deleteSavedCard( shopperPage, card );
184+
await expect(
185+
shopperPage.getByText( 'Payment method deleted.' )
186+
).toBeVisible();
187+
188+
await deleteSavedCard( shopperPage, card2 );
189+
await expect(
190+
shopperPage.getByText( 'Payment method deleted.' )
191+
).toBeVisible();
192+
} );
193+
194+
test.afterAll( async () => {
195+
waitTwentySecondsSinceLastCardAdded( shopperPage );
196+
} );
197+
} );
198+
} );
199+
} );

0 commit comments

Comments
 (0)