From 7584645b8c9a3f6b0eabaec5eb1bdd67cf9a5bce Mon Sep 17 00:00:00 2001 From: Vijay Date: Mon, 30 Dec 2024 14:13:53 +0530 Subject: [PATCH] fix: flaky OOO tests without time dependency (#18412) * fix flaky OOO tests without time dependency * chore --- apps/web/playwright/lib/testUtils.ts | 19 +--- apps/web/playwright/out-of-office.e2e.ts | 126 +++++++++++++++++++---- 2 files changed, 107 insertions(+), 38 deletions(-) diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts index 43005af702..2b5b199e61 100644 --- a/apps/web/playwright/lib/testUtils.ts +++ b/apps/web/playwright/lib/testUtils.ts @@ -1,4 +1,4 @@ -import type { Frame, Locator, Page, Request as PlaywrightRequest } from "@playwright/test"; +import type { Frame, Page, Request as PlaywrightRequest } from "@playwright/test"; import { expect } from "@playwright/test"; import { createHash } from "crypto"; import EventEmitter from "events"; @@ -538,20 +538,3 @@ export async function expectPageToBeNotFound({ page, url }: { page: Page; url: s await page.goto(`${url}`); await expect(page.getByTestId(`404-page`)).toBeVisible(); } - -export async function clickUntilDialogVisible( - dialogOpenButton: Locator, - visibleLocatorOnDialog: Locator, - retries = 3, - delay = 500 -) { - for (let i = 0; i < retries; i++) { - await dialogOpenButton.click(); - try { - await visibleLocatorOnDialog.waitFor({ state: "visible", timeout: delay }); - return; - } catch { - if (i === retries - 1) throw new Error("Dialog did not appear after multiple attempts."); - } - } -} diff --git a/apps/web/playwright/out-of-office.e2e.ts b/apps/web/playwright/out-of-office.e2e.ts index 8f93ae7577..9152db47db 100644 --- a/apps/web/playwright/out-of-office.e2e.ts +++ b/apps/web/playwright/out-of-office.e2e.ts @@ -7,7 +7,7 @@ import { randomString } from "@calcom/lib/random"; import prisma from "@calcom/prisma"; import { test } from "./lib/fixtures"; -import { submitAndWaitForResponse, localize, clickUntilDialogVisible } from "./lib/testUtils"; +import { submitAndWaitForResponse, localize } from "./lib/testUtils"; test.describe.configure({ mode: "parallel" }); test.afterEach(async ({ users }) => { @@ -20,9 +20,19 @@ test.describe("Out of office", () => { await user.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; + await page.getByTestId("reason_select").click(); await page.getByTestId("select-option-4").click(); @@ -67,9 +77,19 @@ test.describe("Out of office", () => { await user.apiLogin(); - await page.goto(`/settings/my-account/out-of-office`); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); + await page.goto("/settings/my-account/out-of-office"); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; + await page.getByTestId("reason_select").click(); await page.getByTestId("select-option-4").click(); @@ -144,7 +164,12 @@ test.describe("Out of office", () => { await user.apiLogin(); - await page.goto(`/settings/my-account/out-of-office`); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); + await page.goto("/settings/my-account/out-of-office"); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; // expect table-redirect-toUserId to be visible await expect(page.locator(`data-testid=table-redirect-${userTo.username}`)).toBeVisible(); @@ -203,9 +228,18 @@ test.describe("Out of office", () => { await user.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; await page.locator('[data-testid="date-range"]').click(); @@ -243,9 +277,18 @@ test.describe("Out of office", () => { await user.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; await page.locator('[data-testid="date-range"]').click(); @@ -256,7 +299,9 @@ test.describe("Out of office", () => { await expect(page.locator(`data-testid=table-redirect-n-a`)).toBeVisible(); // add another entry + await entriesListRespPromise; await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; await page.locator('[data-testid="date-range"]').click(); @@ -273,9 +318,18 @@ test.describe("Out of office", () => { await user.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; await page.locator('[data-testid="date-range"]').click(); @@ -286,7 +340,9 @@ test.describe("Out of office", () => { await expect(page.locator(`data-testid=table-redirect-n-a`)).toBeVisible(); // add another entry + await entriesListRespPromise; await page.getByTestId("add_entry_ooo").click(); + await reasonListRespPromise; await page.locator('[data-testid="date-range"]').click(); @@ -300,21 +356,31 @@ test.describe("Out of office", () => { const user = await users.create({ name: "userOne" }); await user.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); - await page.waitForLoadState(); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; - const addOOOButton = await page.getByTestId("add_entry_ooo"); - const dateButton = await page.locator('[data-testid="date-range"]'); + const addOOOButton = page.getByTestId("add_entry_ooo"); + const dateButton = page.locator('[data-testid="date-range"]'); + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); + await addOOOButton.click(); + await reasonListRespPromise; //Creates 2 OOO entries: //First OOO is created on Next month 1st - 3rd - await clickUntilDialogVisible(addOOOButton, dateButton); await dateButton.click(); await selectDateAndCreateOOO(page, "1", "3"); await expect(page.locator(`data-testid=table-redirect-n-a`).nth(0)).toBeVisible(); //Second OOO is created on Next month 4th - 6th - await clickUntilDialogVisible(addOOOButton, dateButton); + await entriesListRespPromise; + await addOOOButton.click(); + await reasonListRespPromise; await dateButton.click(); await selectDateAndCreateOOO(page, "4", "6"); await expect(page.locator(`data-testid=table-redirect-n-a`).nth(1)).toBeVisible(); @@ -334,14 +400,22 @@ test.describe("Out of office", () => { await owner.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); - await page.waitForLoadState(); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; - const addOOOButton = await page.getByTestId("add_entry_ooo"); - const dateButton = await page.locator('[data-testid="date-range"]'); + const addOOOButton = page.getByTestId("add_entry_ooo"); + const dateButton = page.locator('[data-testid="date-range"]'); + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); + await addOOOButton.click(); + await reasonListRespPromise; //As owner,OOO is created on Next month 1st - 3rd, forwarding to 'member-1' - await clickUntilDialogVisible(addOOOButton, dateButton); await dateButton.click(); await selectDateAndCreateOOO(page, "1", "3", "member-1"); await expect( @@ -351,8 +425,10 @@ test.describe("Out of office", () => { //As member1, OOO is created on Next month 4th - 5th, forwarding to 'owner' await member1User?.apiLogin(); await page.goto("/settings/my-account/out-of-office"); - await page.waitForLoadState(); - await clickUntilDialogVisible(addOOOButton, dateButton); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + await addOOOButton.click(); + await reasonListRespPromise; await dateButton.click(); await selectDateAndCreateOOO(page, "4", "5", "owner"); await expect(page.locator(`data-testid=table-redirect-${owner.username ?? "n-a"}`).nth(0)).toBeVisible(); @@ -373,14 +449,22 @@ test.describe("Out of office", () => { await owner.apiLogin(); + const entriesListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeEntriesList") && response.status() === 200 + ); await page.goto("/settings/my-account/out-of-office"); - await page.waitForLoadState(); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; - const addOOOButton = await page.getByTestId("add_entry_ooo"); - const dateButton = await page.locator('[data-testid="date-range"]'); + const addOOOButton = page.getByTestId("add_entry_ooo"); + const dateButton = page.locator('[data-testid="date-range"]'); + const reasonListRespPromise = page.waitForResponse( + (response) => response.url().includes("outOfOfficeReasonList?batch=1") && response.status() === 200 + ); + await addOOOButton.click(); + await reasonListRespPromise; //As owner,OOO is created on Next month 1st - 3rd, forwarding to 'member-1' - await clickUntilDialogVisible(addOOOButton, dateButton); await dateButton.click(); await selectDateAndCreateOOO(page, "1", "3", "member-1"); await expect( @@ -390,8 +474,10 @@ test.describe("Out of office", () => { //As member1, expect error while OOO is created on Next month 2nd - 5th, forwarding to 'owner' await member1User?.apiLogin(); await page.goto("/settings/my-account/out-of-office"); - await page.waitForLoadState(); - await clickUntilDialogVisible(addOOOButton, dateButton); + await page.waitForLoadState("domcontentloaded"); + await entriesListRespPromise; + await addOOOButton.click(); + await reasonListRespPromise; await dateButton.click(); await selectDateAndCreateOOO(page, "2", "5", "owner", 400); await expect(page.locator(`text=${t("booking_redirect_infinite_not_allowed")}`)).toBeTruthy();