Files
calendar/apps/web/playwright/hash-my-url.e2e.ts
T
Eunjae LeeGitHubClaude Opus 4.5Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
81e4241f85 refactor: apply biome formatting to apps/web (#27692)
* refactor: apply biome formatting to apps/web (batch 1)

Formats apps/web non-modules directories:
- apps/web/app
- apps/web/lib
- apps/web/pages
- apps/web/styles
- apps/web/server
- apps/web/test
- Root-level .ts and .mjs files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/modules (batch 2)

Formats smaller apps/web/modules directories:
- onboarding, data-table, users, apps, auth
- integration-attribute-sync, shell, availability
- feature-flags, team, webhooks, getting-started
- feature-opt-in, troubleshooter, schedules, notifications
- signup-view.tsx

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/modules (batch 3)

Formats medium apps/web/modules directories:
- bookings
- event-types
- insights
- embed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/modules/ee (batch 4)

Formats apps/web/modules/ee directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web (batch 5)

Formats remaining apps/web directories:
- apps/web/modules/settings
- apps/web/modules/booking-audit
- apps/web/playwright

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to apps/web/components (batch 6)

Formats remaining apps/web/components files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to new apps/web files from main

Formats newly added/modified files from main merge:
- WorkflowStepContainer.tsx (resolved merge conflicts)
- Newly moved files (blocklist, form-builder, schedules, etc.)
- Other files modified in main

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: apply biome formatting to new apps/web files from main

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 23:25:24 +05:30

205 lines
8.7 KiB
TypeScript

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/eventTypesHeavy/update?batch=1", {
action: () => page.locator("[data-testid=update-eventtype]").click(),
});
// book using generated url hash
await page.goto($url);
await page.waitForURL((url) => {
return url.searchParams.get("overlayCalendar") === "true";
});
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/eventTypesHeavy/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/eventTypesHeavy/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/eventTypesHeavy/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 page.waitForURL((url) => {
return url.searchParams.get("overlayCalendar") === "true";
});
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"
);
});
});