import { expect } from "@playwright/test"; import { test } from "./lib/fixtures"; import { bookTimeSlot, selectFirstAvailableTimeSlotNextMonth, submitAndWaitForResponse, } from "./lib/testUtils"; test.describe.configure({ mode: "serial" }); test.describe("private links creation and usage", () => { test.beforeEach(async ({ users }) => { const user = await users.create(); await user.apiLogin(); }); test.afterEach(async ({ users }) => { await users.deleteAll(); }); test("generate private link and make a booking with it", async ({ page }) => { await page.goto("/event-types"); // We wait until loading is finished await Promise.all([ page.waitForURL("**/event-types"), page.getByTestId("event-types").locator("li a").first().click(), ]); await expect(page.locator("[data-testid=event-title]")).toBeVisible(); // We wait for the page to load await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); const hashedLinkCheck = page.locator('[data-testid="multiplePrivateLinksCheck"]'); await expect(hashedLinkCheck).toBeVisible(); // ignore if it is already checked, and click if unchecked if (!(await hashedLinkCheck.isChecked())) { await hashedLinkCheck.click(); } // Wait for the private link URL input to be visible and get its value const $url = await page.locator('[data-testid="private-link-url"]').inputValue(); // click update await submitAndWaitForResponse(page, "/api/trpc/eventTypes/heavy/update?batch=1", { action: () => page.locator("[data-testid=update-eventtype]").click(), }); // book using generated url hash await page.goto($url); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page); // Make sure we're navigated to the success page const successPage = page.getByTestId("success-page"); await expect(successPage).toBeVisible(); // hash regenerates after successful booking (only for usage-based links) await page.goto("/event-types"); await page.waitForSelector('[data-testid="event-types"]'); await page.reload(); // ensure fresh state await page.locator("ul[data-testid=event-types] > li a").first().click(); // We wait for the page to load await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); // After booking with a usage-based private link, the link should be expired await expect(page.locator('[data-testid="private-link-description"]')).toContainText( "Usage limit reached" ); // Ensure that private URL is enabled after modifying the event type. // Additionally, if the slug is changed, ensure that the private URL is updated accordingly. await page.getByTestId("vertical-tab-basics").click(); await page.locator("[data-testid=event-title]").first().fill("somethingrandom"); await page.locator("[data-testid=event-slug]").first().fill("somethingrandom"); await expect(page.locator('[data-testid="event-slug"]').first()).toHaveValue("somethingrandom"); await submitAndWaitForResponse(page, "/api/trpc/eventTypes/heavy/update?batch=1", { action: () => page.locator("[data-testid=update-eventtype]").click(), }); await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); // Wait for the private link URL input to be visible and get its value const $url2 = await page.locator('[data-testid="private-link-url"]').inputValue(); expect($url2.includes("somethingrandom")).toBeTruthy(); }); test("generate private link with future expiration date and make a booking with it", async ({ page }) => { await page.goto("/event-types"); // We wait until loading is finished await Promise.all([ page.waitForURL("**/event-types"), page.getByTestId("event-types").locator("li a").first().click(), ]); await expect(page.locator("[data-testid=event-title]")).toBeVisible(); // We wait for the page to load await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); const privateLinkCheck = page.locator('[data-testid="multiplePrivateLinksCheck"]'); await expect(privateLinkCheck).toBeVisible(); // ignore if it is already checked, and click if unchecked if (!(await privateLinkCheck.isChecked())) { await privateLinkCheck.click(); } // Wait for the private link URL input to be visible and get its value const $url = await page.locator('[data-testid="private-link-url"]').inputValue(); await page.locator('[data-testid="private-link-settings"]').click(); await expect(page.locator('[data-testid="private-link-radio-group"]')).toBeVisible(); await page.locator('[data-testid="private-link-time"]').click(); await page.locator('[data-testid="private-link-expiration-settings-save"]').click(); await page.waitForLoadState("networkidle"); // click update await submitAndWaitForResponse(page, "/api/trpc/eventTypes/heavy/update?batch=1", { action: () => page.locator("[data-testid=update-eventtype]").click(), }); // book using generated url hash await page.goto($url); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page); // Make sure we're navigated to the success page await expect(page.getByTestId("success-page")).toBeVisible(); // hash regenerates after successful booking (only for usage-based links) await page.goto("/event-types"); await page.waitForSelector('[data-testid="event-types"]'); await page.reload(); // ensure fresh state await page.locator("ul[data-testid=event-types] > li a").first().click(); // We wait for the page to load await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); // After booking with a expiration date based private link, the link should still be valid await expect(page.locator('[data-testid="private-link-expired"]')).toBeHidden(); }); test("generate private link with 2 usages and make 2 bookings with it", async ({ page }) => { await page.goto("/event-types"); // We wait until loading is finished await Promise.all([ page.waitForURL("**/event-types"), page.getByTestId("event-types").locator("li a").first().click(), ]); await expect(page.locator("[data-testid=event-title]")).toBeVisible(); // We wait for the page to load await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); const privateLinkCheck = page.locator('[data-testid="multiplePrivateLinksCheck"]'); await expect(privateLinkCheck).toBeVisible(); // ignore if it is already checked, and click if unchecked if (!(await privateLinkCheck.isChecked())) { await privateLinkCheck.click(); } // Wait for the private link URL input to be visible and get its value const $url = await page.locator('[data-testid="private-link-url"]').inputValue(); await page.locator('[data-testid="private-link-settings"]').click(); await expect(page.locator('[data-testid="private-link-radio-group"]')).toBeVisible(); await page.locator('[data-testid="private-link-usage-count"]').fill("2"); await page.locator('[data-testid="private-link-expiration-settings-save"]').click(); await page.waitForLoadState("networkidle"); // click update await submitAndWaitForResponse(page, "/api/trpc/eventTypes/heavy/update?batch=1", { action: () => page.locator("[data-testid=update-eventtype]").click(), }); // book using generated url hash await page.goto($url); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page); // Make sure we're navigated to the success page await expect(page.getByTestId("success-page")).toBeVisible(); // book again using generated url hash await page.goto($url); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page); // Make sure we're navigated to the success page await expect(page.getByTestId("success-page")).toBeVisible(); await page.goto("/event-types"); await page.waitForSelector('[data-testid="event-types"]'); await page.reload(); // ensure fresh state await page.locator("ul[data-testid=event-types] > li a").first().click(); // We wait for the page to load await page.locator("[data-testid=vertical-tab-event_advanced_tab_title]").click(); // After booking twice with a 2 usages based private link, the link should be expired await expect(page.locator('[data-testid="private-link-description"]')).toContainText( "Usage limit reached" ); }); });