Skip to content

Commit 9376ce0

Browse files
authored
Prevent duplicate order failure by selling different products on saved card E2E tests (#10230)
1 parent c08a83c commit 9376ce0

File tree

3 files changed

+148
-115
lines changed

3 files changed

+148
-115
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+
Fix flakiness in saved card tests caused by selling the same cart multiple times, triggering duplicate order protection

tests/e2e-pw/specs/shopper/shopper-myaccount-saved-cards.spec.ts

Lines changed: 126 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,43 @@ import {
2121
} from '../../utils/shopper';
2222
import RestAPI from '../../utils/rest-api';
2323

24+
type TestVariablesType = {
25+
[ key: string ]: {
26+
card: typeof config.cards.basic;
27+
address: {
28+
country: string;
29+
postalCode: string;
30+
};
31+
products: [ string, number ][];
32+
};
33+
};
34+
2435
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 };
36+
basic: {
37+
card: config.cards.basic,
38+
address: {
39+
country: 'US',
40+
postalCode: '94110',
41+
},
42+
products: [ [ 'Beanie', 1 ] ],
43+
},
44+
'3ds': {
45+
card: config.cards[ '3ds' ],
46+
address: {
47+
country: 'US',
48+
postalCode: '94110',
49+
},
50+
products: [ [ 'Belt', 1 ] ],
51+
},
52+
'3ds2': {
53+
card: config.cards[ '3ds2' ],
54+
address: {
55+
country: 'US',
56+
postalCode: '94110',
57+
},
58+
products: [ [ 'Cap', 1 ] ],
59+
},
60+
} as TestVariablesType;
2961

3062
test.describe( 'Shopper can save and delete cards', () => {
3163
let timeAdded: number;
@@ -80,10 +112,6 @@ test.describe( 'Shopper can save and delete cards', () => {
80112
)
81113
).toBeVisible();
82114

83-
await expect(
84-
shopperPage.getByText( 'Payment method successfully added' )
85-
).not.toBeVisible();
86-
87115
await expect(
88116
shopperPage.getByText(
89117
`${ config.cards.basic2.expires.month }/${ config.cards.basic2.expires.year }`
@@ -96,104 +124,102 @@ test.describe( 'Shopper can save and delete cards', () => {
96124
await deleteSavedCard( shopperPage, config.cards.basic );
97125
} );
98126

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',
127+
Object.entries( cards ).forEach(
128+
( [ cardName, { card, address, products } ] ) => {
129+
test.describe( 'Testing card: ' + cardName, () => {
130+
test( `should add the ${ cardName } card as a new payment method`, async () => {
131+
await goToMyAccount( shopperPage, 'payment-methods' );
132+
await addSavedCard(
133+
shopperPage,
134+
card,
135+
address.country,
136+
address.postalCode
137+
);
138+
// Take note of the time when we added this card
139+
timeAdded = +Date.now();
140+
141+
if ( cardName === '3ds' || cardName === '3ds2' ) {
142+
await confirmCardAuthentication( shopperPage );
143+
}
144+
145+
await shopperPage.waitForURL(
146+
/\/my-account\/payment-methods/,
147+
{
148+
waitUntil: 'load',
149+
}
150+
);
151+
152+
// Verify that the card was added
153+
await expect(
154+
shopperPage.getByText(
155+
'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.'
156+
)
157+
).not.toBeVisible();
158+
159+
await expect(
160+
shopperPage.getByText(
161+
`${ card.expires.month }/${ card.expires.year }`
162+
)
163+
).toBeVisible();
164+
165+
await waitTwentySecondsSinceLastCardAdded( shopperPage );
113166
} );
114167

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' ) {
168+
test( `should be able to purchase with the saved ${ cardName } card`, async () => {
169+
await goToShop( shopperPage );
170+
await setupProductCheckout( shopperPage, products );
171+
await selectSavedCardOnCheckout( shopperPage, card );
140172
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',
173+
if ( cardName !== 'basic' ) {
174+
await confirmCardAuthentication( shopperPage );
175+
}
176+
await shopperPage.waitForURL( /\/order-received\//, {
177+
waitUntil: 'load',
178+
} );
179+
await expect(
180+
shopperPage.getByRole( 'heading', {
181+
name: 'Order received',
182+
} )
183+
).toBeVisible();
150184
} );
151-
await expect(
152-
shopperPage.getByRole( 'heading', {
153-
name: 'Order received',
154-
} )
155-
).toBeVisible();
156-
} );
157185

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-
} );
186+
test( `should be able to set the ${ cardName } card as default payment method`, async () => {
187+
await goToMyAccount( shopperPage, 'payment-methods' );
188+
await addSavedCard( shopperPage, card2, 'US', '94110' );
189+
// Take note of the time when we added this card
190+
timeAdded = +Date.now();
191+
192+
await expect(
193+
shopperPage.getByText(
194+
`${ card2.expires.month }/${ card2.expires.year }`
195+
)
196+
).toBeVisible();
197+
await setDefaultPaymentMethod( shopperPage, card2 );
198+
// Verify that the card was set as default
199+
await expect(
200+
shopperPage.getByText(
201+
'This payment method was successfully set as your default.'
202+
)
203+
).toBeVisible();
204+
} );
180205

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-
} );
206+
test( `should be able to delete ${ cardName } card`, async () => {
207+
await goToMyAccount( shopperPage, 'payment-methods' );
208+
await deleteSavedCard( shopperPage, card );
209+
await expect(
210+
shopperPage.getByText( 'Payment method deleted.' )
211+
).toBeVisible();
212+
213+
await deleteSavedCard( shopperPage, card2 );
214+
await expect(
215+
shopperPage.getByText( 'Payment method deleted.' )
216+
).toBeVisible();
217+
} );
193218

194-
test.afterAll( async () => {
195-
waitTwentySecondsSinceLastCardAdded( shopperPage );
219+
test.afterAll( async () => {
220+
await waitTwentySecondsSinceLastCardAdded( shopperPage );
221+
} );
196222
} );
197-
} );
198-
} );
223+
}
224+
);
199225
} );

