Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8685862617 | ||
|
|
7422488b5d | ||
|
|
c3e1481d6a | ||
|
|
a1d1883b34 | ||
|
|
f2ae94a190 | ||
|
|
b82a597645 | ||
|
|
5ba0ee8e85 | ||
|
|
1463f97f14 | ||
|
|
34fea35e83 | ||
|
|
2d75048037 | ||
|
|
b549735334 | ||
|
|
86c379817e | ||
|
|
5d1976295c | ||
|
|
e9b1fa1f50 | ||
|
|
80080dda7a | ||
|
|
27c25e1f95 | ||
|
|
858be0f5d8 | ||
|
|
68d0090f50 | ||
|
|
a43fa13b11 | ||
|
|
2bf6da30b3 | ||
|
|
d85e0b51e4 | ||
|
|
55a317d677 | ||
|
|
5fff8fc58c | ||
|
|
0d68767d0a | ||
|
|
2051e87436 | ||
|
|
77a157a12b | ||
|
|
c4f25f2c44 | ||
|
|
d967facb63 | ||
|
|
c6dad39fb0 | ||
|
|
eec7f4d7d4 | ||
|
|
95d5824ba9 | ||
|
|
5f95a4d041 |
@@ -360,10 +360,12 @@ export const EventLimitsTab = () => {
|
||||
title={t("limit_future_bookings")}
|
||||
description={t("limit_future_bookings_description")}
|
||||
checked={isChecked}
|
||||
onCheckedChange={(bool) =>
|
||||
// formMethods.setValue("periodType", bool ? "ROLLING" : "UNLIMITED", { shouldDirty: true })
|
||||
onChange(bool ? "ROLLING" : "UNLIMITED")
|
||||
}>
|
||||
onCheckedChange={(bool) => {
|
||||
if (bool && !formMethods.getValues("periodDays")) {
|
||||
formMethods.setValue("periodDays", 30, { shouldDirty: true });
|
||||
}
|
||||
return onChange(bool ? "ROLLING" : "UNLIMITED");
|
||||
}}>
|
||||
<div className="border-subtle rounded-b-lg border border-t-0 p-6">
|
||||
<RadioGroup.Root
|
||||
value={watchPeriodType}
|
||||
|
||||
@@ -318,7 +318,7 @@ export const EventSetupTab = (
|
||||
/>
|
||||
</div>
|
||||
<ErrorMessage
|
||||
errors={formMethods.formState.errors.locations?.[index]}
|
||||
errors={formMethods.formState.errors?.locations?.[index]}
|
||||
name={eventLocationType.defaultValueVariable}
|
||||
className="text-error my-1 ml-6 text-sm"
|
||||
as="div"
|
||||
|
||||
@@ -160,7 +160,7 @@ const UsernameTextfield = (props: ICustomUsernameProps & Partial<React.Component
|
||||
<div className="bg-subtle flex w-full flex-wrap gap-6 rounded-sm px-2 py-3 text-sm">
|
||||
<div>
|
||||
<p className="text-subtle">{t("current_username")}</p>
|
||||
<p className="text-emphasis mt-1" data-testid="current-username">
|
||||
<p className="text-emphasis mt-1 break-all" data-testid="current-username">
|
||||
{currentUsername}
|
||||
</p>
|
||||
</div>
|
||||
@@ -168,7 +168,7 @@ const UsernameTextfield = (props: ICustomUsernameProps & Partial<React.Component
|
||||
<p className="text-subtle" data-testid="new-username">
|
||||
{t("new_username")}
|
||||
</p>
|
||||
<p className="text-emphasis mt-1">{inputUsernameValue}</p>
|
||||
<p className="text-emphasis mt-1 break-all">{inputUsernameValue}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -266,7 +266,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
beforeEventBuffer: eventType.beforeEventBuffer,
|
||||
eventName: eventType.eventName || "",
|
||||
scheduleName: eventType.scheduleName,
|
||||
periodDays: eventType.periodDays || 30,
|
||||
periodDays: eventType.periodDays,
|
||||
requiresBookerEmailVerification: eventType.requiresBookerEmailVerification,
|
||||
seatsPerTimeSlot: eventType.seatsPerTimeSlot,
|
||||
seatsShowAttendees: eventType.seatsShowAttendees,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@calcom/web",
|
||||
"version": "3.8.3",
|
||||
"version": "3.8.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
|
||||
@@ -95,6 +95,7 @@ const IntegrationsContainer = ({
|
||||
className="mb-6"
|
||||
actions={
|
||||
<Button
|
||||
data-testid="add-apps"
|
||||
href={variant ? `/apps/categories/${variant}` : "/apps"}
|
||||
color="secondary"
|
||||
StartIcon={Plus}>
|
||||
|
||||
@@ -374,7 +374,7 @@ const ProfileView = () => {
|
||||
</div>
|
||||
<DialogFooter showDivider>
|
||||
<Button
|
||||
data-testId="profile-update-email-submit-button"
|
||||
data-testid="profile-update-email-submit-button"
|
||||
color="primary"
|
||||
loading={confirmPasswordMutation.isPending}
|
||||
onClick={(e) => onConfirmPassword(e)}>
|
||||
@@ -511,7 +511,7 @@ const ProfileForm = ({
|
||||
<TextField
|
||||
label={t("email")}
|
||||
hint={t("change_email_hint")}
|
||||
data-testId="profile-form-email"
|
||||
data-testid="profile-form-email"
|
||||
{...formMethods.register("email")}
|
||||
/>
|
||||
</div>
|
||||
@@ -535,7 +535,7 @@ const ProfileForm = ({
|
||||
disabled={isDisabled}
|
||||
color="primary"
|
||||
type="submit"
|
||||
data-testId="profile-submit-button">
|
||||
data-testid="profile-submit-button">
|
||||
{t("update")}
|
||||
</Button>
|
||||
</SectionBottomActions>
|
||||
|
||||
@@ -123,7 +123,7 @@ function TeamPage({
|
||||
(mem) => mem.subteams?.includes(ch.slug) && mem.accepted
|
||||
).length;
|
||||
return (
|
||||
<li key={i} className="hover:bg-muted w-full">
|
||||
<li key={i} className="hover:bg-muted w-full rounded-md">
|
||||
<Link href={`/${ch.slug}`} className="flex items-center justify-between">
|
||||
<div className="flex items-center px-5 py-5">
|
||||
<div className="ms-3 inline-block truncate">
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { loginUser } from "../../fixtures/regularBookings";
|
||||
import { test } from "../../lib/fixtures";
|
||||
|
||||
const ALL_APPS = ["fathom", "matomo", "plausible", "ga4", "gtm", "metapixel"];
|
||||
|
||||
test.describe("Check analytics Apps", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/apps/");
|
||||
});
|
||||
|
||||
test("Check analytics Apps", async ({ appsPage, page }) => {
|
||||
await appsPage.goToAppsCategory("analytics");
|
||||
await appsPage.installApp("fathom");
|
||||
await appsPage.goBackToAppsPage();
|
||||
await appsPage.installApp("matomo");
|
||||
await appsPage.goBackToAppsPage();
|
||||
await appsPage.installApp("plausible");
|
||||
await appsPage.goBackToAppsPage();
|
||||
await appsPage.installApp("ga4");
|
||||
await appsPage.goBackToAppsPage();
|
||||
await appsPage.installApp("gtm");
|
||||
await appsPage.goBackToAppsPage();
|
||||
await appsPage.installApp("metapixel");
|
||||
await appsPage.goBackToAppsPage();
|
||||
await page.goto("/event-types");
|
||||
await appsPage.goToEventType("30 min");
|
||||
await appsPage.goToAppsTab();
|
||||
await appsPage.verifyAppsInfo(0);
|
||||
for (const app of ALL_APPS) {
|
||||
await appsPage.activeApp(app);
|
||||
}
|
||||
await appsPage.verifyAppsInfo(6);
|
||||
});
|
||||
});
|
||||
@@ -175,6 +175,35 @@ testBothFutureAndLegacyRoutes.describe("pro user", () => {
|
||||
await expect(page.locator('[data-testid="empty-screen"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test("can book an unconfirmed event multiple times", async ({ page, users }) => {
|
||||
await page.locator('[data-testid="event-type-link"]:has-text("Opt in")').click();
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
const pageUrl = page.url();
|
||||
|
||||
await bookTimeSlot(page);
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
|
||||
// go back to the booking page to re-book.
|
||||
await page.goto(pageUrl);
|
||||
await bookTimeSlot(page, { email: "test2@example.com" });
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
});
|
||||
|
||||
test("cannot book an unconfirmed event multiple times with the same email", async ({ page, users }) => {
|
||||
await page.locator('[data-testid="event-type-link"]:has-text("Opt in")').click();
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
const pageUrl = page.url();
|
||||
|
||||
await bookTimeSlot(page);
|
||||
// go back to the booking page to re-book.
|
||||
await page.goto(pageUrl);
|
||||
|
||||
await bookTimeSlot(page);
|
||||
await expect(page.getByText("Could not book the meeting.")).toBeVisible();
|
||||
});
|
||||
|
||||
test("can book with multiple guests", async ({ page, users }) => {
|
||||
const additionalGuests = ["test@gmail.com", "test2@gmail.com"];
|
||||
|
||||
|
||||
@@ -1,483 +0,0 @@
|
||||
import { loginUser } from "../../fixtures/regularBookings";
|
||||
import { test } from "../../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Address Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Checkbox Group Question", () => {
|
||||
test("Address required and checkbox group required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Checkbox Group question (both required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and checkbox group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Checkbox Group question (only address required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Checkbox Question", () => {
|
||||
test("Address required and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Checkbox question (both required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Addres and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Checkbox question (only address required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Long text Question", () => {
|
||||
test("Addres required and Long Text required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Long Text question (both required)",
|
||||
secondQuestion: "textarea",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and Long Text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", false, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Long Text question (only address required)",
|
||||
secondQuestion: "textarea",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Multi email Question", () => {
|
||||
test("Address required and Multi email required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multiemail question (both required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and Multi email not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
false,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multiemail question (only address required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and multiselect Question", () => {
|
||||
test("Address required and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multi Select question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isMultiSelect: true },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multi Select question (only address required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isMultiSelect: true, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Number Question", () => {
|
||||
test("Address required and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", true, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Number question (both required)",
|
||||
secondQuestion: "number",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", false, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Number question (only address required)",
|
||||
secondQuestion: "number",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Phone Question", () => {
|
||||
test("Address required and Phone required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone-test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multi Select question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and Phone not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", false, "phone-test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multi Select question (only address required)",
|
||||
secondQuestion: "phone",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Radio group Question", () => {
|
||||
test("Address required and Radio group required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Radio question (both required)",
|
||||
secondQuestion: "radio",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and Radio group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Radio question (only address required)",
|
||||
secondQuestion: "radio",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and select Question", () => {
|
||||
test("Address required and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and select not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", false, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Address Question and Short text question", () => {
|
||||
test("Address required and Short text required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multi Select question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Address and Short text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "address",
|
||||
fillText: "Test Address question and Multi Select question (only address required)",
|
||||
secondQuestion: "text",
|
||||
options: { ...bookingOptions, isRequired: true },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,110 +0,0 @@
|
||||
/* eslint-disable playwright/no-conditional-in-test */
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With All Questions", () => {
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
const bookingOptions = { isAllRequired: true };
|
||||
|
||||
test("Selecting and filling all questions as required", async ({ bookingPage }) => {
|
||||
const allQuestions = [
|
||||
"phone",
|
||||
"address",
|
||||
"checkbox",
|
||||
"boolean",
|
||||
"textarea",
|
||||
"multiemail",
|
||||
"multiselect",
|
||||
"number",
|
||||
"radio",
|
||||
"select",
|
||||
"text",
|
||||
];
|
||||
for (const question of allQuestions) {
|
||||
if (
|
||||
question !== "number" &&
|
||||
question !== "select" &&
|
||||
question !== "checkbox" &&
|
||||
question !== "boolean" &&
|
||||
question !== "multiselect" &&
|
||||
question !== "radio"
|
||||
) {
|
||||
await bookingPage.addQuestion(
|
||||
question,
|
||||
`${question}-test`,
|
||||
`${question} test`,
|
||||
true,
|
||||
`${question} test`
|
||||
);
|
||||
} else {
|
||||
await bookingPage.addQuestion(question, `${question}-test`, `${question} test`, true);
|
||||
}
|
||||
await bookingPage.checkField(question);
|
||||
}
|
||||
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAllQuestions(eventTypePage, allQuestions, bookingOptions);
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Selecting and filling all questions as optional", async ({ bookingPage }) => {
|
||||
const allQuestions = [
|
||||
"phone",
|
||||
"address",
|
||||
"checkbox",
|
||||
"boolean",
|
||||
"textarea",
|
||||
"multiemail",
|
||||
"multiselect",
|
||||
"number",
|
||||
"radio",
|
||||
"select",
|
||||
"text",
|
||||
];
|
||||
for (const question of allQuestions) {
|
||||
if (
|
||||
question !== "number" &&
|
||||
question !== "select" &&
|
||||
question !== "checkbox" &&
|
||||
question !== "boolean" &&
|
||||
question !== "multiselect" &&
|
||||
question !== "radio"
|
||||
) {
|
||||
await bookingPage.addQuestion(
|
||||
question,
|
||||
`${question}-test`,
|
||||
`${question} test`,
|
||||
false,
|
||||
`${question} test`
|
||||
);
|
||||
} else {
|
||||
await bookingPage.addQuestion(question, `${question}-test`, `${question} test`, false);
|
||||
}
|
||||
await bookingPage.checkField(question, { isOptional: true });
|
||||
}
|
||||
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAllQuestions(eventTypePage, allQuestions, {
|
||||
...bookingOptions,
|
||||
isAllRequired: false,
|
||||
});
|
||||
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
@@ -1,445 +0,0 @@
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Address Question", () => {
|
||||
test("Checkbox Group required and Address required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Address question (both required)",
|
||||
secondQuestion: "address",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Address not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", false, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Address question (only checkbox required)",
|
||||
secondQuestion: "address",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Phone Question", () => {
|
||||
test("Checkbox Group required and Phone required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and phone question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Phone not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", false, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Phone question (only checkbox required)",
|
||||
secondQuestion: "phone",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and checkbox Question", () => {
|
||||
test("Checkbox Group required and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and checkbox question (both required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and checkbox (only checkbox required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Long text Question", () => {
|
||||
test("Checkbox Group required and Long text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Long Text question (both required)",
|
||||
secondQuestion: "textarea",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Long text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", false, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Long Text question (only checkbox required)",
|
||||
secondQuestion: "textarea",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Multi email Question", () => {
|
||||
test("Checkbox Group required and Multi email required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Multi Email question (both required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Multi email not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
false,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Multi Email question (only checkbox required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and multiselect Question", () => {
|
||||
test("Checkbox Group required and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Multi Select question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Multi Select question (only checkbox required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Number Question", () => {
|
||||
test("Checkbox Group required and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", true, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Number question (both required)",
|
||||
secondQuestion: "number",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", false, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Number question (only checkbox required)",
|
||||
secondQuestion: "number",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Radio group Question", () => {
|
||||
test("Checkbox Group required and Radio group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Radio question (both required)",
|
||||
secondQuestion: "radio",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Radio group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Radio question (only checkbox required)",
|
||||
secondQuestion: "radio",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and select Question", () => {
|
||||
test("Checkbox Group required and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and select not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", false, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Select question (only checkbox required)",
|
||||
secondQuestion: "select",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Checkbox Group Question and Short text question", () => {
|
||||
test("Checkbox Group required and Short Text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Text question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Checkbox Group and Short Text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "checkbox",
|
||||
fillText: "Test Checkbox Group question and Text question (only checkbox required)",
|
||||
secondQuestion: "text",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,54 +0,0 @@
|
||||
import { test } from "../../lib/fixtures";
|
||||
|
||||
test.describe("Collective event type", () => {
|
||||
const teamEventTitle = "Test Managed Event Type";
|
||||
let userId: number;
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
const userFixture = await users.create(
|
||||
{ name: "testuser" },
|
||||
{ hasTeam: true, schedulingType: "COLLECTIVE", teamEventTitle }
|
||||
);
|
||||
await userFixture.apiLogin();
|
||||
userId = userFixture.id;
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType(teamEventTitle);
|
||||
});
|
||||
test("Book a Collective event type", async ({ bookingPage }) => {
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillEmailAndName(eventTypePage);
|
||||
await bookingPage.confirmBooking(eventTypePage);
|
||||
await bookingPage.backToBookings(eventTypePage);
|
||||
await bookingPage.assertLabelWithCorrectTeamName(eventTypePage, teamEventTitle);
|
||||
await bookingPage.assertBookingWithCorrectTitleAndDescription(eventTypePage, {
|
||||
profileName: "testuser",
|
||||
bookingName: teamEventTitle,
|
||||
teamName: `user-id-${userId}'s Team`,
|
||||
});
|
||||
await bookingPage.clickOnBooking(eventTypePage, teamEventTitle);
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBookingWithReason(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
test("Book a Collective event type (with added guest)", async ({ bookingPage }) => {
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillEmailAndName(eventTypePage);
|
||||
await bookingPage.addGuests(eventTypePage, { guests: ["test@example.com"] });
|
||||
await bookingPage.confirmBooking(eventTypePage);
|
||||
await bookingPage.backToBookings(eventTypePage);
|
||||
await bookingPage.assertLabelWithCorrectTeamName(eventTypePage, teamEventTitle);
|
||||
await bookingPage.assertBookingWithCorrectTitleAndDescription(eventTypePage, {
|
||||
profileName: "testuser",
|
||||
bookingName: teamEventTitle,
|
||||
teamName: `user-id-${userId}'s Team`,
|
||||
aditionalGuestEmail: "test@example.com",
|
||||
});
|
||||
await bookingPage.clickOnBooking(eventTypePage, teamEventTitle);
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBookingWithReason(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
@@ -1,483 +0,0 @@
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Long Text Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
});
|
||||
|
||||
test("Long Text and Address required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Address question (both required)",
|
||||
secondQuestion: "address",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and Address not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", false, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Address question (only Long Text required)",
|
||||
secondQuestion: "address",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and Checkbox Group Question", () => {
|
||||
test("Long Text and Checkbox Group required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Checkbox Group question (both required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and Checkbox Group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Checkbox Group question (only Long Text required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and checkbox Question", () => {
|
||||
test("Long Text and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Checkbox question (only Long Text required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Checkbox question (only Long Text required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and Multiple email Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
test("Long Text and Multiple email required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Multiple email question (both required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and Multiple email not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
false,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Multiple email question (only Long Text required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: { hasPlaceholder: true, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and multiselect Question", () => {
|
||||
test("Long Text and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and multiselect question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and multiselect question (only long text required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { hasPlaceholder: false, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and Number Question", () => {
|
||||
test("Long Text and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Number question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test("Long Text required and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Number question (only Long Textß required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { hasPlaceholder: false, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and Phone Question", () => {
|
||||
test("Long Text and Phone required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Phone question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and Phone not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", false, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Phone question (only Long Text required)",
|
||||
secondQuestion: "phone",
|
||||
options: { hasPlaceholder: false, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and Radio group Question", () => {
|
||||
test("Long Text and Radio group required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Radio Group question (both required)",
|
||||
secondQuestion: "radio",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and Radio group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Radio Group question (only Long Text required)",
|
||||
secondQuestion: "radio",
|
||||
options: { hasPlaceholder: false, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and select Question", () => {
|
||||
test("Long Text and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and select not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Select question (only Long Text required)",
|
||||
secondQuestion: "select",
|
||||
options: { hasPlaceholder: false, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Long Text Question and Short text question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
test("Long Text and Short text required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Text question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Long Text required and Short text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "textarea",
|
||||
fillText: "Test Long Text question and Text question (only Long Text required)",
|
||||
secondQuestion: "text",
|
||||
options: { hasPlaceholder: false, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,553 +0,0 @@
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Multiple Email Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and Address Question", () => {
|
||||
test("Multiple Email required and Address required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Address question (both required)",
|
||||
secondQuestion: "address",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and Address not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", false, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Address question (only Multiple Email required)",
|
||||
secondQuestion: "address",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and checkbox group Question", () => {
|
||||
test("Multiple Email required and checkbox group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and checkbox group question (both required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and checkbox group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and checkbox group question (only Multiple Email required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and checkbox Question", () => {
|
||||
test("Multiple Email required and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and checkbox question (both required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and checkbox (only Multiple Email required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and Long text Question", () => {
|
||||
test("Multiple Email required and Long text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Long Text question (both required)",
|
||||
secondQuestion: "textarea",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and Long text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", false, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Long Text question (only Multiple Email required)",
|
||||
secondQuestion: "textarea",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and multiselect Question", () => {
|
||||
test("Multiple Email required and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Multi Select question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Multi Select question (only Multiple Email required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and Number Question", () => {
|
||||
test("Multiple Email required and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", true, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Number question (both required)",
|
||||
secondQuestion: "number",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", false, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Number question (only Multiple Email required)",
|
||||
secondQuestion: "number",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple email Question and phone Question", () => {
|
||||
test("Multiple email required and Phone required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Phone question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple email and Phone not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", false, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Phone question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and Radio group Question", () => {
|
||||
test("Multiple Email required and Radio group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Radio question (both required)",
|
||||
secondQuestion: "radio",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and Radio group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Radio question (only Multiple Email required)",
|
||||
secondQuestion: "radio",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and select Question", () => {
|
||||
test("Multiple Email required and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and select not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", false, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Select question (only Multiple Email required)",
|
||||
secondQuestion: "select",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Multiple Email Question and Short text question", () => {
|
||||
test("Multiple Email required and Short text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Text question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Multiple Email and Short text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "multiemail",
|
||||
fillText: "Test Multiple Email question and Text question (only Multiple Email required)",
|
||||
secondQuestion: "text",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,446 +0,0 @@
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Phone Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and Address Question", () => {
|
||||
test("Phone and Address required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Address question (both required)",
|
||||
secondQuestion: "address",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and Address not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", false, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Address question (only phone required)",
|
||||
secondQuestion: "address",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and checkbox group Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: false, isRequired: true };
|
||||
test("Phone and checkbox group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and checkbox group question (both required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and checkbox group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and checkbox group question (only phone required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and checkbox Question", () => {
|
||||
test("Phone and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and checkbox question (both required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
test("Phone required and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and checkbox (only phone required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and Long text Question", () => {
|
||||
test("Phone and Long text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Long Text question (both required)",
|
||||
secondQuestion: "textarea",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and Long text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", false, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Long Text question (only phone required)",
|
||||
secondQuestion: "textarea",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and Multi email Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
test("Phone and Multi email required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Multi Email question (both required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and Multi email not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
false,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Multi Email question (only phone required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and multiselect Question", () => {
|
||||
test("Phone and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Multi Select question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Multi Select question (only phone required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and Number Question", () => {
|
||||
test("Phone and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", true, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Number question (both required)",
|
||||
secondQuestion: "number",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", false, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Number question (only phone required)",
|
||||
secondQuestion: "number",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and Radio group Question", () => {
|
||||
test("Phone and Radio group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Radio question (both required)",
|
||||
secondQuestion: "radio",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and Radio group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Radio question (only phone required)",
|
||||
secondQuestion: "radio",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and select Question", () => {
|
||||
test("Phone and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and select not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", false, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Select question (only phone required)",
|
||||
secondQuestion: "select",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Phone Question and Short text question", () => {
|
||||
test("Phone and Short text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Text question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Phone required and Short text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "phone",
|
||||
fillText: "Test Phone question and Text question (only phone required)",
|
||||
secondQuestion: "text",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,444 +0,0 @@
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Radio Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and Address Question", () => {
|
||||
test("Radio required and Address required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Address question (both required)",
|
||||
secondQuestion: "address",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and Address not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", false, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Address question (only radio required)",
|
||||
secondQuestion: "address",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and checkbox group Question", () => {
|
||||
test("Radio required and checkbox group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and checkbox group question (both required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and checkbox group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and checkbox group question (only radio required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and checkbox Question", () => {
|
||||
test("Radio required and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and checkbox question (both required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
test("Radio and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and checkbox (only radio required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and Long text Question", () => {
|
||||
test("Radio required and Long text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Long Text question (both required)",
|
||||
secondQuestion: "textarea",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and Long text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", false, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Long Text question (only radio required)",
|
||||
secondQuestion: "textarea",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and Multi email Question", () => {
|
||||
test("Radio required and Multi email required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Multi Email question (both required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and Multi email not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
false,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Multi Email question (only radio required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and multiselect Question", () => {
|
||||
test("Radio required and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Multi Select question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Multi Select question (only radio required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and Number Question", () => {
|
||||
test("Radio required and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", true, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Number question (both required)",
|
||||
secondQuestion: "number",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", false, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Number question (only radio required)",
|
||||
secondQuestion: "number",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and Phone Question", () => {
|
||||
test("Radio required and Phone required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Phone question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and Phone not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", false, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Phone question (only radio required)",
|
||||
secondQuestion: "phone",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and select Question", () => {
|
||||
test("Radio required and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Select question (both required)",
|
||||
secondQuestion: "select",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and select not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", false, "select test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Select question (only radio required)",
|
||||
secondQuestion: "select",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Radio Question and Short text question", () => {
|
||||
test("Radio required and Short text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Text question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Radio and Short text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "radio",
|
||||
fillText: "Test Radio question and Text question (only radio required)",
|
||||
secondQuestion: "text",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
/* eslint-disable playwright/no-conditional-in-test */
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe.configure({ mode: "serial" });
|
||||
|
||||
test.describe("Booking with recurring checked", () => {
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("recurring");
|
||||
});
|
||||
|
||||
test("Updates event type with recurring events", async ({ page, bookingPage }) => {
|
||||
await bookingPage.updateRecurringTab("2", "3");
|
||||
await bookingPage.updateEventType();
|
||||
await page.getByRole("link", { name: "Event Types" }).click();
|
||||
await bookingPage.assertRepeatEventType();
|
||||
});
|
||||
|
||||
test("Updates and shows recurring schedule correctly in booking page", async ({ bookingPage }) => {
|
||||
await bookingPage.updateRecurringTab("2", "3");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.fillRecurringFieldAndConfirm(eventTypePage);
|
||||
});
|
||||
});
|
||||
@@ -1,107 +0,0 @@
|
||||
/* eslint-disable playwright/no-conditional-in-test */
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
const resolutions = [
|
||||
{
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
},
|
||||
{
|
||||
width: 1280,
|
||||
height: 720,
|
||||
},
|
||||
{
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
];
|
||||
|
||||
test.describe("Booking With All Questions", () => {
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
|
||||
const allQuestions = [
|
||||
"phone",
|
||||
"address",
|
||||
"checkbox",
|
||||
"boolean",
|
||||
"textarea",
|
||||
"multiemail",
|
||||
"multiselect",
|
||||
"number",
|
||||
"radio",
|
||||
"select",
|
||||
"text",
|
||||
];
|
||||
for (const question of allQuestions) {
|
||||
if (
|
||||
question !== "number" &&
|
||||
question !== "select" &&
|
||||
question !== "checkbox" &&
|
||||
question !== "boolean" &&
|
||||
question !== "multiselect" &&
|
||||
question !== "radio"
|
||||
) {
|
||||
await bookingPage.addQuestion(
|
||||
question,
|
||||
`${question}-test`,
|
||||
`${question} test`,
|
||||
true,
|
||||
`${question} test`
|
||||
);
|
||||
} else {
|
||||
await bookingPage.addQuestion(question, `${question}-test`, `${question} test`, true);
|
||||
}
|
||||
await bookingPage.checkField(question);
|
||||
}
|
||||
});
|
||||
|
||||
for (const resolution of resolutions) {
|
||||
test(`Booking with ${resolution.width}x${resolution.height} resolution and all questions`, async ({
|
||||
bookingPage,
|
||||
}) => {
|
||||
await bookingPage.setResolution(resolution.width, resolution.height);
|
||||
await bookingPage.updateEventType();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe("Booking With no questions", () => {
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
for (const resolution of resolutions) {
|
||||
test(`Booking with ${resolution.width}x${resolution.height} resolution and no questions`, async ({
|
||||
bookingPage,
|
||||
}) => {
|
||||
await bookingPage.setResolution(resolution.width, resolution.height);
|
||||
await bookingPage.updateEventType();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe("Booking page with no questions", () => {
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
for (const resolution of resolutions) {
|
||||
test(`Booking page with ${resolution.width}x${resolution.height} resolution`, async ({ bookingPage }) => {
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await eventTypePage.setViewportSize({ width: resolution.width, height: resolution.height });
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.confirmBooking(eventTypePage);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,441 +0,0 @@
|
||||
import { loginUser } from "../fixtures/regularBookings";
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.describe("Booking With Phone Question and Each Other Question", () => {
|
||||
const bookingOptions = { hasPlaceholder: true, isRequired: true };
|
||||
|
||||
test.beforeEach(async ({ page, users, bookingPage }) => {
|
||||
await loginUser(users);
|
||||
await page.goto("/event-types");
|
||||
await bookingPage.goToEventType("30 min");
|
||||
await bookingPage.goToTab("event_advanced_tab_title");
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Address Question", () => {
|
||||
test("Select required and Address required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", true, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and Address question (both required)",
|
||||
secondQuestion: "address",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Address not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("address", "address-test", "address test", false, "address test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and Address question (only select required)",
|
||||
secondQuestion: "address",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and checkbox group Question", () => {
|
||||
test("Select required and checkbox group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and Checkbox question (both required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and checkbox group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("checkbox", "checkbox-test", "checkbox test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and Checkbox question (only Select required)",
|
||||
secondQuestion: "checkbox",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and checkbox Question", () => {
|
||||
test("Select required and checkbox required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and boolean question (both required)",
|
||||
secondQuestion: "boolean",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and checkbox not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("boolean", "boolean-test", "boolean test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and boolean question (only select required)",
|
||||
secondQuestion: "boolean",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Long text Question", () => {
|
||||
test("Select required and Long text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", true, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and textarea question (both required)",
|
||||
secondQuestion: "textarea",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Long text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("textarea", "textarea-test", "textarea test", false, "textarea test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and textarea question (only select required)",
|
||||
secondQuestion: "textarea",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Multi email Question", () => {
|
||||
test("Select required and Multi email required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
true,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and multiemail question (both required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Multi email not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion(
|
||||
"multiemail",
|
||||
"multiemail-test",
|
||||
"multiemail test",
|
||||
false,
|
||||
"multiemail test"
|
||||
);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and multiemail question (only select required)",
|
||||
secondQuestion: "multiemail",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and multiselect Question", () => {
|
||||
test("Select required and multiselect text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and multiselect question (both required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and multiselect text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("multiselect", "multiselect-test", "multiselect test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and multiselect question (only select required)",
|
||||
secondQuestion: "multiselect",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Number Question", () => {
|
||||
test("Select required and Number required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", true, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and number question (both required)",
|
||||
secondQuestion: "number",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Number not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("number", "number-test", "number test", false, "number test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and number question (only select required)",
|
||||
secondQuestion: "number",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Phone Question", () => {
|
||||
test("Select required and select required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", true, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and phone question (both required)",
|
||||
secondQuestion: "phone",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Phone not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("phone", "phone-test", "phone test", false, "phone test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and phone question (only select required)",
|
||||
secondQuestion: "phone",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Radio group Question", () => {
|
||||
test("Select required and Radio group required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", true);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and radio question (both required)",
|
||||
secondQuestion: "radio",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Radio group not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("radio", "radio-test", "radio test", false);
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and radio question (only select required)",
|
||||
secondQuestion: "radio",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Booking With Select Question and Short text question", () => {
|
||||
test("Select required and Short text required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", true, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and text question (both required)",
|
||||
secondQuestion: "text",
|
||||
options: bookingOptions,
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
|
||||
test("Select and Short text not required", async ({ bookingPage }) => {
|
||||
await bookingPage.addQuestion("select", "select-test", "select test", true, "select test");
|
||||
await bookingPage.addQuestion("text", "text-test", "text test", false, "text test");
|
||||
await bookingPage.updateEventType();
|
||||
const eventTypePage = await bookingPage.previewEventType();
|
||||
await bookingPage.selectTimeSlot(eventTypePage);
|
||||
await bookingPage.fillAndConfirmBooking({
|
||||
eventTypePage,
|
||||
placeholderText: "Please share anything that will help prepare for our meeting.",
|
||||
question: "select",
|
||||
fillText: "Test Select question and text question (only select required)",
|
||||
secondQuestion: "text",
|
||||
options: { ...bookingOptions, isRequired: false },
|
||||
});
|
||||
await bookingPage.rescheduleBooking(eventTypePage);
|
||||
await bookingPage.assertBookingRescheduled(eventTypePage);
|
||||
await bookingPage.cancelBooking(eventTypePage);
|
||||
await bookingPage.assertBookingCanceled(eventTypePage);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { expect, type Page } from "@playwright/test";
|
||||
|
||||
export function createAppsFixture(page: Page) {
|
||||
return {
|
||||
goToAppsCategory: async (category: string) => {
|
||||
await page.getByTestId(`app-store-category-${category}`).nth(1).click();
|
||||
await page.goto("apps/categories/analytics");
|
||||
},
|
||||
installApp: async (app: string) => {
|
||||
await page.getByTestId(`app-store-app-card-${app}`).click();
|
||||
await page.getByTestId("install-app-button").click();
|
||||
},
|
||||
goBackToAppsPage: async () => {
|
||||
await page.getByTestId("add-apps").click();
|
||||
},
|
||||
goToEventType: async (eventType: string) => {
|
||||
await page.getByRole("link", { name: eventType }).click();
|
||||
},
|
||||
goToAppsTab: async () => {
|
||||
await page.getByTestId("vertical-tab-apps").click();
|
||||
},
|
||||
activeApp: async (app: string) => {
|
||||
await page.getByTestId(`${app}-app-switch`).click();
|
||||
},
|
||||
verifyAppsInfo: async (activeApps: number) => {
|
||||
await expect(page.locator(`text=6 apps, ${activeApps} active`)).toBeVisible();
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,183 +1,14 @@
|
||||
import { expect, type Page } from "@playwright/test";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import type { MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
import { localize } from "../lib/testUtils";
|
||||
import type { createUsersFixture } from "./users";
|
||||
|
||||
const reschedulePlaceholderText = "Let others know why you need to reschedule";
|
||||
export const scheduleSuccessfullyText = "This meeting is scheduled";
|
||||
|
||||
const EMAIL = "test@test.com";
|
||||
const EMAIL2 = "test2@test.com";
|
||||
const PHONE = "+55 (32) 983289947";
|
||||
|
||||
type BookingOptions = {
|
||||
hasPlaceholder?: boolean;
|
||||
isReschedule?: boolean;
|
||||
isRequired?: boolean;
|
||||
isAllRequired?: boolean;
|
||||
isMultiSelect?: boolean;
|
||||
};
|
||||
|
||||
interface QuestionActions {
|
||||
[key: string]: () => Promise<void>;
|
||||
}
|
||||
|
||||
type teamBookingtypes = { isManagedType?: boolean; isRoundRobinType?: boolean; isCollectiveType?: boolean };
|
||||
|
||||
type customLocators = {
|
||||
shouldChangeSelectLocator: boolean;
|
||||
shouldUseLastRadioGroupLocator: boolean;
|
||||
shouldUseFirstRadioGroupLocator: boolean;
|
||||
shouldChangeMultiSelectLocator: boolean;
|
||||
};
|
||||
|
||||
type fillAndConfirmBookingParams = {
|
||||
eventTypePage: Page;
|
||||
placeholderText: string;
|
||||
question: string;
|
||||
fillText: string;
|
||||
secondQuestion: string;
|
||||
options: BookingOptions;
|
||||
};
|
||||
|
||||
type UserFixture = ReturnType<typeof createUsersFixture>;
|
||||
|
||||
function isLastDayOfMonth(): boolean {
|
||||
const today = dayjs();
|
||||
const endOfMonth = today.endOf("month");
|
||||
return today.isSame(endOfMonth, "day");
|
||||
}
|
||||
|
||||
const fillQuestion = async (eventTypePage: Page, questionType: string, customLocators: customLocators) => {
|
||||
const questionActions: QuestionActions = {
|
||||
phone: async () => {
|
||||
await eventTypePage.locator('input[name="phone-test"]').clear();
|
||||
await eventTypePage.locator('input[name="phone-test"]').fill(PHONE);
|
||||
},
|
||||
multiemail: async () => {
|
||||
await eventTypePage.getByRole("button", { name: `${questionType} test` }).click();
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).fill(EMAIL);
|
||||
await eventTypePage.getByTestId("add-another-guest").last().click();
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).last().fill(EMAIL2);
|
||||
},
|
||||
checkbox: async () => {
|
||||
if (customLocators.shouldUseLastRadioGroupLocator || customLocators.shouldChangeMultiSelectLocator) {
|
||||
await eventTypePage.getByLabel("Option 1").last().click();
|
||||
await eventTypePage.getByLabel("Option 2").last().click();
|
||||
} else if (customLocators.shouldUseFirstRadioGroupLocator) {
|
||||
await eventTypePage.getByLabel("Option 1").first().click();
|
||||
await eventTypePage.getByLabel("Option 2").first().click();
|
||||
} else {
|
||||
await eventTypePage.getByLabel("Option 1").click();
|
||||
await eventTypePage.getByLabel("Option 2").click();
|
||||
}
|
||||
},
|
||||
multiselect: async () => {
|
||||
if (customLocators.shouldChangeMultiSelectLocator) {
|
||||
await eventTypePage.getByLabel("multi-select-dropdown").click();
|
||||
await eventTypePage.getByTestId("select-option-Option 1").click();
|
||||
} else {
|
||||
await eventTypePage.getByLabel("multi-select-dropdown").last().click();
|
||||
await eventTypePage.getByTestId("select-option-Option 1").click();
|
||||
}
|
||||
},
|
||||
boolean: async () => {
|
||||
await eventTypePage.getByLabel(`${questionType} test`).check();
|
||||
},
|
||||
radio: async () => {
|
||||
await eventTypePage.locator('[id="radio-test\\.option\\.0\\.radio"]').click();
|
||||
},
|
||||
select: async () => {
|
||||
if (customLocators.shouldChangeSelectLocator) {
|
||||
await eventTypePage.getByLabel("select-dropdown").first().click();
|
||||
await eventTypePage.getByTestId("select-option-Option 1").click();
|
||||
} else {
|
||||
await eventTypePage.getByLabel("select-dropdown").last().click();
|
||||
await eventTypePage.getByTestId("select-option-Option 1").click();
|
||||
}
|
||||
},
|
||||
number: async () => {
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).click();
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).fill("123");
|
||||
},
|
||||
address: async () => {
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).click();
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).fill("address test");
|
||||
},
|
||||
textarea: async () => {
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).click();
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).fill("textarea test");
|
||||
},
|
||||
text: async () => {
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).click();
|
||||
await eventTypePage.getByPlaceholder(`${questionType} test`).fill("text test");
|
||||
},
|
||||
};
|
||||
if (questionActions[questionType]) {
|
||||
await questionActions[questionType]();
|
||||
}
|
||||
};
|
||||
|
||||
const fillAllQuestions = async (eventTypePage: Page, questions: string[], options: BookingOptions) => {
|
||||
if (options.isAllRequired) {
|
||||
for (const question of questions) {
|
||||
switch (question) {
|
||||
case "email":
|
||||
await eventTypePage.getByPlaceholder("Email").click();
|
||||
await eventTypePage.getByPlaceholder("Email").fill(EMAIL);
|
||||
break;
|
||||
case "phone":
|
||||
await eventTypePage.getByPlaceholder("Phone test").click();
|
||||
await eventTypePage.getByPlaceholder("Phone test").fill(PHONE);
|
||||
break;
|
||||
case "address":
|
||||
await eventTypePage.getByPlaceholder("Address test").click();
|
||||
await eventTypePage.getByPlaceholder("Address test").fill("123 Main St, City, Country");
|
||||
break;
|
||||
case "textarea":
|
||||
await eventTypePage.getByPlaceholder("Textarea test").click();
|
||||
await eventTypePage.getByPlaceholder("Textarea test").fill("This is a sample text for textarea.");
|
||||
break;
|
||||
case "select":
|
||||
await eventTypePage.getByLabel("select-dropdown").last().click();
|
||||
await eventTypePage.getByTestId("select-option-Option 1").click();
|
||||
break;
|
||||
case "multiselect":
|
||||
// select-dropdown
|
||||
await eventTypePage.getByLabel("multi-select-dropdown").click();
|
||||
await eventTypePage.getByTestId("select-option-Option 1").click();
|
||||
break;
|
||||
case "number":
|
||||
await eventTypePage.getByLabel("number test").click();
|
||||
await eventTypePage.getByLabel("number test").fill("123");
|
||||
break;
|
||||
case "radio":
|
||||
await eventTypePage.getByRole("radiogroup").getByText("Option 1").check();
|
||||
break;
|
||||
case "text":
|
||||
await eventTypePage.getByPlaceholder("Text test").click();
|
||||
await eventTypePage.getByPlaceholder("Text test").fill("Sample text");
|
||||
break;
|
||||
case "checkbox":
|
||||
await eventTypePage.getByLabel("Option 1").first().check();
|
||||
await eventTypePage.getByLabel("Option 2").first().check();
|
||||
break;
|
||||
case "boolean":
|
||||
await eventTypePage.getByLabel(`${question} test`).check();
|
||||
break;
|
||||
case "multiemail":
|
||||
await eventTypePage.getByRole("button", { name: "multiemail test" }).click();
|
||||
await eventTypePage.getByPlaceholder("multiemail test").fill(EMAIL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export async function loginUser(users: UserFixture) {
|
||||
const pro = await users.create({ name: "testuser" });
|
||||
await pro.apiLogin();
|
||||
@@ -191,17 +22,6 @@ export async function loginUserWithTeam(users: UserFixture, role: MembershipRole
|
||||
await pro.apiLogin();
|
||||
}
|
||||
|
||||
const goToNextMonthIfNoAvailabilities = async (eventTypePage: Page) => {
|
||||
try {
|
||||
if (isLastDayOfMonth()) {
|
||||
await eventTypePage.getByTestId("view_next_month").waitFor({ timeout: 6000 });
|
||||
await eventTypePage.getByTestId("view_next_month").click();
|
||||
}
|
||||
} catch (err) {
|
||||
console.info("No need to click on view next month button");
|
||||
}
|
||||
};
|
||||
|
||||
export function createBookingPageFixture(page: Page) {
|
||||
return {
|
||||
goToEventType: async (eventType: string) => {
|
||||
@@ -216,308 +36,19 @@ export function createBookingPageFixture(page: Page) {
|
||||
goToTab: async (tabName: string) => {
|
||||
await page.getByTestId(`vertical-tab-${tabName}`).click();
|
||||
},
|
||||
|
||||
goToEventTypesPage: async () => {
|
||||
await page.goto("/event-types");
|
||||
},
|
||||
|
||||
setResolution: async (width: number, height: number) => {
|
||||
await page.setViewportSize({ width: width, height: height });
|
||||
},
|
||||
addQuestion: async (
|
||||
questionType: string,
|
||||
identifier: string,
|
||||
label: string,
|
||||
isRequired: boolean,
|
||||
placeholder?: string
|
||||
) => {
|
||||
await page.getByTestId("add-field").click();
|
||||
await page.getByTestId("test-field-type").click();
|
||||
await page.getByTestId(`select-option-${questionType}`).click();
|
||||
await page.getByLabel("Identifier").dblclick();
|
||||
await page.getByLabel("Identifier").fill(identifier);
|
||||
await page.getByLabel("Label").click();
|
||||
await page.getByLabel("Label").fill(label);
|
||||
if (placeholder) {
|
||||
await page.getByLabel("Placeholder").click();
|
||||
await page.getByLabel("Placeholder").fill(placeholder);
|
||||
}
|
||||
if (!isRequired) {
|
||||
await page.getByRole("radio", { name: "No" }).click();
|
||||
}
|
||||
await page.getByTestId("field-add-save").click();
|
||||
},
|
||||
updateRecurringTab: async (repeatWeek: string, maxEvents: string) => {
|
||||
const repeatText = (await localize("en"))("repeats_every");
|
||||
const maximumOf = (await localize("en"))("for_a_maximum_of");
|
||||
await page.getByTestId("recurring-event-check").click();
|
||||
await page
|
||||
.getByTestId("recurring-event-collapsible")
|
||||
.locator("div")
|
||||
.filter({ hasText: repeatText })
|
||||
.getByRole("spinbutton")
|
||||
.fill(repeatWeek);
|
||||
await page
|
||||
.getByTestId("recurring-event-collapsible")
|
||||
.locator("div")
|
||||
.filter({ hasText: maximumOf })
|
||||
.getByRole("spinbutton")
|
||||
.fill(maxEvents);
|
||||
},
|
||||
updateEventType: async () => {
|
||||
await page.getByTestId("update-eventtype").click();
|
||||
const toast = await page.waitForSelector('[data-testid="toast-success"]');
|
||||
expect(toast).toBeTruthy();
|
||||
},
|
||||
|
||||
previewEventType: async () => {
|
||||
const eventtypePromise = page.waitForEvent("popup");
|
||||
await page.getByTestId("preview-button").click();
|
||||
return eventtypePromise;
|
||||
},
|
||||
|
||||
selectTimeSlot: async (eventTypePage: Page) => {
|
||||
await goToNextMonthIfNoAvailabilities(eventTypePage);
|
||||
await eventTypePage.getByTestId("time").first().click();
|
||||
},
|
||||
|
||||
clickReschedule: async () => {
|
||||
await page.getByText("Reschedule").click();
|
||||
},
|
||||
|
||||
selectFirstAvailableTime: async () => {
|
||||
await page.getByTestId("time").first().click();
|
||||
},
|
||||
|
||||
fillRescheduleReasonAndConfirm: async () => {
|
||||
await page.getByPlaceholder(reschedulePlaceholderText).click();
|
||||
await page.getByPlaceholder(reschedulePlaceholderText).fill("Test reschedule");
|
||||
await page.getByTestId("confirm-reschedule-button").click();
|
||||
},
|
||||
|
||||
fillRecurringFieldAndConfirm: async (eventTypePage: Page) => {
|
||||
await eventTypePage.getByTestId("occurrence-input").click();
|
||||
await eventTypePage.getByTestId("occurrence-input").fill("2");
|
||||
await goToNextMonthIfNoAvailabilities(eventTypePage);
|
||||
await eventTypePage.getByTestId("time").first().click();
|
||||
await expect(eventTypePage.getByTestId("recurring-dates")).toBeVisible();
|
||||
},
|
||||
|
||||
cancelBookingWithReason: async (page: Page) => {
|
||||
await page.getByTestId("cancel").click();
|
||||
await page.getByTestId("cancel_reason").fill("Test cancel");
|
||||
await page.getByTestId("confirm_cancel").click();
|
||||
},
|
||||
|
||||
assertBookingCanceled: async (page: Page) => {
|
||||
await expect(page.getByTestId("cancelled-headline")).toBeVisible();
|
||||
},
|
||||
|
||||
rescheduleBooking: async (eventTypePage: Page) => {
|
||||
await goToNextMonthIfNoAvailabilities(eventTypePage);
|
||||
await eventTypePage.getByText("Reschedule").click();
|
||||
while (await eventTypePage.getByRole("button", { name: "View next" }).isVisible()) {
|
||||
await eventTypePage.getByRole("button", { name: "View next" }).click();
|
||||
}
|
||||
await eventTypePage.getByTestId("time").first().click();
|
||||
await eventTypePage.getByPlaceholder(reschedulePlaceholderText).click();
|
||||
await eventTypePage.getByPlaceholder(reschedulePlaceholderText).fill("Test reschedule");
|
||||
await eventTypePage.getByTestId("confirm-reschedule-button").click();
|
||||
await eventTypePage.waitForTimeout(400);
|
||||
if (
|
||||
await eventTypePage.getByRole("heading", { name: "Could not reschedule the meeting." }).isVisible()
|
||||
) {
|
||||
await eventTypePage.getByTestId("back").click();
|
||||
await eventTypePage.getByTestId("time").last().click();
|
||||
await eventTypePage.getByTestId("confirm-reschedule-button").click();
|
||||
}
|
||||
},
|
||||
|
||||
assertBookingRescheduled: async (page: Page) => {
|
||||
await expect(page.getByText(scheduleSuccessfullyText)).toBeVisible();
|
||||
},
|
||||
|
||||
assertRepeatEventType: async () => {
|
||||
await expect(page.getByTestId("repeat-eventtype")).toBeVisible();
|
||||
},
|
||||
|
||||
cancelBooking: async (eventTypePage: Page) => {
|
||||
await eventTypePage.getByTestId("cancel").click();
|
||||
await eventTypePage.getByTestId("cancel_reason").fill("Test cancel");
|
||||
await eventTypePage.getByTestId("confirm_cancel").click();
|
||||
await expect(eventTypePage.getByTestId("cancelled-headline")).toBeVisible();
|
||||
},
|
||||
|
||||
confirmBooking: async (eventTypePage: Page) => {
|
||||
await eventTypePage.getByTestId("confirm-book-button").click();
|
||||
await eventTypePage.waitForURL("booking/**");
|
||||
await expect(eventTypePage.getByText(scheduleSuccessfullyText)).toBeVisible();
|
||||
},
|
||||
|
||||
fillAndConfirmBooking: async ({
|
||||
eventTypePage,
|
||||
placeholderText,
|
||||
question,
|
||||
fillText,
|
||||
secondQuestion,
|
||||
options,
|
||||
}: fillAndConfirmBookingParams) => {
|
||||
const confirmButton = options.isReschedule ? "confirm-reschedule-button" : "confirm-book-button";
|
||||
|
||||
await expect(eventTypePage.getByText(`${secondQuestion} test`).first()).toBeVisible();
|
||||
await eventTypePage.getByPlaceholder(placeholderText).fill(fillText);
|
||||
|
||||
// Change the selector for specifics cases related to select question
|
||||
const shouldChangeSelectLocator = (question: string, secondQuestion: string): boolean =>
|
||||
question === "select" && ["multiemail", "multiselect", "address"].includes(secondQuestion);
|
||||
|
||||
const shouldUseLastRadioGroupLocator = (question: string, secondQuestion: string): boolean =>
|
||||
question === "radio" && secondQuestion === "checkbox";
|
||||
|
||||
const shouldUseFirstRadioGroupLocator = (question: string, secondQuestion: string): boolean =>
|
||||
question === "checkbox" && secondQuestion === "radio";
|
||||
|
||||
const shouldChangeMultiSelectLocator = (question: string, secondQuestion: string): boolean =>
|
||||
question === "multiselect" &&
|
||||
["address", "checkbox", "multiemail", "select"].includes(secondQuestion);
|
||||
|
||||
const customLocators = {
|
||||
shouldChangeSelectLocator: shouldChangeSelectLocator(question, secondQuestion),
|
||||
shouldUseLastRadioGroupLocator: shouldUseLastRadioGroupLocator(question, secondQuestion),
|
||||
shouldUseFirstRadioGroupLocator: shouldUseFirstRadioGroupLocator(question, secondQuestion),
|
||||
shouldChangeMultiSelectLocator: shouldChangeMultiSelectLocator(question, secondQuestion),
|
||||
};
|
||||
|
||||
// Fill the first question
|
||||
await fillQuestion(eventTypePage, question, customLocators);
|
||||
|
||||
// Fill the second question if is required
|
||||
options.isRequired && (await fillQuestion(eventTypePage, secondQuestion, customLocators));
|
||||
|
||||
await eventTypePage.getByTestId(confirmButton).click();
|
||||
await eventTypePage.waitForTimeout(400);
|
||||
if (await eventTypePage.getByRole("heading", { name: "Could not book the meeting." }).isVisible()) {
|
||||
await eventTypePage.getByTestId("back").click();
|
||||
await eventTypePage.getByTestId("time").last().click();
|
||||
await fillQuestion(eventTypePage, question, customLocators);
|
||||
options.isRequired && (await fillQuestion(eventTypePage, secondQuestion, customLocators));
|
||||
await eventTypePage.getByTestId(confirmButton).click();
|
||||
}
|
||||
const scheduleSuccessfullyPage = eventTypePage.getByText(scheduleSuccessfullyText);
|
||||
await scheduleSuccessfullyPage.waitFor({ state: "visible" });
|
||||
await expect(scheduleSuccessfullyPage).toBeVisible();
|
||||
},
|
||||
|
||||
fillAllQuestions: async (eventTypePage: Page, questions: string[], options: BookingOptions) => {
|
||||
const confirmButton = options.isReschedule ? "confirm-reschedule-button" : "confirm-book-button";
|
||||
await fillAllQuestions(eventTypePage, questions, options);
|
||||
await eventTypePage.getByTestId(confirmButton).click();
|
||||
const scheduleSuccessfullyPage = eventTypePage.getByText(scheduleSuccessfullyText);
|
||||
await scheduleSuccessfullyPage.waitFor({ state: "visible" });
|
||||
await expect(scheduleSuccessfullyPage).toBeVisible();
|
||||
},
|
||||
addGuests: async (eventTypePage: Page, options: { guests: string[] }) => {
|
||||
await eventTypePage.getByTestId("add-guests").click();
|
||||
for (const guest of options.guests) {
|
||||
await eventTypePage.getByPlaceholder("Email").fill(guest);
|
||||
}
|
||||
},
|
||||
createTeam: async (name: string) => {
|
||||
await page.getByTestId("teams-test").click();
|
||||
await page.getByTestId("new-team-btn").click();
|
||||
await page.getByPlaceholder("Acme Inc.").click();
|
||||
await page.getByPlaceholder("Acme Inc.").fill(name);
|
||||
await page.getByTestId("continue-button").click();
|
||||
await page.getByTestId("publish-button").click();
|
||||
|
||||
await page.getByTestId("vertical-tab-Back").click();
|
||||
},
|
||||
|
||||
createTeamEventType: async (name: string, options: teamBookingtypes) => {
|
||||
await page.getByTestId("new-event-type").click();
|
||||
await page.getByTestId("option-0").click();
|
||||
|
||||
// We first simulate to create a default event type to check if managed option is not available
|
||||
|
||||
const managedEventDescription = (await localize("en"))("managed_event_description");
|
||||
const roundRobinEventDescription = (await localize("en"))("round_robin_description");
|
||||
const collectiveEventDescription = (await localize("en"))("collective_description");
|
||||
const quickChatText = (await localize("en"))("quick_chat");
|
||||
await expect(page.locator("div").filter({ hasText: managedEventDescription })).toBeHidden();
|
||||
await page.getByTestId("dialog-rejection").click();
|
||||
|
||||
await page.getByTestId("new-event-type").click();
|
||||
await page.getByTestId("option-team-1").click();
|
||||
await page.getByPlaceholder(quickChatText).fill(name);
|
||||
if (options.isCollectiveType) {
|
||||
await page
|
||||
.locator("div")
|
||||
.filter({ hasText: `Collective${collectiveEventDescription}` })
|
||||
.getByRole("radio")
|
||||
.first()
|
||||
.click();
|
||||
}
|
||||
|
||||
if (options.isRoundRobinType) {
|
||||
await page
|
||||
.locator("div")
|
||||
.filter({ hasText: `Round Robin${roundRobinEventDescription}` })
|
||||
.getByRole("radio")
|
||||
.nth(1)
|
||||
.click();
|
||||
}
|
||||
|
||||
if (options.isManagedType) {
|
||||
await page
|
||||
.locator("div")
|
||||
.filter({ hasText: `Managed Event${managedEventDescription}` })
|
||||
.getByRole("radio")
|
||||
.last()
|
||||
.click();
|
||||
|
||||
const managedEventClarification = (await localize("en"))("managed_event_url_clarification");
|
||||
await expect(page.getByText(managedEventClarification)).toBeVisible();
|
||||
}
|
||||
|
||||
const continueText = (await localize("en"))("continue");
|
||||
const toast = page.getByTestId("toast-success");
|
||||
|
||||
await page.getByRole("button", { name: continueText }).click();
|
||||
expect(toast).toBeTruthy();
|
||||
await page.getByTestId("update-eventtype").click();
|
||||
},
|
||||
assertLabelWithCorrectTeamName: async (page: Page, teamName: string) => {
|
||||
await expect(page.getByRole("link", { name: teamName }).first()).toBeVisible();
|
||||
},
|
||||
assertBookingWithCorrectTitleAndDescription: async (
|
||||
page: Page,
|
||||
options: { profileName: string; bookingName: string; teamName: string; aditionalGuestEmail?: string }
|
||||
) => {
|
||||
options.aditionalGuestEmail
|
||||
? await expect(
|
||||
page.getByRole("link", {
|
||||
name: `${options.bookingName} between ${options.teamName} and ${options.profileName} You , ${options.profileName} and ${options.aditionalGuestEmail}`,
|
||||
})
|
||||
).toBeVisible()
|
||||
: await expect(
|
||||
page.getByRole("link", {
|
||||
name: `${options.bookingName} between ${options.teamName} and ${options.profileName} You and ${options.profileName}`,
|
||||
})
|
||||
).toBeVisible();
|
||||
},
|
||||
clickOnBooking: async (page: Page, teamName: string) => {
|
||||
await page.getByRole("link", { name: teamName }).first().click();
|
||||
},
|
||||
|
||||
checkField: async (question: string, options?: { isOptional: boolean }) => {
|
||||
if (options?.isOptional) {
|
||||
await expect(page.getByTestId(`field-${question}-test`).getByTestId("optional")).toBeVisible();
|
||||
} else {
|
||||
await expect(page.getByTestId(`field-${question}-test`).getByTestId("required")).toBeVisible();
|
||||
}
|
||||
await expect(page.getByTestId(`field-${question}-test`)).toBeVisible();
|
||||
},
|
||||
|
||||
checkRequiresConfirmation: async () => {
|
||||
// Check existence of the icon
|
||||
await expect(page.getByTestId("requires-confirmation-title").locator("svg")).toBeVisible();
|
||||
@@ -526,7 +57,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(confirmationSwitch).toBeVisible();
|
||||
await confirmationSwitch.click();
|
||||
},
|
||||
|
||||
checkRequiresBookerEmailVerification: async () => {
|
||||
await expect(page.getByTestId("requires-booker-email-verification-title").locator("svg")).toBeVisible();
|
||||
|
||||
@@ -535,7 +65,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(emailSwitch).toBeVisible();
|
||||
await emailSwitch.click();
|
||||
},
|
||||
|
||||
checkHideNotes: async () => {
|
||||
await expect(page.getByTestId("disable-notes-title").locator("svg")).toBeVisible();
|
||||
|
||||
@@ -544,7 +73,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(hideNotesSwitch).toBeVisible();
|
||||
await hideNotesSwitch.click();
|
||||
},
|
||||
|
||||
checkRedirectOnBooking: async () => {
|
||||
await expect(page.getByTestId("redirect-success-booking-title").locator("svg")).toBeVisible();
|
||||
|
||||
@@ -555,7 +83,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await page.getByTestId("external-redirect-url").fill("https://cal.com");
|
||||
await expect(page.getByTestId("redirect-url-warning")).toBeVisible();
|
||||
},
|
||||
|
||||
checkEnablePrivateUrl: async () => {
|
||||
await expect(page.getByTestId("hashedLinkCheck-title").locator("label div")).toBeVisible();
|
||||
|
||||
@@ -564,7 +91,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await page.getByTestId("hashedLinkCheck").click();
|
||||
await expect(page.getByTestId("generated-hash-url")).toBeVisible();
|
||||
},
|
||||
|
||||
toggleOfferSeats: async () => {
|
||||
await expect(page.getByTestId("offer-seats-toggle-title").locator("svg")).toBeVisible();
|
||||
|
||||
@@ -575,7 +101,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(seatSwitchField).toHaveValue("3");
|
||||
await expect(page.getByTestId("show-attendees")).toBeVisible();
|
||||
},
|
||||
|
||||
checkLockTimezone: async () => {
|
||||
await expect(page.getByTestId("lock-timezone-toggle-title").locator("svg")).toBeVisible();
|
||||
|
||||
@@ -584,18 +109,9 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(lockSwitch).toBeVisible();
|
||||
await lockSwitch.click();
|
||||
},
|
||||
|
||||
checkEventType: async () => {
|
||||
await expect(page.getByTestId("requires-confirmation-badge").last()).toBeVisible();
|
||||
},
|
||||
|
||||
assertBookingIsVisible: async (name: string) => {
|
||||
await expect(
|
||||
page.getByRole("link", {
|
||||
name,
|
||||
})
|
||||
).toBeVisible();
|
||||
},
|
||||
checkBufferTime: async () => {
|
||||
const minutes = (await localize("en"))("minutes");
|
||||
const fieldPlaceholder = page.getByPlaceholder("0");
|
||||
@@ -629,7 +145,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await page.getByTestId("select-option-60").click();
|
||||
await expect(page.getByText(`60 ${minutes}`, { exact: true })).toBeVisible();
|
||||
},
|
||||
|
||||
checkLimitBookingFrequency: async () => {
|
||||
const fieldPlaceholder = page.getByPlaceholder("1").nth(1);
|
||||
const limitFrequency = (await localize("en"))("limit_booking_frequency");
|
||||
@@ -645,7 +160,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(fieldPlaceholder).toHaveValue("12");
|
||||
await limitFrequencySwitch.click();
|
||||
},
|
||||
|
||||
checkLimitBookingDuration: async () => {
|
||||
const limitDuration = (await localize("en"))("limit_total_booking_duration");
|
||||
const addlimit = (await localize("en"))("add_limit");
|
||||
@@ -659,7 +173,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(page.getByTestId("add-limit")).toHaveCount(2);
|
||||
await limitDurationSwitch.click();
|
||||
},
|
||||
|
||||
checkLimitFutureBookings: async () => {
|
||||
const limitFutureBookings = (await localize("en"))("limit_future_bookings");
|
||||
const limitBookingsSwitch = page
|
||||
@@ -672,7 +185,6 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(page.locator("#RANGE")).toBeChecked();
|
||||
await limitBookingsSwitch.click();
|
||||
},
|
||||
|
||||
checkOffsetTimes: async () => {
|
||||
const offsetStart = (await localize("en"))("offset_start");
|
||||
const offsetStartTimes = (await localize("en"))("offset_toggle");
|
||||
@@ -685,54 +197,8 @@ export function createBookingPageFixture(page: Page) {
|
||||
page.getByText("e.g. this will show time slots to your bookers at 9:10 AM instead of 9:00 AM")
|
||||
).toBeVisible();
|
||||
},
|
||||
|
||||
checkTimeSlotsCount: async (eventTypePage: Page, count: number) => {
|
||||
await expect(eventTypePage.getByTestId("time")).toHaveCount(count);
|
||||
},
|
||||
createBookingWebhook: async (webhookReceiver: { url: string }, eventTitle: string) => {
|
||||
const events = [
|
||||
"Booking Canceled",
|
||||
"Booking Created",
|
||||
"Booking Rejected",
|
||||
"Booking Requested",
|
||||
"Booking Payment Initiated",
|
||||
"Booking Rescheduled",
|
||||
"Meeting Ended",
|
||||
"Booking Paid",
|
||||
"Recording Download Link Ready",
|
||||
];
|
||||
await page.goto(`${WEBAPP_URL}/event-types`);
|
||||
await page.getByText(eventTitle).click();
|
||||
|
||||
await page.getByTestId("vertical-tab-webhooks").click();
|
||||
|
||||
await page.getByTestId("new_webhook").click();
|
||||
await page.getByLabel("Subscriber URL").fill(webhookReceiver.url);
|
||||
await page.getByRole("button", { name: "Ping test" }).click();
|
||||
page
|
||||
.getByTestId("dialog-creation")
|
||||
.locator("div")
|
||||
.filter({ hasText: '{ "ok": true, "status": 200, "message": "{}" }' })
|
||||
.nth(2);
|
||||
await page.getByRole("button", { name: "Create Webhook" }).click();
|
||||
|
||||
page.getByText(webhookReceiver.url);
|
||||
events.forEach((event) => {
|
||||
page.getByText(event);
|
||||
});
|
||||
},
|
||||
rejectFirstBooking: async () => {
|
||||
await page.goto("/bookings/unconfirmed");
|
||||
await page.getByTestId("horizontal-tab-unconfirmed").click();
|
||||
await page.getByTestId("booking-item").first().getByText("Reject").click();
|
||||
await page.getByTestId("rejection-confirm").click();
|
||||
},
|
||||
fillEmailAndName: async (eventTypePage: Page) => {
|
||||
const emailLabel = (await localize("en"))("email_address");
|
||||
const nameLabel = (await localize("en"))("your_name");
|
||||
|
||||
await eventTypePage.getByLabel(emailLabel).fill(EMAIL);
|
||||
await eventTypePage.getByLabel(nameLabel).fill("testuser");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { test as base } from "@playwright/test";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import type { ExpectedUrlDetails } from "../../../../playwright.config";
|
||||
import { createAppsFixture } from "../fixtures/apps";
|
||||
import { createBookingsFixture } from "../fixtures/bookings";
|
||||
import { createEmailsFixture } from "../fixtures/emails";
|
||||
import { createEmbedsFixture } from "../fixtures/embeds";
|
||||
@@ -32,6 +33,7 @@ export interface Fixtures {
|
||||
workflowPage: ReturnType<typeof createWorkflowPageFixture>;
|
||||
features: ReturnType<typeof createFeatureFixture>;
|
||||
eventTypePage: ReturnType<typeof createEventTypeFixture>;
|
||||
appsPage: ReturnType<typeof createAppsFixture>;
|
||||
}
|
||||
|
||||
declare global {
|
||||
@@ -104,4 +106,8 @@ export const test = base.extend<Fixtures>({
|
||||
const eventTypePage = createEventTypeFixture(page);
|
||||
await use(eventTypePage);
|
||||
},
|
||||
appsPage: async ({ page }, use) => {
|
||||
const appsPage = createAppsFixture(page);
|
||||
await use(appsPage);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ test.describe("Update Profile", () => {
|
||||
|
||||
await page.getByTestId("profile-update-email-submit-button").click();
|
||||
|
||||
const toastLocator = await page.waitForSelector('[data-testId="toast-success"]');
|
||||
const toastLocator = await page.getByTestId("toast-success");
|
||||
|
||||
const textContent = await toastLocator.textContent();
|
||||
|
||||
@@ -84,7 +84,7 @@ test.describe("Update Profile", () => {
|
||||
|
||||
await page.goto(verifyUrl);
|
||||
|
||||
const errorLocator = await page.waitForSelector('[data-testId="toast-error"]');
|
||||
const errorLocator = await page.getByTestId("toast-error");
|
||||
|
||||
expect(errorLocator).toBeDefined();
|
||||
|
||||
@@ -118,11 +118,7 @@ test.describe("Update Profile", () => {
|
||||
|
||||
await page.getByTestId("profile-update-email-submit-button").click();
|
||||
|
||||
const toastLocator = await page.waitForSelector('[data-testId="toast-success"]');
|
||||
|
||||
const textContent = await toastLocator.textContent();
|
||||
|
||||
expect(textContent).toContain(email);
|
||||
expect(await page.getByTestId("toast-success").textContent()).toContain(email);
|
||||
|
||||
// Instead of dealing with emails in e2e lets just get the token and navigate to it
|
||||
const verificationToken = await prisma.verificationToken.findFirst({
|
||||
@@ -140,9 +136,7 @@ test.describe("Update Profile", () => {
|
||||
|
||||
await page.goto(verifyUrl);
|
||||
|
||||
const successLocator = await page.waitForSelector('[data-testId="toast-success"]');
|
||||
|
||||
expect(await successLocator.textContent()).toContain(email);
|
||||
expect(await page.getByTestId("toast-success").textContent()).toContain(email);
|
||||
|
||||
// After email verification is successfull. user is sent to /event-types
|
||||
await page.waitForURL("/event-types");
|
||||
@@ -176,9 +170,7 @@ test.describe("Update Profile", () => {
|
||||
|
||||
await page.getByTestId("profile-update-email-submit-button").click();
|
||||
|
||||
const toastLocator = await page.waitForSelector('[data-testId="toast-success"]');
|
||||
|
||||
expect(await toastLocator.isVisible()).toBe(true);
|
||||
expect(await page.getByTestId("toast-success").isVisible()).toBe(true);
|
||||
|
||||
const emailInputUpdated = page.getByTestId("profile-form-email");
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"identity_provider": "Azonosítás szolgáltató",
|
||||
"trial_days_left": "Még $t(day, {\"count\": {{days}} }) maradt a PRO próbaidőszakodból",
|
||||
"day_one": "{{count}} nap",
|
||||
"day_other": "{{count}} nap",
|
||||
@@ -7,6 +8,7 @@
|
||||
"upgrade_now": "Frissíts most",
|
||||
"accept_invitation": "Meghívó elfogadása",
|
||||
"have_any_questions": "Van kérdésed? Itt vagyunk hogy segítsünk.",
|
||||
"verify_email_email_button": "Email igazolása",
|
||||
"organizer": "Szervező",
|
||||
"rejection_reason": "Lemondás oka",
|
||||
"help": "Segítség",
|
||||
@@ -160,7 +162,7 @@
|
||||
"yearly_one": "év",
|
||||
"yearly_other": "év",
|
||||
"name": "Név",
|
||||
"logo": "Logo",
|
||||
"logo": "Logó",
|
||||
"error": "Hiba",
|
||||
"type": "Típus",
|
||||
"edit": "Szerkesztés",
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"reset_password_subject": "{{appName}}: інструкції зі скидання пароля",
|
||||
"verify_email_subject": "{{appName}}: підтвердьте свій обліковий запис",
|
||||
"check_your_email": "Перевірте свою електронну пошту",
|
||||
"old_email_address": "Стара адреса електронної пошти",
|
||||
"new_email_address": "Нова адреса електронної пошти",
|
||||
"verify_email_page_body": "Ми надіслали лист на адресу {{email}}. Підтвердьте свою електронну адресу, щоб уникнути проблем із доставкою листів і даних календаря із застосунку {{appName}}.",
|
||||
"verify_email_banner_body": "Підтвердьте свою електронну адресу, щоб уникнути проблем із доставкою листів і даних календаря",
|
||||
"verify_email_email_header": "Підтвердьте свою електронну адресу",
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Only deploy to production
|
||||
if [ "$VERCEL_ENV" != "production" ]; then exit 0; fi
|
||||
|
||||
checkRoute () {
|
||||
if [ "$1" != '1' ]; then rm -rf $2; fi
|
||||
}
|
||||
|
||||
# These conditionals are used to remove directories from the build that are not needed in production
|
||||
# This is to reduce the size of the build and prevent OOM errors
|
||||
checkRoute "$APP_ROUTER_EVENT_TYPES_ENABLED" app/future/event-types
|
||||
checkRoute "$APP_ROUTER_SETTINGS_ADMIN_ENABLED" app/future/settings/admin
|
||||
checkRoute "$APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED" app/future/apps/installed
|
||||
checkRoute "$APP_ROUTER_APPS_SLUG_ENABLED" app/future/apps/\[slug\]
|
||||
checkRoute "$APP_ROUTER_APPS_SLUG_SETUP_ENABLED" app/future/apps/\[slug\]/setup
|
||||
checkRoute "$APP_ROUTER_APPS_CATEGORIES_ENABLED" app/future/apps/categories
|
||||
checkRoute "$APP_ROUTER_APPS_CATEGORIES_CATEGORY_ENABLED" app/future/apps/categories/\[category\]
|
||||
checkRoute "$APP_ROUTER_WORKFLOWS_ENABLED" app/future/workflows
|
||||
checkRoute "$APP_ROUTER_SETTINGS_TEAMS_ENABLED" app/future/settings/teams
|
||||
checkRoute "$APP_ROUTER_GETTING_STARTED_STEP_ENABLED" app/future/getting-started
|
||||
checkRoute "$APP_ROUTER_APPS_ENABLED" app/future/apps
|
||||
checkRoute "$APP_ROUTER_BOOKINGS_STATUS_ENABLED" app/future/bookings
|
||||
checkRoute "$APP_ROUTER_VIDEO_ENABLED" app/future/video
|
||||
checkRoute "$APP_ROUTER_TEAMS_ENABLED" app/future/teams
|
||||
|
||||
# These are routes that don't have and environment variable to enable or disable them
|
||||
# Will stop removing gradually as we test and confirm that they are working
|
||||
rm -rf \
|
||||
app/future/[user]\
|
||||
app/future/auth\
|
||||
app/future/booking\
|
||||
app/future/connect-and-join\
|
||||
app/future/d\
|
||||
app/future/enterprise\
|
||||
app/future/insights\
|
||||
app/future/maintenance\
|
||||
app/future/more\
|
||||
app/future/org\
|
||||
app/future/payment\
|
||||
app/future/reschedule\
|
||||
app/future/routing-forms\
|
||||
app/future/settings\
|
||||
app/future/signup\
|
||||
app/future/team
|
||||
|
||||
exit 1
|
||||
@@ -14,6 +14,7 @@ import closecom_config_json from "./closecom/config.json";
|
||||
import cron_config_json from "./cron/config.json";
|
||||
import { metadata as dailyvideo__metadata_ts } from "./dailyvideo/_metadata";
|
||||
import deel_config_json from "./deel/config.json";
|
||||
import demodesk_config_json from "./demodesk/config.json";
|
||||
import discord_config_json from "./discord/config.json";
|
||||
import eightxeight_config_json from "./eightxeight/config.json";
|
||||
import element_call_config_json from "./element-call/config.json";
|
||||
@@ -97,6 +98,7 @@ export const appStoreMetadata = {
|
||||
cron: cron_config_json,
|
||||
dailyvideo: dailyvideo__metadata_ts,
|
||||
deel: deel_config_json,
|
||||
demodesk: demodesk_config_json,
|
||||
discord: discord_config_json,
|
||||
eightxeight: eightxeight_config_json,
|
||||
"element-call": element_call_config_json,
|
||||
|
||||
@@ -14,6 +14,7 @@ export const apiHandlers = {
|
||||
closecom: import("./closecom/api"),
|
||||
cron: import("./cron/api"),
|
||||
deel: import("./deel/api"),
|
||||
demodesk: import("./demodesk/api"),
|
||||
discord: import("./discord/api"),
|
||||
eightxeight: import("./eightxeight/api"),
|
||||
"element-call": import("./element-call/api"),
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import around_config_json from "./around/config.json";
|
||||
import campfire_config_json from "./campfire/config.json";
|
||||
import { metadata as dailyvideo__metadata_ts } from "./dailyvideo/_metadata";
|
||||
import demodesk_config_json from "./demodesk/config.json";
|
||||
import discord_config_json from "./discord/config.json";
|
||||
import eightxeight_config_json from "./eightxeight/config.json";
|
||||
import element_call_config_json from "./element-call/config.json";
|
||||
@@ -41,6 +42,7 @@ export const appStoreMetadata = {
|
||||
around: around_config_json,
|
||||
campfire: campfire_config_json,
|
||||
dailyvideo: dailyvideo__metadata_ts,
|
||||
demodesk: demodesk_config_json,
|
||||
discord: discord_config_json,
|
||||
eightxeight: eightxeight_config_json,
|
||||
"element-call": element_call_config_json,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
items:
|
||||
- iframe: { src: https://www.youtube.com/embed/X6XVzJ0E8xY }
|
||||
- 1.jpeg
|
||||
- 2.webp
|
||||
- 3.webp
|
||||
- 4.webp
|
||||
---
|
||||
|
||||
{DESCRIPTION}
|
||||
|
||||
### AI superpowers for your sales meetings
|
||||
|
||||
#### Coach and onboard sellers with AI-based insights
|
||||
- Automatically record all meetings, GDPR & MiFID compliant
|
||||
- Transcribe and summarize meetings using Demodesk’s AI
|
||||
- Coach teams along conversational metrics and scorecards
|
||||
- Automatically log key information into your CRM
|
||||
|
||||
#### Schedule more customer meetings, on auto-pilot
|
||||
- Let customers schedule time without email back-and-forth
|
||||
- Qualify website leads and route them to the right person
|
||||
- Automate and control handoff processes in your team
|
||||
- Automate admin work and sync interactions to your CRM
|
||||
|
||||
#### Run secure video meetings that convert into revenue
|
||||
- Host professional, secure video meetings without downloads
|
||||
- Engage customers with interactive screen sharing
|
||||
- Coach sellers in real-time along standardized playbooks
|
||||
- Automate preparation, follow-up and CRM documentation
|
||||
@@ -0,0 +1,16 @@
|
||||
import { createDefaultInstallation } from "@calcom/app-store/_utils/installation";
|
||||
import type { AppDeclarativeHandler } from "@calcom/types/AppHandler";
|
||||
|
||||
import appConfig from "../config.json";
|
||||
|
||||
const handler: AppDeclarativeHandler = {
|
||||
appType: appConfig.type,
|
||||
variant: appConfig.variant,
|
||||
slug: appConfig.slug,
|
||||
supportsMultipleInstalls: false,
|
||||
handlerType: "add",
|
||||
createCredential: ({ appType, user, slug, teamId }) =>
|
||||
createDefaultInstallation({ appType, user: user, slug, key: {}, teamId }),
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as add } from "./add";
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"/*": "Don't modify slug - If required, do it using cli edit command",
|
||||
"name": "Demodesk",
|
||||
"slug": "demodesk",
|
||||
"type": "demodesk_conferencing",
|
||||
"logo": "icon.svg",
|
||||
"url": "https://demodesk.com",
|
||||
"variant": "conferencing",
|
||||
"categories": ["conferencing"],
|
||||
"publisher": "Cal.com, Inc.",
|
||||
"email": "support@cal.com",
|
||||
"appData": {
|
||||
"location": {
|
||||
"type": "integrations:{SLUG}_video",
|
||||
"label": "{TITLE}",
|
||||
"linkType": "static",
|
||||
"organizerInputPlaceholder": "https://demodesk.com/meet/mylink",
|
||||
"urlRegExp": "^http(s)?:\\/\\/(www\\.)?demodesk.com\\/[a-zA-Z0-9]*"
|
||||
}
|
||||
},
|
||||
"description": "Run Professional Video Meetings, Coach Sales Teams in Real-Time with AI, And Schedule Meetings on Auto-Pilot. 100% GDPR Compliant, Enterprise Ready.",
|
||||
"isTemplate": false,
|
||||
"__createdUsingCli": true,
|
||||
"__template": "event-type-location-video-static"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * as api from "./api";
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"name": "@calcom/demodesk",
|
||||
"version": "0.0.1",
|
||||
"main": "./index.ts",
|
||||
"dependencies": {
|
||||
"@calcom/lib": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@calcom/types": "*"
|
||||
},
|
||||
"description": "Run Professional Video Meetings, Coach Sales Teams in Real-Time with AI, And Schedule Meetings on Auto-Pilot. 100% GDPR Compliant, Enterprise Ready."
|
||||
}
|
||||
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 425 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="2484" height="2484" viewBox="0 0 2484 2484" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="2484" height="2484" rx="200" fill="#DDDDDD"/>
|
||||
<path d="M1126.24 514.004H687.083C663.823 514.004 645 532.827 645 556.088V656.4C645 679.661 663.823 698.484 687.083 698.484H1109.75C1451.81 698.484 1699.98 941.881 1699.98 1241.1C1699.98 1365.7 1657.75 1480.59 1586.85 1572.29C1599.97 1525.62 1607.02 1476.42 1607.02 1425.58C1607.02 1126.36 1418.26 882.963 1025.89 882.963H687.083C663.823 882.963 645 901.786 645 925.047V1025.36C645 1048.62 663.823 1067.44 687.083 1067.44H1019.19C1270.01 1068.59 1412.48 1228.09 1412.48 1425.58C1412.48 1623.06 1270.01 1783.75 1019.19 1783.75H850.096V1294.04C850.096 1270.79 831.274 1251.96 808.014 1251.96H687.083C663.823 1251.96 645 1270.79 645 1294.04V1926.15C645 1949.4 663.823 1968.23 687.083 1968.23H1064.45H1064.53H1126.28C1579.28 1968.23 1894.59 1642.04 1894.59 1241.13C1894.59 840.229 1607.05 512.703 1126.24 514.004Z" fill="#2B2D28"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 998 B |
@@ -21,6 +21,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
switchChecked={enabled}
|
||||
teamId={eventType.team?.id || undefined}>
|
||||
<TextField
|
||||
dataTestid={app.slug}
|
||||
name="Tracking ID"
|
||||
value={trackingId}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -21,6 +21,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
switchChecked={enabled}
|
||||
teamId={eventType.team?.id || undefined}>
|
||||
<TextField
|
||||
dataTestid={app.slug}
|
||||
name="Tracking ID"
|
||||
value={trackingId}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -264,6 +264,7 @@ export default class GoogleCalendarService implements Calendar {
|
||||
calendarId: selectedCalendar,
|
||||
eventId: event.id || "",
|
||||
requestBody: {
|
||||
location: getLocation(calEventRaw),
|
||||
description: getRichDescription({
|
||||
...calEventRaw,
|
||||
}),
|
||||
|
||||
@@ -21,6 +21,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
switchChecked={enabled}
|
||||
teamId={eventType.team?.id || undefined}>
|
||||
<TextField
|
||||
dataTestid={app.slug}
|
||||
name="Tracking ID"
|
||||
value={trackingId}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "ICS Feed",
|
||||
"title": "ICS Feed",
|
||||
"slug": "ics-feed",
|
||||
"dirName":"ics-feedcalendar",
|
||||
"type": "ics-feed_calendar",
|
||||
"logo": "icon.svg",
|
||||
"variant": "calendar",
|
||||
|
||||
@@ -23,6 +23,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
teamId={eventType.team?.id || undefined}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<TextField
|
||||
dataTestid={`${app.slug}-url`}
|
||||
name="Matomo URL"
|
||||
placeholder="Enter your Matomo URL here"
|
||||
value={matomoUrl}
|
||||
@@ -32,6 +33,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
dataTestid={`${app.slug}-site-id`}
|
||||
disabled={disabled}
|
||||
name="Site ID"
|
||||
placeholder="Enter your Site ID"
|
||||
|
||||
@@ -19,6 +19,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
switchChecked={enabled}
|
||||
teamId={eventType.team?.id || undefined}>
|
||||
<TextField
|
||||
dataTestid={app.slug}
|
||||
name="Pixel ID"
|
||||
value={trackingId}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -23,6 +23,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
teamId={eventType.team?.id || undefined}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<TextField
|
||||
dataTestid={`${app.slug}-url`}
|
||||
name="Plausible URL"
|
||||
defaultValue="https://plausible.io/js/script.js"
|
||||
placeholder="https://plausible.io/js/script.js"
|
||||
@@ -33,6 +34,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
dataTestid={`${app.slug}-tracking-id`}
|
||||
disabled={disabled}
|
||||
name="Tracked Domain"
|
||||
placeholder="yourdomain.com"
|
||||
|
||||
@@ -22,7 +22,7 @@ const zeroDecimalCurrencies = [
|
||||
|
||||
export const convertToSmallestCurrencyUnit = (amount: number, currency: string) => {
|
||||
// Special cases
|
||||
if (zeroDecimalCurrencies.includes(currency)) {
|
||||
if (zeroDecimalCurrencies.includes(currency.toUpperCase())) {
|
||||
return amount;
|
||||
}
|
||||
return Math.round(amount * 100);
|
||||
@@ -30,7 +30,7 @@ export const convertToSmallestCurrencyUnit = (amount: number, currency: string)
|
||||
|
||||
export const convertFromSmallestToPresentableCurrencyUnit = (amount: number, currency: string) => {
|
||||
// Special cases
|
||||
if (zeroDecimalCurrencies.includes(currency)) {
|
||||
if (zeroDecimalCurrencies.includes(currency.toUpperCase())) {
|
||||
return amount;
|
||||
}
|
||||
return amount / 100;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
export const sanitizeDisplayName = (nameAndEmail: string) => {
|
||||
const match = nameAndEmail.match(/^(.*?)\s<(.*)>$/);
|
||||
|
||||
if (match) {
|
||||
const sanitizedName = sanitize(match[1]);
|
||||
return `${sanitizedName} <${match[2]}>`;
|
||||
}
|
||||
|
||||
return nameAndEmail;
|
||||
};
|
||||
|
||||
const sanitize = (name: string) => {
|
||||
const charsToReplace = /[;,"<>()]/g;
|
||||
|
||||
return name.replace(charsToReplace, " ");
|
||||
};
|
||||
@@ -9,6 +9,8 @@ import { serverConfig } from "@calcom/lib/serverConfig";
|
||||
import { setTestEmail } from "@calcom/lib/testEmails";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { sanitizeDisplayName } from "../lib/sanitizeDisplayName";
|
||||
|
||||
export default class BaseEmail {
|
||||
name = "";
|
||||
|
||||
@@ -46,10 +48,21 @@ export default class BaseEmail {
|
||||
}
|
||||
|
||||
const payload = await this.getNodeMailerPayload();
|
||||
|
||||
const from = "from" in payload ? (payload.from as string) : "";
|
||||
const to = "to" in payload ? (payload.to as string) : "";
|
||||
|
||||
const sanitizedFrom = sanitizeDisplayName(from);
|
||||
const sanitizedTo = sanitizeDisplayName(to);
|
||||
|
||||
const parseSubject = z.string().safeParse(payload?.subject);
|
||||
const payloadWithUnEscapedSubject = {
|
||||
headers: this.getMailerOptions().headers,
|
||||
...payload,
|
||||
...{
|
||||
from: sanitizedFrom,
|
||||
to: sanitizedTo,
|
||||
},
|
||||
...(parseSubject.success && { subject: decodeHTML(parseSubject.data) }),
|
||||
};
|
||||
await new Promise((resolve, reject) =>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { TFunction } from "next-i18next";
|
||||
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
|
||||
import { renderEmail } from "..";
|
||||
import BaseEmail from "./_base-email";
|
||||
|
||||
@@ -30,7 +32,7 @@ export default class DisabledAppEmail extends BaseEmail {
|
||||
|
||||
protected async getNodeMailerPayload(): Promise<Record<string, unknown>> {
|
||||
return {
|
||||
from: `Cal.com <${this.getMailerOptions().from}>`,
|
||||
from: `${APP_NAME} <${this.getMailerOptions().from}>`,
|
||||
to: this.email,
|
||||
subject:
|
||||
this.title && this.eventTypeId
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { TFunction } from "next-i18next";
|
||||
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
|
||||
import { renderEmail } from "..";
|
||||
import BaseEmail from "./_base-email";
|
||||
|
||||
@@ -21,7 +23,7 @@ export default class SlugReplacementEmail extends BaseEmail {
|
||||
|
||||
protected async getNodeMailerPayload(): Promise<Record<string, unknown>> {
|
||||
return {
|
||||
from: `Cal.com <${this.getMailerOptions().from}>`,
|
||||
from: `${APP_NAME} <${this.getMailerOptions().from}>`,
|
||||
to: this.email,
|
||||
subject: this.t("email_subject_slug_replacement", { slug: this.slug }),
|
||||
html: await renderEmail("SlugReplacementEmail", {
|
||||
|
||||
@@ -123,7 +123,8 @@ const BookerComponent = ({
|
||||
|
||||
const { bookerFormErrorRef, key, formEmail, bookingForm, errors: formErrors } = bookerForm;
|
||||
|
||||
const { handleBookEvent, hasInstantMeetingTokenExpired, errors, loadingStates, expiryTime } = bookings;
|
||||
const { handleBookEvent, errors, loadingStates, expiryTime } = bookings;
|
||||
|
||||
const {
|
||||
isEmailVerificationModalVisible,
|
||||
setEmailVerificationModalVisible,
|
||||
@@ -180,7 +181,6 @@ const BookerComponent = ({
|
||||
/>
|
||||
<RedirectToInstantMeetingModal
|
||||
expiryTime={expiryTime}
|
||||
hasInstantMeetingTokenExpired={hasInstantMeetingTokenExpired}
|
||||
bookingId={parseInt(getQueryParam("bookingId") || "0")}
|
||||
onGoBack={() => {
|
||||
onGoBackInstantMeeting();
|
||||
@@ -203,7 +203,6 @@ const BookerComponent = ({
|
||||
formErrors,
|
||||
handleBookEvent,
|
||||
handleVerifyEmail,
|
||||
hasInstantMeetingTokenExpired,
|
||||
isEmailVerificationModalVisible,
|
||||
key,
|
||||
loadingStates,
|
||||
|
||||
@@ -55,13 +55,6 @@ export function Header({
|
||||
|
||||
if (isMobile || !enabledLayouts) return null;
|
||||
|
||||
// Only reason we create this component, is because it is used 3 times in this component,
|
||||
// and this way we can't forget to update one of the props in all places :)
|
||||
const LayoutToggleWithData = () => {
|
||||
return enabledLayouts.length <= 1 ? null : (
|
||||
<LayoutToggle onLayoutToggle={onLayoutToggle} layout={layout} enabledLayouts={enabledLayouts} />
|
||||
);
|
||||
};
|
||||
// In month view we only show the layout toggle.
|
||||
if (isMonthView) {
|
||||
return (
|
||||
@@ -78,7 +71,11 @@ export function Header({
|
||||
) : (
|
||||
renderOverlay?.()
|
||||
)}
|
||||
<LayoutToggleWithData />
|
||||
<LayoutToggleWithData
|
||||
layout={layout}
|
||||
enabledLayouts={enabledLayouts}
|
||||
onLayoutToggle={onLayoutToggle}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -140,7 +137,11 @@ export function Header({
|
||||
{renderOverlay?.()}
|
||||
<TimeFormatToggle />
|
||||
<div className="fixed top-4 ltr:right-4 rtl:left-4">
|
||||
<LayoutToggleWithData />
|
||||
<LayoutToggleWithData
|
||||
layout={layout}
|
||||
enabledLayouts={enabledLayouts}
|
||||
onLayoutToggle={onLayoutToggle}
|
||||
/>
|
||||
</div>
|
||||
{/*
|
||||
This second layout toggle is hidden, but needed to reserve the correct spot in the DIV
|
||||
@@ -150,7 +151,11 @@ export function Header({
|
||||
while it actually already was on place. That's why we have this element twice.
|
||||
*/}
|
||||
<div className="pointer-events-none opacity-0" aria-hidden>
|
||||
<LayoutToggleWithData />
|
||||
<LayoutToggleWithData
|
||||
layout={layout}
|
||||
enabledLayouts={enabledLayouts}
|
||||
onLayoutToggle={onLayoutToggle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,3 +203,17 @@ const LayoutToggle = ({
|
||||
|
||||
return <ToggleGroup onValueChange={onLayoutToggle} defaultValue={layout} options={layoutOptions} />;
|
||||
};
|
||||
|
||||
const LayoutToggleWithData = ({
|
||||
enabledLayouts,
|
||||
onLayoutToggle,
|
||||
layout,
|
||||
}: {
|
||||
enabledLayouts: BookerLayouts[];
|
||||
onLayoutToggle: (layout: string) => void;
|
||||
layout: string;
|
||||
}) => {
|
||||
return enabledLayouts.length <= 1 ? null : (
|
||||
<LayoutToggle onLayoutToggle={onLayoutToggle} layout={layout} enabledLayouts={enabledLayouts} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,18 +12,17 @@ const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
||||
};
|
||||
|
||||
export const RedirectToInstantMeetingModal = ({
|
||||
hasInstantMeetingTokenExpired,
|
||||
bookingId,
|
||||
onGoBack,
|
||||
expiryTime,
|
||||
}: {
|
||||
hasInstantMeetingTokenExpired: boolean;
|
||||
bookingId: number;
|
||||
onGoBack: () => void;
|
||||
expiryTime?: Date;
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
const [timeRemaining, setTimeRemaining] = useState(calculateTimeRemaining());
|
||||
const [hasInstantMeetingTokenExpired, setHasInstantMeetingTokenExpired] = useState(false);
|
||||
|
||||
function calculateTimeRemaining() {
|
||||
const now = dayjs();
|
||||
@@ -37,6 +36,7 @@ export const RedirectToInstantMeetingModal = ({
|
||||
|
||||
const timer = setInterval(() => {
|
||||
setTimeRemaining(calculateTimeRemaining());
|
||||
setHasInstantMeetingTokenExpired(expiryTime && new Date(expiryTime) < new Date());
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -56,7 +56,7 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata }: IUseBo
|
||||
const { t, i18n } = useLocale();
|
||||
const bookingSuccessRedirect = useBookingSuccessRedirect();
|
||||
const bookerFormErrorRef = useRef<HTMLDivElement>(null);
|
||||
const [expiryTime, setExpiryTime] = useState<Date | undefined>();
|
||||
const [instantMeetingTokenExpiryTime, setExpiryTime] = useState<Date | undefined>();
|
||||
const recurringEventCount = useBookerStore((state) => state.recurringEventCount);
|
||||
const isInstantMeeting = useBookerStore((state) => state.isInstantMeeting);
|
||||
const duration = useBookerStore((state) => state.selectedDuration);
|
||||
@@ -66,13 +66,13 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata }: IUseBo
|
||||
const isRescheduling = !!rescheduleUid && !!bookingData;
|
||||
|
||||
const bookingId = parseInt(getQueryParam("bookingId") || "0");
|
||||
const hasInstantMeetingTokenExpired = expiryTime && new Date(expiryTime) < new Date();
|
||||
|
||||
const _instantBooking = trpc.viewer.bookings.getInstantBookingLocation.useQuery(
|
||||
{
|
||||
bookingId: bookingId,
|
||||
},
|
||||
{
|
||||
enabled: !!bookingId && !hasInstantMeetingTokenExpired,
|
||||
enabled: !!bookingId,
|
||||
refetchInterval: 2000,
|
||||
refetchIntervalInBackground: true,
|
||||
}
|
||||
@@ -80,6 +80,7 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata }: IUseBo
|
||||
useEffect(
|
||||
function refactorMeWithoutEffect() {
|
||||
const data = _instantBooking.data;
|
||||
|
||||
if (!data) return;
|
||||
try {
|
||||
showToast(t("something_went_wrong_on_our_end"), "error");
|
||||
@@ -301,11 +302,10 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata }: IUseBo
|
||||
|
||||
return {
|
||||
handleBookEvent,
|
||||
expiryTime,
|
||||
expiryTime: instantMeetingTokenExpiryTime,
|
||||
bookingForm,
|
||||
bookerFormErrorRef,
|
||||
errors,
|
||||
loadingStates,
|
||||
hasInstantMeetingTokenExpired: Boolean(hasInstantMeetingTokenExpired),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,5 +2,5 @@ import { classNames } from "@calcom/lib";
|
||||
|
||||
export function getBookerWrapperClasses({ isEmbed }: { isEmbed: boolean }) {
|
||||
// We don't want any margins for Embed. Any margin needed should be added by Embed user.
|
||||
return classNames("flex h-full items-center justify-center", !isEmbed && "min-h-[100dvh]");
|
||||
return classNames("flex h-full items-center justify-center", !isEmbed && "min-h-[calc(100dvh)]");
|
||||
}
|
||||
|
||||
@@ -1627,6 +1627,19 @@ async function handler(
|
||||
})
|
||||
);
|
||||
|
||||
// update original rescheduled booking (no seats event)
|
||||
if (!eventType.seatsPerTimeSlot && originalRescheduledBooking?.uid) {
|
||||
await prisma.booking.update({
|
||||
where: {
|
||||
id: originalRescheduledBooking.id,
|
||||
},
|
||||
data: {
|
||||
rescheduled: true,
|
||||
status: BookingStatus.CANCELLED,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
booking = await createBooking({
|
||||
originalRescheduledBooking,
|
||||
@@ -1694,7 +1707,7 @@ async function handler(
|
||||
err.message
|
||||
);
|
||||
if (err.code === "P2002") {
|
||||
throw new HttpError({ statusCode: 409, message: "booking.conflict" });
|
||||
throw new HttpError({ statusCode: 409, message: "booking_conflict" });
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@@ -1720,20 +1733,7 @@ async function handler(
|
||||
|
||||
evt = addVideoCallDataToEvent(originalRescheduledBooking.references, evt);
|
||||
|
||||
//update original rescheduled booking (no seats event)
|
||||
if (!eventType.seatsPerTimeSlot) {
|
||||
await prisma.booking.update({
|
||||
where: {
|
||||
id: originalRescheduledBooking.id,
|
||||
},
|
||||
data: {
|
||||
rescheduled: true,
|
||||
status: BookingStatus.CANCELLED,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const newDesinationCalendar = evt.destinationCalendar;
|
||||
const newDestinationCalendar = evt.destinationCalendar;
|
||||
|
||||
evt.destinationCalendar = originalRescheduledBooking?.destinationCalendar
|
||||
? [originalRescheduledBooking?.destinationCalendar]
|
||||
@@ -1752,7 +1752,7 @@ async function handler(
|
||||
originalRescheduledBooking.uid,
|
||||
undefined,
|
||||
changedOrganizer,
|
||||
newDesinationCalendar
|
||||
newDestinationCalendar
|
||||
);
|
||||
|
||||
// This gets overridden when updating the event - to check if notes have been hidden or not. We just reset this back
|
||||
@@ -2291,8 +2291,7 @@ async function handler(
|
||||
loggerWithEventDetails.error("Error while creating booking references", JSON.stringify({ error }));
|
||||
}
|
||||
|
||||
const metadataFromEvent = videoCallUrl ? { videoCallUrl } : undefined;
|
||||
const evtWithMetadata = { ...evt, metadata: metadataFromEvent, eventType: { slug: eventType.slug } };
|
||||
const evtWithMetadata = { ...evt, metadata, eventType: { slug: eventType.slug } };
|
||||
|
||||
await scheduleMandatoryReminder(
|
||||
evtWithMetadata,
|
||||
|
||||
@@ -111,7 +111,7 @@ export function EventList({ day }: Props) {
|
||||
<div
|
||||
key={`${event.id}-${eventStart.toISOString()}`}
|
||||
className="absolute inset-x-1 "
|
||||
data-testId={event.options?.["data-test-id"]}
|
||||
data-testid={event.options?.["data-test-id"]}
|
||||
style={{
|
||||
marginLeft,
|
||||
zIndex,
|
||||
|
||||
@@ -198,6 +198,7 @@ async function isReturningToSelf({ session, creds }: { session: Session | null;
|
||||
role: true,
|
||||
organizationId: true,
|
||||
locale: true,
|
||||
profiles: true,
|
||||
teams: {
|
||||
where: {
|
||||
accepted: true, // Ensure they are apart of the team and not just invited.
|
||||
@@ -213,7 +214,10 @@ async function isReturningToSelf({ session, creds }: { session: Session | null;
|
||||
|
||||
if (returningUser) {
|
||||
// Skip for none org users
|
||||
if (returningUser.role !== "ADMIN" && !returningUser.organizationId) return;
|
||||
const inOrg =
|
||||
returningUser.organizationId || // Keep for backwards compatability
|
||||
returningUser.profiles.some((profile) => profile.organizationId !== undefined); // New way of seeing if the user has a profile in orgs.
|
||||
if (returningUser.role !== "ADMIN" && !inOrg) return;
|
||||
|
||||
const hasTeams = returningUser.teams.length >= 1;
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
switch (reminder.workflowStep.action) {
|
||||
case WorkflowActions.EMAIL_HOST:
|
||||
sendTo = reminder.booking.user?.email;
|
||||
sendTo = reminder.booking?.userPrimaryEmail ?? reminder.booking.user?.email;
|
||||
break;
|
||||
case WorkflowActions.EMAIL_ATTENDEE:
|
||||
sendTo = reminder.booking.attendees[0].email;
|
||||
@@ -227,7 +227,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
html: emailContent.emailBody,
|
||||
batchId: batchId,
|
||||
sendAt: dayjs(reminder.scheduledDate).unix(),
|
||||
replyTo: reminder.booking.user?.email,
|
||||
replyTo: reminder.booking?.userPrimaryEmail ?? reminder.booking.user?.email,
|
||||
attachments: reminder.workflowStep.includeCalendarEvent
|
||||
? [
|
||||
{
|
||||
@@ -297,7 +297,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
html: emailContent.emailBody,
|
||||
batchId: batchId,
|
||||
sendAt: dayjs(reminder.scheduledDate).unix(),
|
||||
replyTo: reminder.booking.user?.email,
|
||||
replyTo: reminder.booking?.userPrimaryEmail ?? reminder.booking.user?.email,
|
||||
},
|
||||
{ sender: reminder.workflowStep?.sender }
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ type PartialBooking =
|
||||
| "responses"
|
||||
| "uid"
|
||||
| "attendees"
|
||||
| "userPrimaryEmail"
|
||||
> & { eventType: Partial<EventType> | null } & { user: Partial<User> | null })
|
||||
| null;
|
||||
|
||||
@@ -134,6 +135,7 @@ export async function getAllUnscheduledReminders(): Promise<PartialWorkflowRemin
|
||||
endTime: true,
|
||||
location: true,
|
||||
description: true,
|
||||
userPrimaryEmail: true,
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { DateArray } from "ics";
|
||||
import { RRule } from "rrule";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { guessEventLocationType } from "@calcom/app-store/locations";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { preprocessNameFieldDataWithVariant } from "@calcom/features/form-builder/utils";
|
||||
import logger from "@calcom/lib/logger";
|
||||
@@ -33,6 +34,12 @@ function getiCalEventAsString(evt: BookingInfo, status?: ParticipationStatus) {
|
||||
recurrenceRule = new RRule(evt.eventType.recurringEvent).toString().replace("RRULE:", "");
|
||||
}
|
||||
|
||||
let location = bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl;
|
||||
|
||||
if (!location) {
|
||||
location = guessEventLocationType(location)?.label || evt.location || "";
|
||||
}
|
||||
|
||||
const icsEvent = createEvent({
|
||||
uid,
|
||||
startInputType: "utc",
|
||||
@@ -44,7 +51,7 @@ function getiCalEventAsString(evt: BookingInfo, status?: ParticipationStatus) {
|
||||
duration: { minutes: dayjs(evt.endTime).diff(dayjs(evt.startTime), "minute") },
|
||||
title: evt.title,
|
||||
description: evt.additionalNotes || "",
|
||||
location: evt.location || "",
|
||||
location,
|
||||
organizer: { email: evt.organizer.email || "", name: evt.organizer.name },
|
||||
attendees: [
|
||||
{
|
||||
|
||||
@@ -462,8 +462,10 @@ function UserDropdown({ small }: UserDropdownProps) {
|
||||
</span>
|
||||
{!small && (
|
||||
<span className="flex flex-grow items-center gap-2">
|
||||
<span className="line-clamp-1 flex-grow text-sm leading-none">
|
||||
<span className="text-emphasis block font-medium">{user.name || "Nameless User"}</span>
|
||||
<span className="w-24 flex-shrink-0 text-sm leading-none">
|
||||
<span className="text-emphasis block truncate font-medium">
|
||||
{user.name || "Nameless User"}
|
||||
</span>
|
||||
</span>
|
||||
<ChevronDown
|
||||
className="group-hover:text-subtle text-muted h-4 w-4 flex-shrink-0 rtl:mr-4"
|
||||
@@ -729,6 +731,7 @@ const NavigationItem: React.FC<{
|
||||
<Fragment>
|
||||
<Tooltip side="right" content={t(item.name)} className="lg:hidden">
|
||||
<Link
|
||||
data-test-id={item.name}
|
||||
href={item.href}
|
||||
aria-label={t(item.name)}
|
||||
className={classNames(
|
||||
|
||||
@@ -83,7 +83,7 @@ export const SEO_IMG_DEFAULT = `${CAL_URL}/og-image.png`;
|
||||
// parameters you pass to the /api/social/og/image endpoint, you wrap them in encodeURIComponent
|
||||
// as well, otherwise the URL won't be valid.
|
||||
export const SEO_IMG_OGIMG = `${CAL_URL}/_next/image?w=1200&q=100&url=${encodeURIComponent(
|
||||
`${CAL_URL}/api/social/og/image`
|
||||
`/api/social/og/image`
|
||||
)}`;
|
||||
export const SEO_IMG_OGIMG_VIDEO = `${CAL_URL}/video-og-image.png`;
|
||||
export const IS_STRIPE_ENABLED = !!(
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { convertFromSmallestToPresentableCurrencyUnit } from "@calcom/app-store/stripepayment/lib/currencyConversions";
|
||||
|
||||
export const formatPrice = (price: number, currency: string | undefined, locale = "en") => {
|
||||
switch (currency) {
|
||||
case "BTC":
|
||||
return `${price} sats`;
|
||||
default:
|
||||
currency = currency?.toUpperCase() || "USD";
|
||||
return `${Intl.NumberFormat(locale, {
|
||||
style: "currency",
|
||||
currency: currency?.toUpperCase() || "USD",
|
||||
}).format(price / 100.0)}`;
|
||||
currency: currency,
|
||||
}).format(convertFromSmallestToPresentableCurrencyUnit(price, currency))}`;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ export const buildBooking = (booking?: Partial<Booking>): Booking => {
|
||||
uid,
|
||||
userId: null,
|
||||
eventTypeId: null,
|
||||
idempotencyKey: null,
|
||||
userPrimaryEmail: null,
|
||||
title: faker.lorem.sentence(),
|
||||
description: faker.lorem.paragraph(),
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { v5 as uuidv5 } from "uuid";
|
||||
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
|
||||
export function bookingIdempotencyKeyExtension() {
|
||||
return Prisma.defineExtension({
|
||||
query: {
|
||||
booking: {
|
||||
async create({ args, query }) {
|
||||
const uniqueEmailJoinInput: string[] = [];
|
||||
if (args.data.attendees?.create && !Array.isArray(args.data.attendees?.create)) {
|
||||
uniqueEmailJoinInput.push(args.data.attendees?.create.email);
|
||||
}
|
||||
if (args.data.attendees?.createMany && Array.isArray(args.data.attendees?.createMany.data)) {
|
||||
uniqueEmailJoinInput.push(...args.data.attendees?.createMany.data.map((record) => record.email));
|
||||
}
|
||||
const idempotencyKey = uuidv5(
|
||||
`${
|
||||
args.data.eventType?.connect?.id
|
||||
}.${args.data.startTime.valueOf()}.${args.data.endTime.valueOf()}.${uniqueEmailJoinInput.join(
|
||||
","
|
||||
)}`,
|
||||
uuidv5.URL
|
||||
);
|
||||
args.data.idempotencyKey = idempotencyKey;
|
||||
return query(args);
|
||||
},
|
||||
async update({ args, query }) {
|
||||
if (args.data.status === BookingStatus.CANCELLED || args.data.status === BookingStatus.REJECTED) {
|
||||
args.data.idempotencyKey = null;
|
||||
}
|
||||
return query(args);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
|
||||
import { PrismaClient as PrismaClientWithoutExtension } from "@prisma/client";
|
||||
import { withAccelerate } from "@prisma/extension-accelerate";
|
||||
|
||||
import { bookingIdempotencyKeyExtension } from "./extensions/booking-idempotency-key";
|
||||
import { excludePendingPaymentsExtension } from "./extensions/exclude-pending-payment-teams";
|
||||
import { bookingReferenceMiddleware } from "./middleware";
|
||||
|
||||
@@ -21,6 +22,7 @@ const prismaWithoutClientExtensions =
|
||||
export const customPrisma = (options?: Prisma.PrismaClientOptions) =>
|
||||
new PrismaClientWithoutExtension({ ...prismaOptions, ...options })
|
||||
.$extends(excludePendingPaymentsExtension())
|
||||
.$extends(bookingIdempotencyKeyExtension())
|
||||
.$extends(withAccelerate());
|
||||
|
||||
// If any changed on middleware server restart is required
|
||||
@@ -31,6 +33,7 @@ bookingReferenceMiddleware(prismaWithoutClientExtensions);
|
||||
// Specifically we get errors like `Type 'string | Date | null | undefined' is not assignable to type 'Exact<string | Date | null | undefined, string | Date | null | undefined>'`
|
||||
const prismaWithClientExtensions = prismaWithoutClientExtensions
|
||||
.$extends(excludePendingPaymentsExtension())
|
||||
.$extends(bookingIdempotencyKeyExtension())
|
||||
.$extends(withAccelerate());
|
||||
|
||||
export const prisma = globalForPrisma.prismaWithClientExtensions || prismaWithClientExtensions;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[idempotencyKey]` on the table `Booking` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Booking" ADD COLUMN "idempotencyKey" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Booking_idempotencyKey_key" ON "Booking"("idempotencyKey");
|
||||
@@ -462,6 +462,8 @@ enum BookingStatus {
|
||||
model Booking {
|
||||
id Int @id @default(autoincrement())
|
||||
uid String @unique
|
||||
// (optional) UID based on slot start/end time & email against duplicates
|
||||
idempotencyKey String? @unique
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId Int?
|
||||
// User's email at the time of booking
|
||||
|
||||
@@ -38,13 +38,9 @@ export async function createUserAndEventType({
|
||||
appId: string;
|
||||
} | null)[];
|
||||
}) {
|
||||
const { password, ...restOfUser } = user;
|
||||
const userData = {
|
||||
...user,
|
||||
password: {
|
||||
create: {
|
||||
hash: await hashPassword(user.password),
|
||||
},
|
||||
},
|
||||
...restOfUser,
|
||||
emailVerified: new Date(),
|
||||
completedOnboarding: user.completedOnboarding ?? true,
|
||||
locale: "en",
|
||||
@@ -69,6 +65,21 @@ export async function createUserAndEventType({
|
||||
create: userData,
|
||||
});
|
||||
|
||||
await prisma.userPassword.upsert({
|
||||
where: { userId: theUser.id },
|
||||
update: {
|
||||
hash: await hashPassword(user.password),
|
||||
},
|
||||
create: {
|
||||
hash: await hashPassword(user.password),
|
||||
user: {
|
||||
connect: {
|
||||
id: theUser.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log(
|
||||
`👤 Upserted '${user.username}' with email "${user.email}" & password "${user.password}". Booking page 👉 ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}`
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@ import { performance } from "@calcom/lib/server/perfObserver";
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
import getSlots from "@calcom/lib/slots";
|
||||
import prisma, { availabilityUserSelect } from "@calcom/prisma";
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
||||
@@ -269,6 +270,31 @@ export function getRegularOrDynamicEventType(
|
||||
: getEventType(input, organizationDetails);
|
||||
}
|
||||
|
||||
const selectSelectedSlots = Prisma.validator<Prisma.SelectedSlotsDefaultArgs>()({
|
||||
select: {
|
||||
id: true,
|
||||
slotUtcStartDate: true,
|
||||
slotUtcEndDate: true,
|
||||
userId: true,
|
||||
isSeat: true,
|
||||
eventTypeId: true,
|
||||
},
|
||||
});
|
||||
|
||||
type SelectedSlots = Prisma.SelectedSlotsGetPayload<typeof selectSelectedSlots>;
|
||||
|
||||
function applyOccupiedSeatsToCurrentSeats(currentSeats: CurrentSeats, occupiedSeats: SelectedSlots[]) {
|
||||
const occupiedSeatsCount = countBy(occupiedSeats, (item) => item.slotUtcStartDate.toISOString());
|
||||
Object.keys(occupiedSeatsCount).forEach((date) => {
|
||||
currentSeats.push({
|
||||
uid: uuid(),
|
||||
startTime: dayjs(date).toDate(),
|
||||
_count: { attendees: occupiedSeatsCount[date] },
|
||||
});
|
||||
});
|
||||
return currentSeats;
|
||||
}
|
||||
|
||||
export async function getAvailableSlots({ input, ctx }: GetScheduleOptions) {
|
||||
const orgDetails = orgDomainConfig(ctx?.req);
|
||||
if (process.env.INTEGRATION_TEST_MODE === "true") {
|
||||
@@ -494,14 +520,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions) {
|
||||
userId: { in: usersWithCredentials.map((user) => user.id) },
|
||||
releaseAt: { gt: dayjs.utc().format() },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
slotUtcStartDate: true,
|
||||
slotUtcEndDate: true,
|
||||
userId: true,
|
||||
isSeat: true,
|
||||
eventTypeId: true,
|
||||
},
|
||||
...selectSelectedSlots,
|
||||
})) || [];
|
||||
await prisma.selectedSlots.deleteMany({
|
||||
where: { eventTypeId: { equals: eventType.id }, id: { notIn: selectedSlots.map((item) => item.id) } },
|
||||
@@ -534,16 +553,11 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions) {
|
||||
);
|
||||
}
|
||||
|
||||
if (occupiedSeats?.length && typeof availabilityCheckProps.currentSeats === undefined)
|
||||
availabilityCheckProps.currentSeats = [];
|
||||
const occupiedSeatsCount = countBy(occupiedSeats, (item) => item.slotUtcStartDate.toISOString());
|
||||
Object.keys(occupiedSeatsCount).forEach((date) => {
|
||||
(availabilityCheckProps.currentSeats as CurrentSeats).push({
|
||||
uid: uuid(),
|
||||
startTime: dayjs(date).toDate(),
|
||||
_count: { attendees: occupiedSeatsCount[date] },
|
||||
});
|
||||
});
|
||||
availabilityCheckProps.currentSeats = applyOccupiedSeatsToCurrentSeats(
|
||||
availabilityCheckProps.currentSeats || [],
|
||||
occupiedSeats
|
||||
);
|
||||
|
||||
currentSeats = availabilityCheckProps.currentSeats;
|
||||
}
|
||||
availableTimeSlots = availableTimeSlots
|
||||
|
||||
@@ -23,17 +23,20 @@ export const deleteHandler = async ({ ctx, input }: DeleteOptions) => {
|
||||
|
||||
if (IS_TEAM_BILLING_ENABLED) await cancelTeamSubscriptionFromStripe(input.teamId);
|
||||
|
||||
// delete all memberships
|
||||
await prisma.membership.deleteMany({
|
||||
where: {
|
||||
teamId: input.teamId,
|
||||
},
|
||||
});
|
||||
const deletedTeam = await prisma.$transaction(async (tx) => {
|
||||
// delete all memberships
|
||||
await tx.membership.deleteMany({
|
||||
where: {
|
||||
teamId: input.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
const deletedTeam = await prisma.team.delete({
|
||||
where: {
|
||||
id: input.teamId,
|
||||
},
|
||||
const deletedTeam = await tx.team.delete({
|
||||
where: {
|
||||
id: input.teamId,
|
||||
},
|
||||
});
|
||||
return deletedTeam;
|
||||
});
|
||||
|
||||
const deletedTeamMetadata = teamMetadataSchema.parse(deletedTeam.metadata);
|
||||
|
||||
@@ -285,7 +285,7 @@ export async function createNewUsersConnectToOrgIfExists({
|
||||
data: {
|
||||
teamId: parentId,
|
||||
userId: createdUser.id,
|
||||
role: input.role as MembershipRole,
|
||||
role: MembershipRole.MEMBER,
|
||||
accepted: autoAccept,
|
||||
},
|
||||
});
|
||||
@@ -332,7 +332,7 @@ export async function createMemberships({
|
||||
accepted,
|
||||
teamId: parentId,
|
||||
userId: invitee.id,
|
||||
role: input.role as MembershipRole,
|
||||
role: MembershipRole.MEMBER,
|
||||
});
|
||||
}
|
||||
return data;
|
||||
|
||||
@@ -43,25 +43,26 @@ export const removeMemberHandler = async ({ ctx, input }: RemoveMemberOptions) =
|
||||
message: "You can not remove yourself from a team you own.",
|
||||
});
|
||||
|
||||
const membership = await ctx.prisma.membership.delete({
|
||||
where: {
|
||||
userId_teamId: { userId: input.memberId, teamId: input.teamId },
|
||||
},
|
||||
include: {
|
||||
user: true,
|
||||
team: true,
|
||||
},
|
||||
});
|
||||
|
||||
// remove user as host from team events associated with this membership
|
||||
await ctx.prisma.host.deleteMany({
|
||||
where: {
|
||||
userId: input.memberId,
|
||||
eventType: {
|
||||
teamId: input.teamId,
|
||||
const [membership] = await ctx.prisma.$transaction([
|
||||
ctx.prisma.membership.delete({
|
||||
where: {
|
||||
userId_teamId: { userId: input.memberId, teamId: input.teamId },
|
||||
},
|
||||
},
|
||||
});
|
||||
include: {
|
||||
user: true,
|
||||
team: true,
|
||||
},
|
||||
}),
|
||||
// remove user as host from team events associated with this membership
|
||||
ctx.prisma.host.deleteMany({
|
||||
where: {
|
||||
userId: input.memberId,
|
||||
eventType: {
|
||||
teamId: input.teamId,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (input.isOrg) {
|
||||
log.debug("Removing a member from the organization");
|
||||
|
||||
@@ -32,7 +32,7 @@ function OrganizationIndicator({
|
||||
return (
|
||||
<div className={classNames("absolute bottom-0 right-0 z-10", size === "lg" ? "h-6 w-6" : "h-10 w-10")}>
|
||||
<img
|
||||
data-testId="organization-logo"
|
||||
data-testid="organization-logo"
|
||||
src={organizationUrl}
|
||||
alt={user.username || ""}
|
||||
className="flex h-full items-center justify-center rounded-full"
|
||||
|
||||
@@ -81,6 +81,7 @@ export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(function
|
||||
onClickAddon,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
t: __t,
|
||||
dataTestid,
|
||||
...passThrough
|
||||
} = props;
|
||||
|
||||
@@ -114,6 +115,7 @@ export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(function
|
||||
</Addon>
|
||||
)}
|
||||
<Input
|
||||
data-testid={`${dataTestid}-input` ?? "input-field"}
|
||||
id={id}
|
||||
type={type}
|
||||
placeholder={placeholder}
|
||||
|
||||
@@ -17,6 +17,7 @@ export type InputFieldProps = {
|
||||
containerClassName?: string;
|
||||
showAsteriskIndicator?: boolean;
|
||||
t?: (key: string) => string;
|
||||
dataTestid?: string;
|
||||
onClickAddon?: () => void;
|
||||
} & React.ComponentProps<typeof Input> & {
|
||||
labelProps?: React.ComponentProps<typeof Label>;
|
||||
|
||||
@@ -78,7 +78,11 @@ const VerticalTabItem = ({
|
||||
{props.isExternalLink ? <ExternalLink data-testid="external-link" /> : null}
|
||||
</span>
|
||||
{info && (
|
||||
<Skeleton as="p" title={t(info)} className="max-w-44 mt-1 truncate text-xs font-normal">
|
||||
<Skeleton
|
||||
data-testid="apps-info"
|
||||
as="p"
|
||||
title={t(info)}
|
||||
className="max-w-44 mt-1 truncate text-xs font-normal">
|
||||
{t(info)}
|
||||
</Skeleton>
|
||||
)}
|
||||
|
||||
@@ -17,21 +17,14 @@ export type PhoneInputProps = {
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
function BasePhoneInput({ name, className = "", onChange, ...rest }: PhoneInputProps) {
|
||||
useEffect(() => {
|
||||
if (!rest.value) {
|
||||
return;
|
||||
}
|
||||
const formattedValue = rest.value.trim().replace(/^\+?/, "+");
|
||||
onChange(formattedValue);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
function BasePhoneInput({ name, className = "", onChange, value, ...rest }: PhoneInputProps) {
|
||||
const defaultCountry = useDefaultCountry();
|
||||
|
||||
return (
|
||||
<PhoneInput
|
||||
{...rest}
|
||||
country={rest.value ? undefined : defaultCountry}
|
||||
value={value ? value.trim().replace(/^\+?/, "+") : undefined}
|
||||
country={value ? undefined : defaultCountry}
|
||||
enableSearch
|
||||
disableSearchIcon
|
||||
inputProps={{
|
||||
|
||||
@@ -3661,7 +3661,7 @@ __metadata:
|
||||
swr: ^1.2.2
|
||||
tailwindcss: ^3.3.3
|
||||
typescript: ^4.9.4
|
||||
zod: ^3.22.2
|
||||
zod: ^3.22.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -3723,6 +3723,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/demodesk@workspace:packages/app-store/demodesk":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/demodesk@workspace:packages/app-store/demodesk"
|
||||
dependencies:
|
||||
"@calcom/lib": "*"
|
||||
"@calcom/types": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/discord@workspace:packages/app-store/discord":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/discord@workspace:packages/app-store/discord"
|
||||
@@ -4083,6 +4092,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/linear@workspace:packages/app-store/linear":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/linear@workspace:packages/app-store/linear"
|
||||
dependencies:
|
||||
"@calcom/lib": "*"
|
||||
"@calcom/types": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/make@workspace:packages/app-store/make":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/make@workspace:packages/app-store/make"
|
||||
@@ -4404,6 +4422,7 @@ __metadata:
|
||||
"@types/node": 16.9.1
|
||||
"@types/react": 18.0.26
|
||||
"@types/react-dom": ^18.0.9
|
||||
"@types/swagger-ui-react": ^4.18.3
|
||||
highlight.js: ^11.6.0
|
||||
isarray: 2.0.5
|
||||
next: ^13.5.4
|
||||
@@ -4748,7 +4767,7 @@ __metadata:
|
||||
"@radix-ui/react-tabs": ^1.0.0
|
||||
"@radix-ui/react-tooltip": ^1.0.0
|
||||
"@stripe/stripe-js": ^1.35.0
|
||||
"@tanstack/react-query": ^4.3.9
|
||||
"@tanstack/react-query": ^5.17.15
|
||||
"@typeform/embed-react": ^1.2.4
|
||||
"@types/bcryptjs": ^2.4.2
|
||||
"@types/debounce": ^1.2.1
|
||||
@@ -4777,6 +4796,7 @@ __metadata:
|
||||
fathom-client: ^3.5.0
|
||||
globby: ^13.1.3
|
||||
graphql: ^16.8.0
|
||||
graphql-codegen: ^0.4.0
|
||||
graphql-request: ^6.1.0
|
||||
gray-matter: ^4.0.3
|
||||
gsap: ^3.11.0
|
||||
@@ -4819,7 +4839,7 @@ __metadata:
|
||||
typescript: ^4.9.4
|
||||
wait-on: ^7.0.1
|
||||
xml2js: ^0.6.0
|
||||
zod: ^3.22.2
|
||||
zod: ^3.22.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -13041,13 +13061,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tanstack/query-core@npm:4.36.1":
|
||||
version: 4.36.1
|
||||
resolution: "@tanstack/query-core@npm:4.36.1"
|
||||
checksum: 47672094da20d89402d9fe03bb7b0462be73a76ff9ca715169738bc600a719d064d106d083a8eedae22a2c22de22f87d5eb5d31ef447aba771d9190f2117ed10
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tanstack/query-core@npm:5.17.19":
|
||||
version: 5.17.19
|
||||
resolution: "@tanstack/query-core@npm:5.17.19"
|
||||
@@ -13055,25 +13068,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tanstack/react-query@npm:^4.3.9":
|
||||
version: 4.36.1
|
||||
resolution: "@tanstack/react-query@npm:4.36.1"
|
||||
dependencies:
|
||||
"@tanstack/query-core": 4.36.1
|
||||
use-sync-external-store: ^1.2.0
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-native: "*"
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
checksum: 1aff0a476859386f8d32253fa0d0bde7b81769a6d4d4d9cbd78778f0f955459a3bdb7ee27a0d2ee7373090f12998b45df80db0b5b313bd0a7a39d36c6e8e51c5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@tanstack/react-query@npm:^5.17.15":
|
||||
version: 5.17.19
|
||||
resolution: "@tanstack/react-query@npm:5.17.19"
|
||||
@@ -14481,6 +14475,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/swagger-ui-react@npm:^4.18.3":
|
||||
version: 4.18.3
|
||||
resolution: "@types/swagger-ui-react@npm:4.18.3"
|
||||
dependencies:
|
||||
"@types/react": "*"
|
||||
checksum: 4927314f1b0d68edf200ef15bca7555f12ec1bb8cc699fa397ef2f4e1e1873d17880b663bbc6d70e30149e50c3e7055178c1e0aad110520dfb31d781ab326dcb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/testing-library__jest-dom@npm:^5.9.1":
|
||||
version: 5.14.8
|
||||
resolution: "@types/testing-library__jest-dom@npm:5.14.8"
|
||||
@@ -16543,6 +16546,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-runtime@npm:^6.11.6":
|
||||
version: 6.26.0
|
||||
resolution: "babel-runtime@npm:6.26.0"
|
||||
dependencies:
|
||||
core-js: ^2.4.0
|
||||
regenerator-runtime: ^0.11.0
|
||||
checksum: 8aeade94665e67a73c1ccc10f6fd42ba0c689b980032b70929de7a6d9a12eb87ef51902733f8fefede35afea7a5c3ef7e916a64d503446c1eedc9e3284bd3d50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bail@npm:^2.0.0":
|
||||
version: 2.0.2
|
||||
resolution: "bail@npm:2.0.2"
|
||||
@@ -17288,6 +17301,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camel-case@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "camel-case@npm:3.0.0"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
upper-case: ^1.1.1
|
||||
checksum: 4190ed6ab8acf4f3f6e1a78ad4d0f3f15ce717b6bfa1b5686d58e4bcd29960f6e312dd746b5fa259c6d452f1413caef25aee2e10c9b9a580ac83e516533a961a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camel-case@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "camel-case@npm:4.1.2"
|
||||
@@ -17323,6 +17346,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camelcase@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "camelcase@npm:3.0.0"
|
||||
checksum: ae4fe1c17c8442a3a345a6b7d2393f028ab7a7601af0c352ad15d1ab97ca75112e19e29c942b2a214898e160194829b68923bce30e018d62149c6d84187f1673
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camelcase@npm:^5.0.0, camelcase@npm:^5.3.1":
|
||||
version: 5.3.1
|
||||
resolution: "camelcase@npm:5.3.1"
|
||||
@@ -17527,6 +17557,32 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"change-case@npm:^3.0.0":
|
||||
version: 3.1.0
|
||||
resolution: "change-case@npm:3.1.0"
|
||||
dependencies:
|
||||
camel-case: ^3.0.0
|
||||
constant-case: ^2.0.0
|
||||
dot-case: ^2.1.0
|
||||
header-case: ^1.0.0
|
||||
is-lower-case: ^1.1.0
|
||||
is-upper-case: ^1.1.0
|
||||
lower-case: ^1.1.1
|
||||
lower-case-first: ^1.0.0
|
||||
no-case: ^2.3.2
|
||||
param-case: ^2.1.0
|
||||
pascal-case: ^2.0.0
|
||||
path-case: ^2.1.0
|
||||
sentence-case: ^2.1.0
|
||||
snake-case: ^2.1.0
|
||||
swap-case: ^1.1.0
|
||||
title-case: ^2.1.0
|
||||
upper-case: ^1.1.1
|
||||
upper-case-first: ^1.1.0
|
||||
checksum: d6f9f90a5f1d2a98294e06ea62f913fa0d7cfc289f188bf05662344da6128f5710b5c99ece83682c6a848db8d996b7348e09b2235dc3363afb6ae7142e7978e1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"change-case@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "change-case@npm:4.1.2"
|
||||
@@ -17919,6 +17975,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cliui@npm:^3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "cliui@npm:3.2.0"
|
||||
dependencies:
|
||||
string-width: ^1.0.1
|
||||
strip-ansi: ^3.0.1
|
||||
wrap-ansi: ^2.0.0
|
||||
checksum: c68d1dbc3e347bfe79ed19cc7f48007d5edd6cd8438342e32073e0b4e311e3c44e1f4f19221462bc6590de56c2df520e427533a9dde95dee25710bec322746ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cliui@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "cliui@npm:6.0.0"
|
||||
@@ -18070,6 +18137,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"code-point-at@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "code-point-at@npm:1.1.0"
|
||||
checksum: 17d5666611f9b16d64fdf48176d9b7fb1c7d1c1607a189f7e600040a11a6616982876af148230336adb7d8fe728a559f743a4e29db3747e3b1a32fa7f4529681
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"coffeescript@npm:^1.10.0":
|
||||
version: 1.12.7
|
||||
resolution: "coffeescript@npm:1.12.7"
|
||||
@@ -18436,6 +18510,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"constant-case@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "constant-case@npm:2.0.0"
|
||||
dependencies:
|
||||
snake-case: ^2.1.0
|
||||
upper-case: ^1.1.1
|
||||
checksum: 893c793a425ebcd0744061c7f12650c655aae259b89d5654fb8eda42d22c3690716a4988ed03f2abe370b1ee7bfec44f8e4395e76e2f1458a8921982b15410ba
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"constant-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "constant-case@npm:3.0.4"
|
||||
@@ -18594,6 +18678,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"core-js@npm:^2.4.0":
|
||||
version: 2.6.12
|
||||
resolution: "core-js@npm:2.6.12"
|
||||
checksum: 44fa9934a85f8c78d61e0c8b7b22436330471ffe59ec5076fe7f324d6e8cf7f824b14b1c81ca73608b13bdb0fef035bd820989bf059767ad6fa13123bb8bd016
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"core-js@npm:^3":
|
||||
version: 3.21.1
|
||||
resolution: "core-js@npm:3.21.1"
|
||||
@@ -19301,7 +19392,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decamelize@npm:1.2.0, decamelize@npm:^1.1.0, decamelize@npm:^1.2.0":
|
||||
"decamelize@npm:1.2.0, decamelize@npm:^1.1.0, decamelize@npm:^1.1.1, decamelize@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "decamelize@npm:1.2.0"
|
||||
checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa
|
||||
@@ -19895,6 +19986,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dot-case@npm:^2.1.0":
|
||||
version: 2.1.1
|
||||
resolution: "dot-case@npm:2.1.1"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
checksum: 5c9d937245ff810a7ae788602e40c62e38cb515146ddf9b11c7f60cb02aae84859588761f1e8769d9e713609fae3c78dc99c8da9e0ee8e4d8b5c09a2fdf70328
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dot-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "dot-case@npm:3.0.4"
|
||||
@@ -20198,7 +20298,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"encoding@npm:0.1.13, encoding@npm:^0.1.13":
|
||||
"encoding@npm:0.1.13, encoding@npm:^0.1.11, encoding@npm:^0.1.13":
|
||||
version: 0.1.13
|
||||
resolution: "encoding@npm:0.1.13"
|
||||
dependencies:
|
||||
@@ -20343,7 +20443,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"error-ex@npm:^1.3.1":
|
||||
"error-ex@npm:^1.2.0, error-ex@npm:^1.3.1":
|
||||
version: 1.3.2
|
||||
resolution: "error-ex@npm:1.3.2"
|
||||
dependencies:
|
||||
@@ -22017,6 +22117,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"find-up@npm:^1.0.0":
|
||||
version: 1.1.2
|
||||
resolution: "find-up@npm:1.1.2"
|
||||
dependencies:
|
||||
path-exists: ^2.0.0
|
||||
pinkie-promise: ^2.0.0
|
||||
checksum: a2cb9f4c9f06ee3a1e92ed71d5aed41ac8ae30aefa568132f6c556fac7678a5035126153b59eaec68da78ac409eef02503b2b059706bdbf232668d7245e3240a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"find-up@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "find-up@npm:2.1.0"
|
||||
@@ -22675,6 +22785,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-caller-file@npm:^1.0.1":
|
||||
version: 1.0.3
|
||||
resolution: "get-caller-file@npm:1.0.3"
|
||||
checksum: 2b90a7f848896abcebcdc0acc627a435bcf05b9cd280599bc980ebfcdc222416c3df12c24c4845f69adc4346728e8966f70b758f9369f3534182791dfbc25c05
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5":
|
||||
version: 2.0.5
|
||||
resolution: "get-caller-file@npm:2.0.5"
|
||||
@@ -23270,6 +23387,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql-codegen@npm:^0.4.0":
|
||||
version: 0.4.0
|
||||
resolution: "graphql-codegen@npm:0.4.0"
|
||||
dependencies:
|
||||
babel-runtime: ^6.11.6
|
||||
change-case: ^3.0.0
|
||||
graphql: ^0.7.0
|
||||
inflected: ^1.1.7
|
||||
mkdirp: ^0.5.1
|
||||
node-fetch: ^1.5.3
|
||||
yargs: ^5.0.0
|
||||
bin:
|
||||
graphql-codegen: ./lib/cli.js
|
||||
checksum: 584ad3382de9ee3927cfd4fcc340abb2f8d4bbdacacebe9e56e34edf255c87eb1e191f2d7c4f3d1d5bb0ebd829b852e50efe91e967683a8b181dcd3b26ae6b6c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql-config@npm:^5.0.2":
|
||||
version: 5.0.3
|
||||
resolution: "graphql-config@npm:5.0.3"
|
||||
@@ -23327,6 +23461,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql@npm:^0.7.0":
|
||||
version: 0.7.2
|
||||
resolution: "graphql@npm:0.7.2"
|
||||
dependencies:
|
||||
iterall: 1.0.2
|
||||
checksum: 9b815b851d4fbc861609ce37e88e0be881d25fa2d5dc54f661379e600d103d4f051cee15a09799c4efa2d3590a61f64fc2e1d67332c7fdf8df2871c27b1c3f40
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql@npm:^16.3.0":
|
||||
version: 16.5.0
|
||||
resolution: "graphql@npm:16.5.0"
|
||||
@@ -23739,6 +23882,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"header-case@npm:^1.0.0":
|
||||
version: 1.0.1
|
||||
resolution: "header-case@npm:1.0.1"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
upper-case: ^1.1.3
|
||||
checksum: fe1cc9a555ec9aabc2de80f4dd961a81c534fc23951694fef34297e59b0dd60f26647148731bf0dd3fdb3a1c688089d3cd147d7038db850e25be7c0a5fabb022
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"header-case@npm:^2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "header-case@npm:2.0.4"
|
||||
@@ -24384,6 +24537,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inflected@npm:^1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "inflected@npm:1.1.7"
|
||||
checksum: eac857f10871586006d629dc72bab05058f1967c10fae9d7391d627534566a8e5be0a1f690d2590102d890e4ef5647b73b7827380dc7bcf50faac4154f0ab084
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inflight@npm:^1.0.4":
|
||||
version: 1.0.6
|
||||
resolution: "inflight@npm:1.0.6"
|
||||
@@ -24613,6 +24773,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"invert-kv@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "invert-kv@npm:1.0.0"
|
||||
checksum: aebeee31dda3b3d25ffd242e9a050926e7fe5df642d60953ab183aca1a7d1ffb39922eb2618affb0e850cf2923116f0da1345367759d88d097df5da1f1e1590e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ip@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "ip@npm:2.0.0"
|
||||
@@ -24906,6 +25073,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-fullwidth-code-point@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "is-fullwidth-code-point@npm:1.0.0"
|
||||
dependencies:
|
||||
number-is-nan: ^1.0.0
|
||||
checksum: 4d46a7465a66a8aebcc5340d3b63a56602133874af576a9ca42c6f0f4bd787a743605771c5f246db77da96605fefeffb65fc1dbe862dcc7328f4b4d03edf5a57
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-fullwidth-code-point@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "is-fullwidth-code-point@npm:3.0.0"
|
||||
@@ -25203,7 +25379,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-stream@npm:^1.1.0":
|
||||
"is-stream@npm:^1.0.1, is-stream@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "is-stream@npm:1.1.0"
|
||||
checksum: 063c6bec9d5647aa6d42108d4c59723d2bd4ae42135a2d4db6eadbd49b7ea05b750fd69d279e5c7c45cf9da753ad2c00d8978be354d65aa9f6bb434969c6a2ae
|
||||
@@ -25294,6 +25470,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-utf8@npm:^0.2.0":
|
||||
version: 0.2.1
|
||||
resolution: "is-utf8@npm:0.2.1"
|
||||
checksum: 167ccd2be869fc228cc62c1a28df4b78c6b5485d15a29027d3b5dceb09b383e86a3522008b56dcac14b592b22f0a224388718c2505027a994fd8471465de54b3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-weakmap@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "is-weakmap@npm:2.0.1"
|
||||
@@ -25473,6 +25656,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iterall@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "iterall@npm:1.0.2"
|
||||
checksum: f87cbb8e22e3681f4d7ba634e4ce7bd419a78b47ff7b01f57f90cf761d187cb845fcac0d4d7e4c7dfcbfb80467c8ea42a9f3691bb3aa909e3e3707a25735ed70
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jackspeak@npm:^2.0.3, jackspeak@npm:^2.3.5":
|
||||
version: 2.3.6
|
||||
resolution: "jackspeak@npm:2.3.6"
|
||||
@@ -26604,6 +26794,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lcid@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "lcid@npm:1.0.0"
|
||||
dependencies:
|
||||
invert-kv: ^1.0.0
|
||||
checksum: e8c7a4db07663068c5c44b650938a2bc41aa992037eebb69376214320f202c1250e70b50c32f939e28345fd30c2d35b8e8cd9a19d5932c398246a864ce54843d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"leac@npm:^0.6.0":
|
||||
version: 0.6.0
|
||||
resolution: "leac@npm:0.6.0"
|
||||
@@ -26953,6 +27152,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"load-json-file@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "load-json-file@npm:1.1.0"
|
||||
dependencies:
|
||||
graceful-fs: ^4.1.2
|
||||
parse-json: ^2.2.0
|
||||
pify: ^2.0.0
|
||||
pinkie-promise: ^2.0.0
|
||||
strip-bom: ^2.0.0
|
||||
checksum: 0e4e4f380d897e13aa236246a917527ea5a14e4fc34d49e01ce4e7e2a1e08e2740ee463a03fb021c04f594f29a178f4adb994087549d7c1c5315fcd29bf9934b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"load-json-file@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "load-json-file@npm:4.0.0"
|
||||
@@ -27096,6 +27308,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.assign@npm:^4.1.0, lodash.assign@npm:^4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "lodash.assign@npm:4.2.0"
|
||||
checksum: 75bbc6733c9f577c448031b4051f990f068802708891f94be9d4c2faffd6a9ec67a2c49671dafc908a068d35687765464853282842b4560b662e6c903d11cc90
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.camelcase@npm:^4.3.0":
|
||||
version: 4.3.0
|
||||
resolution: "lodash.camelcase@npm:4.3.0"
|
||||
@@ -29654,6 +29873,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"no-case@npm:^2.2.0, no-case@npm:^2.3.2":
|
||||
version: 2.3.2
|
||||
resolution: "no-case@npm:2.3.2"
|
||||
dependencies:
|
||||
lower-case: ^1.1.1
|
||||
checksum: 856487731936fef44377ca74fdc5076464aba2e0734b56a4aa2b2a23d5b154806b591b9b2465faa59bb982e2b5c9391e3685400957fb4eeb38f480525adcf3dd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"no-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "no-case@npm:3.0.4"
|
||||
@@ -29747,6 +29975,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch@npm:^1.5.3":
|
||||
version: 1.7.3
|
||||
resolution: "node-fetch@npm:1.7.3"
|
||||
dependencies:
|
||||
encoding: ^0.1.11
|
||||
is-stream: ^1.0.1
|
||||
checksum: 3bb0528c05d541316ebe52770d71ee25a6dce334df4231fd55df41a644143e07f068637488c18a5b0c43f05041dbd3346752f9e19b50df50569a802484544d5b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch@npm:^2.0.0, node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.9":
|
||||
version: 2.7.0
|
||||
resolution: "node-fetch@npm:2.7.0"
|
||||
@@ -30115,6 +30353,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"number-is-nan@npm:^1.0.0":
|
||||
version: 1.0.1
|
||||
resolution: "number-is-nan@npm:1.0.1"
|
||||
checksum: 13656bc9aa771b96cef209ffca31c31a03b507ca6862ba7c3f638a283560620d723d52e626d57892c7fff475f4c36ac07f0600f14544692ff595abff214b9ffb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nwsapi@npm:^2.2.4":
|
||||
version: 2.2.4
|
||||
resolution: "nwsapi@npm:2.2.4"
|
||||
@@ -30585,6 +30830,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"os-locale@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "os-locale@npm:1.4.0"
|
||||
dependencies:
|
||||
lcid: ^1.0.0
|
||||
checksum: 0161a1b6b5a8492f99f4b47fe465df9fc521c55ba5414fce6444c45e2500487b8ed5b40a47a98a2363fe83ff04ab033785300ed8df717255ec4c3b625e55b1fb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"os-tmpdir@npm:~1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "os-tmpdir@npm:1.0.2"
|
||||
@@ -30810,6 +31064,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"param-case@npm:^2.1.0":
|
||||
version: 2.1.1
|
||||
resolution: "param-case@npm:2.1.1"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
checksum: 3a63dcb8d8dc7995a612de061afdc7bb6fe7bd0e6db994db8d4cae999ed879859fd24389090e1a0d93f4c9207ebf8c048c870f468a3f4767161753e03cb9ab58
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"param-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "param-case@npm:3.0.4"
|
||||
@@ -30921,6 +31184,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-json@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "parse-json@npm:2.2.0"
|
||||
dependencies:
|
||||
error-ex: ^1.2.0
|
||||
checksum: dda78a63e57a47b713a038630868538f718a7ca0cd172a36887b0392ccf544ed0374902eb28f8bf3409e8b71d62b79d17062f8543afccf2745f9b0b2d2bb80ca
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-json@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "parse-json@npm:4.0.0"
|
||||
@@ -31009,6 +31281,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pascal-case@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "pascal-case@npm:2.0.1"
|
||||
dependencies:
|
||||
camel-case: ^3.0.0
|
||||
upper-case-first: ^1.1.0
|
||||
checksum: 4c539bf556572812f64a02fc6b544f3d2b51db12aed484e5162ed7f8ac2b366775d15e536091c890d71d82bdf9153128321f21574721b3a984bd85df9e519a35
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pascal-case@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "pascal-case@npm:3.1.2"
|
||||
@@ -31052,6 +31334,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-case@npm:^2.1.0":
|
||||
version: 2.1.1
|
||||
resolution: "path-case@npm:2.1.1"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
checksum: eb1da508c28378715cbe4ce054ee5f83a570c5010f041f4cfb439c811f7a78e36c46f26a8d59b2594c3882b53db06ef26195519c27f86523dc5d19c2e29f306d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "path-case@npm:3.0.4"
|
||||
@@ -31062,6 +31353,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-exists@npm:^2.0.0":
|
||||
version: 2.1.0
|
||||
resolution: "path-exists@npm:2.1.0"
|
||||
dependencies:
|
||||
pinkie-promise: ^2.0.0
|
||||
checksum: fdb734f1d00f225f7a0033ce6d73bff6a7f76ea08936abf0e5196fa6e54a645103538cd8aedcb90d6d8c3fa3705ded0c58a4da5948ae92aa8834892c1ab44a84
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-exists@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "path-exists@npm:3.0.0"
|
||||
@@ -31151,6 +31451,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "path-type@npm:1.1.0"
|
||||
dependencies:
|
||||
graceful-fs: ^4.1.2
|
||||
pify: ^2.0.0
|
||||
pinkie-promise: ^2.0.0
|
||||
checksum: 59a4b2c0e566baf4db3021a1ed4ec09a8b36fca960a490b54a6bcefdb9987dafe772852982b6011cd09579478a96e57960a01f75fa78a794192853c9d468fc79
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "path-type@npm:3.0.0"
|
||||
@@ -31371,7 +31682,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pify@npm:^2.3.0":
|
||||
"pify@npm:^2.0.0, pify@npm:^2.3.0":
|
||||
version: 2.3.0
|
||||
resolution: "pify@npm:2.3.0"
|
||||
checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba
|
||||
@@ -31401,6 +31712,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pinkie-promise@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "pinkie-promise@npm:2.0.1"
|
||||
dependencies:
|
||||
pinkie: ^2.0.0
|
||||
checksum: b53a4a2e73bf56b6f421eef711e7bdcb693d6abb474d57c5c413b809f654ba5ee750c6a96dd7225052d4b96c4d053cdcb34b708a86fceed4663303abee52fcca
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pinkie@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "pinkie@npm:1.0.0"
|
||||
@@ -31408,6 +31728,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pinkie@npm:^2.0.0":
|
||||
version: 2.0.4
|
||||
resolution: "pinkie@npm:2.0.4"
|
||||
checksum: b12b10afea1177595aab036fc220785488f67b4b0fc49e7a27979472592e971614fa1c728e63ad3e7eb748b4ec3c3dbd780819331dad6f7d635c77c10537b9db
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pirates@npm:^4.0.1, pirates@npm:^4.0.5":
|
||||
version: 4.0.5
|
||||
resolution: "pirates@npm:4.0.5"
|
||||
@@ -33554,6 +33881,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"read-pkg-up@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "read-pkg-up@npm:1.0.1"
|
||||
dependencies:
|
||||
find-up: ^1.0.0
|
||||
read-pkg: ^1.0.0
|
||||
checksum: d18399a0f46e2da32beb2f041edd0cda49d2f2cc30195a05c759ef3ed9b5e6e19ba1ad1bae2362bdec8c6a9f2c3d18f4d5e8c369e808b03d498d5781cb9122c7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"read-pkg@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "read-pkg@npm:1.1.0"
|
||||
dependencies:
|
||||
load-json-file: ^1.0.0
|
||||
normalize-package-data: ^2.3.2
|
||||
path-type: ^1.0.0
|
||||
checksum: a0f5d5e32227ec8e6a028dd5c5134eab229768dcb7a5d9a41a284ed28ad4b9284fecc47383dc1593b5694f4de603a7ffaee84b738956b9b77e0999567485a366
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"read-pkg@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "read-pkg@npm:3.0.0"
|
||||
@@ -33841,6 +34189,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerator-runtime@npm:^0.11.0":
|
||||
version: 0.11.1
|
||||
resolution: "regenerator-runtime@npm:0.11.1"
|
||||
checksum: 3c97bd2c7b2b3247e6f8e2147a002eb78c995323732dad5dc70fac8d8d0b758d0295e7015b90d3d444446ae77cbd24b9f9123ec3a77018e81d8999818301b4f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerator-runtime@npm:^0.13.3":
|
||||
version: 0.13.9
|
||||
resolution: "regenerator-runtime@npm:0.13.9"
|
||||
@@ -34172,6 +34527,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"require-main-filename@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "require-main-filename@npm:1.0.1"
|
||||
checksum: 1fef30754da961f4e13c450c3eb60c7ae898a529c6ad6fa708a70bd2eed01564ceb299187b2899f5562804d797a059f39a5789884d0ac7b7ae1defc68fba4abf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"require-main-filename@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "require-main-filename@npm:2.0.0"
|
||||
@@ -34972,6 +35334,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sentence-case@npm:^2.1.0":
|
||||
version: 2.1.1
|
||||
resolution: "sentence-case@npm:2.1.1"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
upper-case-first: ^1.1.2
|
||||
checksum: ce5ca48804051e056a6956ad75a1a7d833e5d8f5021a015d380a22d3cf04496d5238de2e5c876d9701a9218633052c3a65911ca1b6460d36a41ecad46e81d139
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sentence-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "sentence-case@npm:3.0.4"
|
||||
@@ -35366,6 +35738,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"snake-case@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "snake-case@npm:2.1.0"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
checksum: 7e42b4841103be4dd050b2f57f5cb423d5164524c1cb3d81efda9809265a82a2d02ddf44361beae37d75a239308e6414be85fe441dc48cd70c708cb975387d10
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"snake-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "snake-case@npm:3.0.4"
|
||||
@@ -35895,6 +36276,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"string-width@npm:^1.0.1, string-width@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "string-width@npm:1.0.2"
|
||||
dependencies:
|
||||
code-point-at: ^1.0.0
|
||||
is-fullwidth-code-point: ^1.0.0
|
||||
strip-ansi: ^3.0.0
|
||||
checksum: 5c79439e95bc3bd7233a332c5f5926ab2ee90b23816ed4faa380ce3b2576d7800b0a5bb15ae88ed28737acc7ea06a518c2eef39142dd727adad0e45c776cd37e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2":
|
||||
version: 5.1.2
|
||||
resolution: "string-width@npm:5.1.2"
|
||||
@@ -36086,7 +36478,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strip-ansi@npm:^3.0.0":
|
||||
"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "strip-ansi@npm:3.0.1"
|
||||
dependencies:
|
||||
@@ -36111,6 +36503,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strip-bom@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "strip-bom@npm:2.0.0"
|
||||
dependencies:
|
||||
is-utf8: ^0.2.0
|
||||
checksum: 08efb746bc67b10814cd03d79eb31bac633393a782e3f35efbc1b61b5165d3806d03332a97f362822cf0d4dd14ba2e12707fcff44fe1c870c48a063a0c9e4944
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strip-bom@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "strip-bom@npm:3.0.0"
|
||||
@@ -37018,6 +37419,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"title-case@npm:^2.1.0":
|
||||
version: 2.1.1
|
||||
resolution: "title-case@npm:2.1.1"
|
||||
dependencies:
|
||||
no-case: ^2.2.0
|
||||
upper-case: ^1.0.3
|
||||
checksum: e88ddfc4608a7fb18ed440139d9c42a5f8a50f916e07062be2aef5e2038720746ed51c4fdf9e7190d24a8cc10e6dec9773027fc44450b3a4a5e5c49b4a931fb1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"title-case@npm:^3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "title-case@npm:3.0.3"
|
||||
@@ -38379,7 +38790,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"upper-case-first@npm:^1.1.0":
|
||||
"upper-case-first@npm:^1.1.0, upper-case-first@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "upper-case-first@npm:1.1.2"
|
||||
dependencies:
|
||||
@@ -38397,7 +38808,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"upper-case@npm:^1.0.3, upper-case@npm:^1.1.0, upper-case@npm:^1.1.1":
|
||||
"upper-case@npm:^1.0.3, upper-case@npm:^1.1.0, upper-case@npm:^1.1.1, upper-case@npm:^1.1.3":
|
||||
version: 1.1.3
|
||||
resolution: "upper-case@npm:1.1.3"
|
||||
checksum: 991c845de75fa56e5ad983f15e58494dd77b77cadd79d273cc11e8da400067e9881ae1a52b312aed79b3d754496e2e0712e08d22eae799e35c7f9ba6f3d8a85d
|
||||
@@ -38555,7 +38966,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"use-sync-external-store@npm:1.2.0, use-sync-external-store@npm:^1.2.0":
|
||||
"use-sync-external-store@npm:1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "use-sync-external-store@npm:1.2.0"
|
||||
peerDependencies:
|
||||
@@ -39299,6 +39710,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-module@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "which-module@npm:1.0.0"
|
||||
checksum: 98434f7deb36350cb543c1f15612188541737e1f12d39b23b1c371dff5cf4aa4746210f2bdec202d5fe9da8682adaf8e3f7c44c520687d30948cfc59d5534edb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-module@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "which-module@npm:2.0.0"
|
||||
@@ -39381,6 +39799,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"window-size@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "window-size@npm:0.2.0"
|
||||
bin:
|
||||
window-size: cli.js
|
||||
checksum: a85e2acf156cfa194301294809867bdadd8a48ee5d972d9fa8e3e1b3420a1d0201b13ac8eb0348a0d14bbf2c3316565b6a749749c2384c5d286caf8a064c4f90
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"word-wrap@npm:^1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "word-wrap@npm:1.2.3"
|
||||
@@ -39406,6 +39833,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wrap-ansi@npm:^2.0.0":
|
||||
version: 2.1.0
|
||||
resolution: "wrap-ansi@npm:2.1.0"
|
||||
dependencies:
|
||||
string-width: ^1.0.1
|
||||
strip-ansi: ^3.0.1
|
||||
checksum: 2dacd4b3636f7a53ee13d4d0fe7fa2ed9ad81e9967e17231924ea88a286ec4619a78288de8d41881ee483f4449ab2c0287cde8154ba1bd0126c10271101b2ee3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wrap-ansi@npm:^6.0.1, wrap-ansi@npm:^6.2.0":
|
||||
version: 6.2.0
|
||||
resolution: "wrap-ansi@npm:6.2.0"
|
||||
@@ -39717,6 +40154,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"y18n@npm:^3.2.1":
|
||||
version: 3.2.2
|
||||
resolution: "y18n@npm:3.2.2"
|
||||
checksum: 6154fd7544f8bbf5b18cdf77692ed88d389be49c87238ecb4e0d6a5276446cd2a5c29cc4bdbdddfc7e4e498b08df9d7e38df4a1453cf75eecfead392246ea74a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"y18n@npm:^4.0.0":
|
||||
version: 4.0.3
|
||||
resolution: "y18n@npm:4.0.3"
|
||||
@@ -39825,6 +40269,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs-parser@npm:^3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "yargs-parser@npm:3.2.0"
|
||||
dependencies:
|
||||
camelcase: ^3.0.0
|
||||
lodash.assign: ^4.1.0
|
||||
checksum: d86fd69816a28a617f4cad21f7bfe7f7c931b16d063c73449cd914db409b8d5981a0f29f9e2a05014a7229164aa47336adf5a8856fa9870ab892346d29138e9a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs@npm:^15.1.0, yargs@npm:^15.3.1":
|
||||
version: 15.4.1
|
||||
resolution: "yargs@npm:15.4.1"
|
||||
@@ -39904,6 +40358,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "yargs@npm:5.0.0"
|
||||
dependencies:
|
||||
cliui: ^3.2.0
|
||||
decamelize: ^1.1.1
|
||||
get-caller-file: ^1.0.1
|
||||
lodash.assign: ^4.2.0
|
||||
os-locale: ^1.4.0
|
||||
read-pkg-up: ^1.0.1
|
||||
require-directory: ^2.1.1
|
||||
require-main-filename: ^1.0.1
|
||||
set-blocking: ^2.0.0
|
||||
string-width: ^1.0.2
|
||||
which-module: ^1.0.0
|
||||
window-size: ^0.2.0
|
||||
y18n: ^3.2.1
|
||||
yargs-parser: ^3.2.0
|
||||
checksum: 478e9c8562c5cf5b9c2efc7c917e0b00c489cc50153d5d911ab68767c2cfddaf0b5bd4e04d6fefc00cb1d8f6263eab1d73df79a24d650ba95f5d45c819a1585a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yarn@npm:^1.22.18":
|
||||
version: 1.22.19
|
||||
resolution: "yarn@npm:1.22.19"
|
||||
@@ -40040,13 +40516,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zod@npm:^3.22.2":
|
||||
version: 3.22.2
|
||||
resolution: "zod@npm:3.22.2"
|
||||
checksum: 231e2180c8eabb56e88680d80baff5cf6cbe6d64df3c44c50ebe52f73081ecd0229b1c7215b9552537f537a36d9e36afac2737ddd86dc14e3519bdbc777e82b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zod@npm:^3.22.3, zod@npm:^3.22.4":
|
||||
version: 3.22.4
|
||||
resolution: "zod@npm:3.22.4"
|
||||
|
||||