Skip to content

Commit a7083fa

Browse files
chanceaclarkclaude
andcommitted
fix(core): add retry patterns to flaky shipping, cart, and compare E2E tests
Replace bare try/catch + single page.reload() with the established expect().toPass() retry pattern (from product.spec.ts) across all flaky assertion points. This handles Next.js server action state propagation delays [CATALYST-1685] and currency switch re-render lag. Refs TRAC-281 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 3179322 commit a7083fa

File tree

3 files changed

+117
-82
lines changed

3 files changed

+117
-82
lines changed

core/tests/ui/e2e/cart.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ test('Cart page displays line item', async ({ page, catalog, currency }) => {
2727
cartLink: (chunks: React.ReactNode) => chunks,
2828
}) as string;
2929

30-
await expect(page.getByText(addToCartSuccessMessage)).toBeVisible();
30+
await expect(async () => {
31+
try {
32+
await expect(page.getByText(addToCartSuccessMessage)).toBeVisible();
33+
} catch {
34+
await page.reload();
35+
await expect(page.getByText(addToCartSuccessMessage)).toBeVisible();
36+
}
37+
}).toPass({ timeout: 30000, intervals: [2000] });
3138

3239
await page.goto('/cart');
3340

core/tests/ui/e2e/compare.spec.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ test('Validate compare page', async ({ page, catalog, currency }) => {
3737
});
3838

