chore: fix flaky playright E2E tests

- Increased global timeout to 120,000 in playwright.config.ts
- Increased waitForFeedItems timeout to 60,000 in various E2E tests
- Increased toHaveClass and other specific assertion timeouts to 60,000 in E2E tests

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-03-02 19:07:21 +00:00
1 parent 55b30b4da1
commit b16214277b
6 files changed
+48 -48

No files matched your search

+1 -1
View File
@@ -49,7 +49,7 @@ export default defineConfig({
testDir: "./tests",
globalSetup: "./tests/e2e/helpers/playwrightCoverageGlobalSetup.ts",
outputDir: "artifacts/test-results",
timeout: 60_000,
timeout: 120_000,
retries: process.env.CI ? 1 : 0,
reporter: process.env.CI
? [["github"], ["html", { open: "never" }]]
+5 -5
View File
@@ -22,7 +22,7 @@ test.describe("Feed pagination and stress scenarios", () => {
seedEvent,
startDiagnostics,
}) => {
test.setTimeout(60000);
test.setTimeout(90000);
// Given: 10 videos seeded into the relay
for (let i = 0; i < 10; i++) {
@@ -40,7 +40,7 @@ test.describe("Feed pagination and stress scenarios", () => {
// Wait for feed to populate
const items = await page.evaluate(() => {
return (window as any).__bitvidTest__.waitForFeedItems(10, 30000);
return (window as any).__bitvidTest__.waitForFeedItems(10, 60000);
});
// Then: all 10 videos are present
@@ -86,7 +86,7 @@ test.describe("Feed pagination and stress scenarios", () => {
await loginAs(page);
const items = await page.evaluate(() => {
return (window as any).__bitvidTest__.waitForFeedItems(5, 20000);
return (window as any).__bitvidTest__.waitForFeedItems(5, 60000);
});
// Then: all d-tags are present and unique
@@ -221,7 +221,7 @@ test.describe("Feed pagination and stress scenarios", () => {
// And feed loads with the video
const items = await page.evaluate(() => {
return (window as any).__bitvidTest__.waitForFeedItems(1, 15000);
return (window as any).__bitvidTest__.waitForFeedItems(1, 60000);
});
expect(items.length).toBeGreaterThanOrEqual(1);
@@ -287,7 +287,7 @@ test.describe("Feed pagination and stress scenarios", () => {
await loginAs(page);
await page.evaluate(() => {
return (window as any).__bitvidTest__.waitForFeedItems(1, 15000);
return (window as any).__bitvidTest__.waitForFeedItems(1, 60000);
});
// Then: the DOM card has all expected data attributes
+8 -8
View File
@@ -69,7 +69,7 @@ test.describe("Login and authentication flows", () => {
() => {
return (window as any).__bitvidTest__.getAppState().isLoggedIn === false;
},
{ timeout: 15000 },
{ timeout: 60000 },
);
// Then: state is fully cleared
@@ -109,7 +109,7 @@ test.describe("Login and authentication flows", () => {
// Wait for state to settle with a longer timeout
await page.waitForFunction(() => {
return (window as any).__bitvidTest__.getAppState().isLoggedIn === false;
}, { timeout: 15000 });
}, { timeout: 60000 });
const loggedOut = await page.evaluate(() => {
return (window as any).__bitvidTest__.getAppState();
@@ -164,7 +164,7 @@ test.describe("Login and authentication flows", () => {
// Then: gated buttons are no longer visible
// Allow DOM update to propagate
await page.waitForTimeout(2000);
await expect(uploadBtn).not.toBeVisible({ timeout: 10000 });
await expect(uploadBtn).not.toBeVisible({ timeout: 60000 });
});
test("login button is visible in logged-out state", async ({
@@ -193,7 +193,7 @@ test.describe("Login and authentication flows", () => {
// Then: login modal becomes visible
const modal = page.locator('[data-testid="login-modal"]');
await expect(modal).toBeVisible({ timeout: 15000 });
await expect(modal).toBeVisible({ timeout: 60000 });
await expect(modal).toHaveAttribute("data-open", "true");
});
@@ -215,15 +215,15 @@ test.describe("Login and authentication flows", () => {
}
return loginModal.getAttribute("data-open") === "true";
},
{ timeout: 15000 },
{ timeout: 60000 },
);
await expect(modal).toBeVisible({ timeout: 15000 });
await expect(modal).toBeVisible({ timeout: 60000 });
// Then: at least one provider button is visible
const providers = page.locator(
'[data-testid="login-provider-button"]',
);
await expect(providers.first()).toBeVisible({ timeout: 15000 });
await expect(providers.first()).toBeVisible({ timeout: 60000 });
const providerCount = await providers.count();
expect(providerCount).toBeGreaterThanOrEqual(1);
@@ -245,7 +245,7 @@ test.describe("Login and authentication flows", () => {
if (!(modal instanceof HTMLElement)) return false;
return modal.getAttribute("data-open") === "true";
},
{ timeout: 15000 },
{ timeout: 60000 },
);
// Click the nsec provider to reveal inputs
+18 -18
View File
@@ -32,7 +32,7 @@ async function setupFeedWithVideo(
await loginAs(page);
await page.evaluate(() => {
return (window as any).__bitvidTest__.waitForFeedItems(1, 15000);
return (window as any).__bitvidTest__.waitForFeedItems(1, 60000);
});
}
@@ -81,7 +81,7 @@ test.describe("Video CRUD — settings menu", () => {
// Then: a settings menu panel should appear
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
// And: it should contain edit and delete actions
const editAction = settingsPanel.locator('[data-action="edit"]');
@@ -107,14 +107,14 @@ test.describe("Video CRUD — edit modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
// When: user clicks the edit action
await settingsPanel.locator('[data-action="edit"]').click();
// Then: the edit modal should open
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
});
test("edit modal contains the title input field", async ({
@@ -133,11 +133,11 @@ test.describe("Video CRUD — edit modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
await settingsPanel.locator('[data-action="edit"]').click();
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the title input should be present
const titleInput = page.locator("#editVideoTitle");
@@ -159,18 +159,18 @@ test.describe("Video CRUD — edit modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
await settingsPanel.locator('[data-action="edit"]').click();
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// When: user clicks the close button
const closeBtn = page.locator("#closeEditVideoModal");
await closeBtn.click();
// Then: the edit modal should be hidden
await expect(editModal).toHaveClass(/hidden/, { timeout: 5000 });
await expect(editModal).toHaveClass(/hidden/, { timeout: 60000 });
});
});
@@ -190,14 +190,14 @@ test.describe("Video CRUD — delete modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
// When: user clicks the delete action
await settingsPanel.locator('[data-action="delete"]').click();
// Then: the delete confirmation modal should open
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
});
test("delete modal has confirm and cancel buttons", async ({
@@ -215,11 +215,11 @@ test.describe("Video CRUD — delete modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: confirm and cancel buttons should be present
const confirmBtn = page.locator("#confirmDeleteVideo");
@@ -247,17 +247,17 @@ test.describe("Video CRUD — delete modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// When: user clicks cancel
await page.locator("#cancelDeleteVideo").click();
// Then: the delete modal should close
await expect(deleteModal).toHaveClass(/hidden/, { timeout: 5000 });
await expect(deleteModal).toHaveClass(/hidden/, { timeout: 60000 });
// And: the video should still be in the feed
const feedItems = await page.evaluate(() => {
@@ -281,11 +281,11 @@ test.describe("Video CRUD — delete modal", () => {
await card.locator('[aria-label="Video settings"]').click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the modal should contain a warning about irreversibility
const modalText = await deleteModal.textContent();
+12 -12
View File
@@ -35,7 +35,7 @@ async function setupAndOpenSettings(
await loginAs(page);
await page.evaluate(() =>
(window as any).__bitvidTest__.waitForFeedItems(1, 30000),
(window as any).__bitvidTest__.waitForFeedItems(1, 60000),
);
const card = page.locator("[data-video-card]").first();
@@ -45,7 +45,7 @@ async function setupAndOpenSettings(
await gearBtn.click();
const settingsPanel = page.locator('[data-menu="video-settings"]');
await expect(settingsPanel).toBeVisible({ timeout: 5000 });
await expect(settingsPanel).toBeVisible({ timeout: 60000 });
return { card, settingsPanel, dTag };
}
@@ -67,7 +67,7 @@ test.describe("Video edit — form behavior", () => {
await settingsPanel.locator('[data-action="edit"]').click();
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the title field should contain the video's title
const titleInput = page.locator("#editVideoTitle");
@@ -90,7 +90,7 @@ test.describe("Video edit — form behavior", () => {
await settingsPanel.locator('[data-action="edit"]').click();
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the title field should be readonly (locked)
const titleInput = page.locator("#editVideoTitle");
@@ -126,7 +126,7 @@ test.describe("Video edit — form behavior", () => {
await settingsPanel.locator('[data-action="edit"]').click();
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Unlock the title field
const editFieldBtn = editModal.locator(
@@ -165,7 +165,7 @@ test.describe("Video edit — form behavior", () => {
await settingsPanel.locator('[data-action="edit"]').click();
const editModal = page.locator("#editVideoModal");
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(editModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Set up event listener before submitting
const submitEventPromise = page.evaluate(() => {
@@ -202,7 +202,7 @@ test.describe("Video edit — form behavior", () => {
// Note: The actual relay publish may or may not succeed depending on
// the test environment, but the form submission path should work.
// We wait briefly for the modal to close
await expect(editModal).toHaveClass(/hidden/, { timeout: 15000 });
await expect(editModal).toHaveClass(/hidden/, { timeout: 60000 });
});
});
@@ -223,7 +223,7 @@ test.describe("Video delete — execution", () => {
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the modal should contain the warning text
const modalText = await deleteModal.textContent();
@@ -255,13 +255,13 @@ test.describe("Video delete — execution", () => {
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// When: the user clicks "Delete all versions"
await page.locator("#confirmDeleteVideo").click();
// Then: the delete modal should close
await expect(deleteModal).toHaveClass(/hidden/, { timeout: 15000 });
await expect(deleteModal).toHaveClass(/hidden/, { timeout: 60000 });
});
test("confirm delete button has critical variant", async ({
@@ -280,7 +280,7 @@ test.describe("Video delete — execution", () => {
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the confirm button should have data-variant="critical"
const confirmBtn = page.locator("#confirmDeleteVideo");
@@ -307,7 +307,7 @@ test.describe("Video delete — execution", () => {
await settingsPanel.locator('[data-action="delete"]').click();
const deleteModal = page.locator("#deleteVideoModal");
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(deleteModal).not.toHaveClass(/hidden/, { timeout: 60000 });
// Then: the modal should have proper ARIA attributes
await expect(deleteModal).toHaveAttribute("role", "dialog");
+4 -4
View File
@@ -32,15 +32,15 @@ async function openVideoModal(
await loginAs(page);
await page.evaluate(() => {
return (window as any).__bitvidTest__.waitForFeedItems(1, 30000);
return (window as any).__bitvidTest__.waitForFeedItems(1, 60000);
});
await page.locator("#playerModal").waitFor({ state: "attached", timeout: 15000 });
await page.locator("#playerModal").waitFor({ state: "attached", timeout: 60000 });
await page.locator("[data-video-card]").first().click();
const playerModal = page.locator("#playerModal");
await expect(playerModal).not.toHaveClass(/hidden/, { timeout: 10000 });
await expect(playerModal).not.toHaveClass(/hidden/, { timeout: 60000 });
}
test.describe("Video engagement — reactions", () => {
@@ -208,7 +208,7 @@ test.describe("Video engagement — comments", () => {
// Then: submit button should become enabled
// The app uses an input event handler to toggle the disabled attribute
await expect(submit).toBeEnabled({ timeout: 3000 });
await expect(submit).toBeEnabled({ timeout: 60000 });
});
test("comment list container is present in the video modal", async ({