Skip to content

Commit c4fb779

Browse files
committed
refactor: update load state waits from "networkidle" to "domcontentloaded" for improved test reliability
1 parent 6fb8c7a commit c4fb779

File tree

4 files changed

+35
-23
lines changed

4 files changed

+35
-23
lines changed

e2e/articles.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ test.describe("Authenticated Feed Page (Articles)", () => {
336336
);
337337

338338
// Wait for page to be fully loaded including all network requests
339-
await page.waitForLoadState("networkidle");
339+
await page.waitForLoadState("domcontentloaded");
340340

341341
// Wait for action bar to load - bookmark button shows either "Save" or "Saved"
342342
// depending on whether another parallel test has already bookmarked it

e2e/my-posts.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async function openTab(
1111
isMobile: boolean = false,
1212
) {
1313
await page.goto("http://localhost:3000/my-posts");
14-
await page.waitForLoadState("networkidle");
14+
await page.waitForLoadState("domcontentloaded");
1515

1616
// Mobile renders tabs as a select dropdown, desktop uses links
1717
if (isMobile) {
@@ -20,7 +20,7 @@ async function openTab(
2020
await expect(tabSelect).toBeEnabled({ timeout: 5000 });
2121
await tabSelect.selectOption({ label: tabName });
2222
// Wait for mobile navigation to settle
23-
await page.waitForLoadState("networkidle");
23+
await page.waitForLoadState("domcontentloaded");
2424
} else {
2525
await page.getByRole("link", { name: tabName }).click();
2626
}
@@ -37,7 +37,7 @@ async function openTab(
3737
});
3838

3939
// Wait for network to settle and content to load
40-
await page.waitForLoadState("networkidle");
40+
await page.waitForLoadState("domcontentloaded");
4141

4242
// Wait for at least one article to be visible with increased timeout for mobile
4343
await expect(page.locator("article").first()).toBeVisible({
@@ -131,9 +131,9 @@ test.describe("Authenticated my-posts Page", () => {
131131
timeout: 15000,
132132
});
133133
// Verify the article has a heading (h2)
134-
await expect(
135-
page.locator("article").first().locator("h2"),
136-
).toBeVisible({ timeout: 10000 });
134+
await expect(page.locator("article").first().locator("h2")).toBeVisible({
135+
timeout: 10000,
136+
});
137137
});
138138

139139
test("User should close delete modal with Cancel button", async ({

e2e/notifications.spec.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,27 +227,32 @@ test.describe("Notifications Page", () => {
227227
timeout: 15000,
228228
});
229229

230-
// Find the comment container that has the original comment text and click its first reply button
231-
const commentContainer = page
232-
.locator("article")
230+
// Find the comment section that has the original comment text and click its reply button
231+
// Discussion comments are wrapped in <section> elements with class "group/comment"
232+
const commentSection = page
233+
.locator("section.group\\/comment")
233234
.filter({ hasText: originalComment })
234235
.first();
235-
await commentContainer
236+
await commentSection
236237
.getByRole("button", { name: "Reply" })
237238
.first()
238239
.click();
239240

240241
// Wait for reply editor to expand
241242
await page.waitForTimeout(500);
242-
// Focus the reply editor and type - find the editor within the comment's reply section
243-
await page.locator(".ProseMirror").last().click();
243+
244+
// The reply editor appears within the same comment section
245+
// Find the ProseMirror editor that appeared after clicking Reply
246+
const replyEditor = commentSection.locator(".ProseMirror").first();
247+
await replyEditor.click();
244248
const replyText = `Reply to trigger notification ${randomUUID()}`;
245249
await page.keyboard.type(replyText);
246250

247-
// Submit the reply - use nth(1) to get the reply button in the form, not the expand button
248-
await page
251+
// Submit the reply - click the Reply button within the reply form
252+
// The submit button has the same text "Reply" as the expand button, but it's the last one
253+
await commentSection
249254
.getByRole("button", { name: "Reply", exact: true })
250-
.nth(1)
255+
.last()
251256
.click();
252257

253258
// Verify reply was posted - this confirms the mutation completed and notification was created

e2e/saved.spec.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ test.describe("Authenticated Saved Page", () => {
4040
);
4141

4242
// Wait for page to be fully loaded including network requests
43-
await page.waitForLoadState("networkidle");
43+
await page.waitForLoadState("domcontentloaded");
4444

4545
// Get the bookmark button - on article detail page it shows "Save" or "Saved"
4646
const saveButton = page.getByRole("button", { name: "Save" });
@@ -65,13 +65,20 @@ test.describe("Authenticated Saved Page", () => {
6565

6666
// Navigate to saved page
6767
await page.goto("http://localhost:3000/saved");
68-
await page.waitForLoadState("networkidle");
68+
await page.waitForLoadState("domcontentloaded");
6969

7070
// Verify the saved page loaded and shows either:
7171
// - The bookmarked article (if no parallel test unbookmarked it)
7272
// - Or at least the page loaded successfully
73-
const hasArticle = await page.locator("article").first().isVisible().catch(() => false);
74-
const hasEmptyState = await page.getByText("Your saved posts will show up here.").isVisible().catch(() => false);
73+
const hasArticle = await page
74+
.locator("article")
75+
.first()
76+
.isVisible()
77+
.catch(() => false);
78+
const hasEmptyState = await page
79+
.getByText("Your saved posts will show up here.")
80+
.isVisible()
81+
.catch(() => false);
7582

7683
// Either we have saved articles, or we see the empty state (parallel test interference)
7784
// Both are acceptable outcomes since we already verified the bookmark action succeeded
@@ -81,7 +88,7 @@ test.describe("Authenticated Saved Page", () => {
8188
test("Should navigate to content from saved items", async ({ page }) => {
8289
// First ensure there's a saved item
8390
await page.goto("http://localhost:3000/feed?type=article");
84-
await page.waitForLoadState("networkidle");
91+
await page.waitForLoadState("domcontentloaded");
8592
await page.waitForSelector("article");
8693

8794
// Click bookmark
@@ -92,7 +99,7 @@ test.describe("Authenticated Saved Page", () => {
9299

93100
// Go to saved page
94101
await page.goto("http://localhost:3000/saved");
95-
await page.waitForLoadState("networkidle");
102+
await page.waitForLoadState("domcontentloaded");
96103

97104
// Click on a saved item to navigate to it
98105
const firstLink = page.locator("article").first().locator("a").first();
@@ -114,7 +121,7 @@ test.describe("Authenticated Saved Page", () => {
114121

115122
// First, bookmark an article
116123
await page.goto("http://localhost:3000/feed?type=article");
117-
await page.waitForLoadState("networkidle");
124+
await page.waitForLoadState("domcontentloaded");
118125
await page.waitForSelector("article");
119126

120127
// Click bookmark

0 commit comments

Comments
 (0)