tests/e2e-pw/utils/shopper.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -437,32 +437,35 @@ export const deleteSavedCard = async (
437437
page: Page,
438438
card: typeof config.cards.basic
439439
) => {
440-
await page
441-
.getByRole( 'row', { name: card.label } )
442-
.first()
443-
.getByRole( 'link', { name: 'Delete' } )
444-
.click();
445-
await page.waitForTimeout( 1000 );
446-
await expect( page.getByText( 'Payment method deleted.' ) ).toBeVisible();
440+
const row = page.getByRole( 'row', { name: card.label } ).first();
441+
await expect( row ).toBeVisible( { timeout: 100 } );
442+
const button = row.getByRole( 'link', { name: 'Delete' } );
443+
await expect( button ).toBeVisible( { timeout: 100 } );
444+
await expect( button ).toBeEnabled( { timeout: 100 } );
445+
await button.click();
447446
};
448447

449448
export const selectSavedCardOnCheckout = async (
450449
page: Page,
451450
card: typeof config.cards.basic
452-
) =>
453-
await page
451+
) => {
452+
const option = page
454453
.getByText(
455454
`${ card.label } (expires ${ card.expires.month }/${ card.expires.year })`
456455
)
457-
.click();
456+
.first();
457+
await expect( option ).toBeVisible( { timeout: 100 } );
458+
option.click();
459+
};
458460

459461
export const setDefaultPaymentMethod = async (
460462
page: Page,
461463
card: typeof config.cards.basic
462464
) => {
463-
await page
464-
.getByRole( 'row', { name: card.label } )
465-
.first()
466-
.getByRole( 'link', { name: 'Make default' } )
467-
.click();
465+
const row = page.getByRole( 'row', { name: card.label } ).first();
466+
await expect( row ).toBeVisible( { timeout: 100 } );
467+
const button = row.getByRole( 'link', { name: 'Make default' } );
468+
await expect( button ).toBeVisible( { timeout: 100 } );
469+
await expect( button ).toBeEnabled( { timeout: 100 } );
470+
button.click();
468471
};

0 commit comments

Comments
 (0)