Skip to content

Commit 9797cfd

Browse files
committed
refactor(e2e): verify mutation persistence via re-navigation
The update and default-address-toggle tests were asserting against DOM state that persists regardless of mutation success. The form uses uncontrolled inputs (defaultValue/defaultChecked), so user-typed values survive React re-renders even when the MSW mutation fails silently. Both tests now re-navigate after the mutation, forcing fresh component mounts that can only render data from MSW closure state. This ensures the assertions verify server-side persistence, not stale DOM values. The completion signal (button text check) was also a race condition - it could pass immediately before React re-rendered to the loading state. Replaced with waitForLoadState('networkidle') which reliably waits for the full action + revalidation cycle to complete. Also uses MSW_SCENARIOS constant in smoke test for consistency.
1 parent fa84d86 commit 9797cfd

File tree

3 files changed

+21
-15
lines changed

3 files changed

+21
-15
lines changed

e2e/fixtures/delivery-address-utils.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {expect, Locator, Page} from '@playwright/test';
22

33
export const EMPTY_STATE_MESSAGE = 'You have no addresses saved.';
4-
const FORM_SUBMISSION_TIMEOUT_IN_MS = 10_000;
54

65
export interface AddressFormData {
76
firstName: string;
@@ -87,26 +86,20 @@ export class DeliveryAddressUtil {
8786
await this.fillAddressForm(form, data);
8887
const createButton = form.getByRole('button', {name: 'Create'});
8988
await createButton.click();
90-
await expect(createButton).toHaveText('Create', {
91-
timeout: FORM_SUBMISSION_TIMEOUT_IN_MS,
92-
});
89+
await this.page.waitForLoadState('networkidle');
9390
}
9491

9592
async updateAddress(form: Locator, data: Partial<AddressFormData>) {
9693
await this.fillAddressForm(form, data);
9794
const saveButton = form.getByRole('button', {name: 'Save'});
9895
await saveButton.click();
99-
await expect(saveButton).toHaveText('Save', {
100-
timeout: FORM_SUBMISSION_TIMEOUT_IN_MS,
101-
});
96+
await this.page.waitForLoadState('networkidle');
10297
}
10398

10499
async deleteAddress(form: Locator) {
105100
const deleteButton = form.getByRole('button', {name: 'Delete'});
106101
await deleteButton.click();
107-
await expect(deleteButton).not.toBeVisible({
108-
timeout: FORM_SUBMISSION_TIMEOUT_IN_MS,
109-
});
102+
await this.page.waitForLoadState('networkidle');
110103
}
111104

112105
async assertAddressCount(count: number) {

e2e/specs/skeleton/deliveryAddresses.spec.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ test.describe('Delivery Addresses', () => {
8888
await expect(targetForm.getByLabel('City')).not.toHaveValue(updatedCity);
8989
await addresses.updateAddress(targetForm, {city: updatedCity});
9090

91-
await expect(targetForm.getByLabel('City')).toHaveValue(updatedCity);
91+
// Re-navigate to verify the mutation persisted in MSW closure state.
92+
// Without this, the assertion would pass from the user-typed DOM value
93+
// alone, since the form uses uncontrolled inputs (defaultValue).
94+
await addresses.navigateToAddresses();
95+
await addresses.assertAddressVisible({city: updatedCity});
9296
});
9397
});
9498

@@ -106,8 +110,17 @@ test.describe('Delivery Addresses', () => {
106110

107111
await addresses.updateAddress(secondForm, {defaultAddress: true});
108112

109-
await expect(secondForm.getByRole('checkbox')).toBeChecked();
110-
await expect(firstForm.getByRole('checkbox')).not.toBeChecked();
113+
// Re-navigate to verify the default toggle persisted in MSW state.
114+
// The checkbox uses defaultChecked (uncontrolled), and key={address.id}
115+
// is stable across default-toggle updates, so React reconciles in place
116+
// without resetting the checkbox DOM state. Fresh mount is needed.
117+
await addresses.navigateToAddresses();
118+
119+
const refreshedForms = addresses.getExistingAddresses();
120+
await expect(
121+
refreshedForms.first().getByRole('checkbox'),
122+
).not.toBeChecked();
123+
await expect(refreshedForms.nth(1).getByRole('checkbox')).toBeChecked();
111124
});
112125
});
113126

e2e/specs/smoke/account.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import {setTestStore, test} from '../../fixtures';
1+
import {setTestStore, test, MSW_SCENARIOS} from '../../fixtures';
22
import {AccountUtil} from '../../fixtures/account-utils';
33

44
setTestStore('mockShop', {
55
mock: {
6-
scenario: 'customer-account-logged-in',
6+
scenario: MSW_SCENARIOS.customerAccountLoggedIn,
77
},
88
});
99

0 commit comments

Comments
 (0)