3939
test('Validate compare page with alternate currency', async ({ page, catalog, currency }) => {
40+
// Currency switch re-render can be delayed; retry with reload
41+
test.setTimeout(90000);
42+
4043
const format = getFormatter();
4144
const defaultCurrency = await currency.getDefaultCurrency();
4245
const alternateCurrency = (await currency.getEnabledCurrencies()).find(
@@ -77,8 +80,6 @@ test('Validate compare page with alternate currency', async ({ page, catalog, cu
7780
currency: alternateCurrency,
7881
});
7982

80-
await expect(page.getByText(formattedProductPrice)).toBeVisible();
81-
8283
const productWithVariantsPriceConverted = await currency.convertWithExchangeRate(
8384
alternateCurrency,
8485
productWithVariants.price,
@@ -89,7 +90,17 @@ test('Validate compare page with alternate currency', async ({ page, catalog, cu
8990
currency: alternateCurrency,
9091
});
9192

92-
await expect(page.getByText(formattedProductWithVariantsPrice).first()).toBeVisible();
93+
await expect(async () => {
94+
try {
95+
await expect(page.getByText(formattedProductPrice)).toBeVisible();
96+
await expect(page.getByText(formattedProductWithVariantsPrice).first()).toBeVisible();
97+
} catch {
98+
await page.reload();
99+
await page.waitForLoadState('networkidle');
100+
await expect(page.getByText(formattedProductPrice)).toBeVisible();
101+
await expect(page.getByText(formattedProductWithVariantsPrice).first()).toBeVisible();
102+
}
103+
}).toPass({ timeout: 90000, intervals: [2000] });
93104
});
94105

95106
test('Can add simple product to cart', async ({ page, catalog }) => {

core/tests/ui/e2e/shipping.spec.ts

Lines changed: 95 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ async function selectRandomShippingOption(page: Page): Promise<string> {
6666
}
6767

6868
test('Add shipping estimates', async ({ page, catalog }) => {
69+
// Shipping state assertions are flaky due to Next.js server action state propagation [CATALYST-1685]
70+
test.setTimeout(90000);
71+
6972
const t = await getTranslations('Cart.CheckoutSummary.Shipping');
7073

7174
await addProductAndGoToCart(page, catalog);
@@ -78,29 +81,34 @@ test('Add shipping estimates', async ({ page, catalog }) => {
7881

7982
await page.getByRole('button', { name: t('viewShippingOptions') }).click();
8083

81-
try {
82-
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
83-
} catch {
84-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
85-
await page.reload();
86-
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
87-
}
84+
await expect(async () => {
85+
try {
86+
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
87+
} catch {
88+
await page.reload();
89+
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
90+
}
91+
}).toPass({ timeout: 90000, intervals: [2000] });
8892

8993
const selectedOption = await selectRandomShippingOption(page);
9094

9195
await page.getByRole('button', { name: t('addShipping') }).click();
9296
await page.waitForLoadState('networkidle');
9397

94-
try {
95-
await expect(page.getByText(`${selectedOption}${t('change')}`)).toBeVisible();
96-
} catch {
97-
await page.reload();
98-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
99-
await expect(page.getByText(`${selectedOption}${t('change')}`)).toBeVisible();
100-
}
98+
await expect(async () => {
99+
try {
100+
await expect(page.getByText(`${selectedOption}${t('change')}`)).toBeVisible();
101+
} catch {
102+
await page.reload();
103+
await expect(page.getByText(`${selectedOption}${t('change')}`)).toBeVisible();
104+
}
105+
}).toPass({ timeout: 90000, intervals: [2000] });
101106
});
102107

103108
test('Update shipping estimates', async ({ page, catalog }) => {
109+
// Shipping state assertions are flaky due to Next.js server action state propagation [CATALYST-1685]
110+
test.setTimeout(90000);
111+
104112
const t = await getTranslations('Cart.CheckoutSummary.Shipping');
105113

106114
await addProductAndGoToCart(page, catalog);
@@ -113,28 +121,30 @@ test('Update shipping estimates', async ({ page, catalog }) => {
113121

114122
await page.getByRole('button', { name: t('viewShippingOptions') }).click();
115123

116-
try {
117-
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
118-
} catch {
119-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
120-
await page.reload();
121-
await page.waitForLoadState('networkidle');
122-
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
123-
}
124+
await expect(async () => {
125+
try {
126+
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
127+
} catch {
128+
await page.reload();
129+
await page.waitForLoadState('networkidle');
130+
await expect(page.getByLabel(t('shippingOptions'))).toBeVisible();
131+
}
132+
}).toPass({ timeout: 90000, intervals: [2000] });
124133

125134
let selectedOption = await selectRandomShippingOption(page);
126135

127136
await page.getByRole('button', { name: t('addShipping') }).click();
128137
await page.waitForLoadState('networkidle');
129138

130-
try {
131-
await expect(page.getByText(t('change'))).toBeVisible();
132-
} catch {
133-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
134-
await page.reload();
135-
await page.waitForLoadState('networkidle');
136-
await expect(page.getByText(t('change'))).toBeVisible();
137-
}
139+
await expect(async () => {
140+
try {
141+
await expect(page.getByText(t('change'))).toBeVisible();
142+
} catch {
143+
await page.reload();
144+
await page.waitForLoadState('networkidle');
145+
await expect(page.getByText(t('change'))).toBeVisible();
146+
}
147+
}).toPass({ timeout: 90000, intervals: [2000] });
138148

139149
await page.getByText(t('change')).click();
140150
await page.getByRole('button', { name: t('editAddress') }).click();
@@ -143,14 +153,15 @@ test('Update shipping estimates', async ({ page, catalog }) => {
143153

144154
await page.getByRole('button', { name: t('updatedShippingOptions') }).click();
145155

146-
try {
147-
await expect(page.getByRole('button', { name: t('updatedShippingOptions') })).toBeHidden();
148-
} catch {
149-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
150-
await page.reload();
151-
await page.waitForLoadState('networkidle');
152-
await expect(page.getByRole('button', { name: t('updatedShippingOptions') })).toBeHidden();
153-
}
156+
await expect(async () => {
157+
try {
158+
await expect(page.getByRole('button', { name: t('updatedShippingOptions') })).toBeHidden();
159+
} catch {
160+
await page.reload();
161+
await page.waitForLoadState('networkidle');
162+
await expect(page.getByRole('button', { name: t('updatedShippingOptions') })).toBeHidden();
163+
}
164+
}).toPass({ timeout: 90000, intervals: [2000] });
154165

155166
if (await page.getByLabel(t('shippingOptions')).isVisible()) {
156167
selectedOption = await selectRandomShippingOption(page);
@@ -165,6 +176,9 @@ test('Updating cart quantity with a shipping estimate opens the shipping options
165176
page,
166177
catalog,
167178
}) => {
179+
// Shipping state assertions are flaky due to Next.js server action state propagation [CATALYST-1685]
180+
test.setTimeout(90000);
181+
168182
const t = await getTranslations('Cart');
169183

170184
await addProductAndGoToCart(page, catalog);
@@ -179,59 +193,62 @@ test('Updating cart quantity with a shipping estimate opens the shipping options
179193
.getByRole('button', { name: t('CheckoutSummary.Shipping.viewShippingOptions') })
180194
.click();
181195

182-
try {
183-
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
184-
} catch {
185-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
186-
await page.reload();
187-
await page.waitForLoadState('networkidle');
188-
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
189-
}
196+
await expect(async () => {
197+
try {
198+
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
199+
} catch {
200+
await page.reload();
201+
await page.waitForLoadState('networkidle');
202+
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
203+
}
204+
}).toPass({ timeout: 90000, intervals: [2000] });
190205

191206
let selectedOption = await selectRandomShippingOption(page);
192207

193208
await page.getByRole('button', { name: t('CheckoutSummary.Shipping.addShipping') }).click();
194209
await page.waitForLoadState('networkidle');
195210

196-
try {
197-
await expect(
198-
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
199-
).toBeVisible();
200-
} catch {
201-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
202-
await page.reload();
203-
await expect(
204-
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
205-
).toBeVisible();
206-
}
211+
await expect(async () => {
212+
try {
213+
await expect(
214+
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
215+
).toBeVisible();
216+
} catch {
217+
await page.reload();
218+
await expect(
219+
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
220+
).toBeVisible();
221+
}
222+
}).toPass({ timeout: 90000, intervals: [2000] });
207223

208224
await page.getByLabel(t('increment')).click();
209225
await page.waitForLoadState('networkidle');
210226

211-
try {
212-
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
213-
} catch {
214-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
215-
await page.reload();
216-
await page.waitForLoadState('networkidle');
217-
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
218-
}
227+
await expect(async () => {
228+
try {
229+
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
230+
} catch {
231+
await page.reload();
232+
await page.waitForLoadState('networkidle');
233+
await expect(page.getByLabel(t('CheckoutSummary.Shipping.shippingOptions'))).toBeVisible();
234+
}
235+
}).toPass({ timeout: 90000, intervals: [2000] });
219236

220237
selectedOption = await selectRandomShippingOption(page);
221238

222239
await page.getByRole('button', { name: t('CheckoutSummary.Shipping.addShipping') }).click();
223-
224-
try {
225-
await expect(
226-
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
227-
).toBeVisible();
228-
} catch {
229-
// TODO: Remove try/catch when root cause of next state issue is found/resolved [CATALYST-1685]
230-
await page.reload();
231-
}
232-
233240
await page.waitForLoadState('networkidle');
234-
await expect(
235-
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
236-
).toBeVisible();
241+
242+
await expect(async () => {
243+
try {
244+
await expect(
245+
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
246+
).toBeVisible();
247+
} catch {
248+
await page.reload();
249+
await expect(
250+
page.getByText(`${selectedOption}${t('CheckoutSummary.Shipping.change')}`),
251+
).toBeVisible();
252+
}
253+
}).toPass({ timeout: 90000, intervals: [2000] });
237254
});

0 commit comments

Comments
 (0)