Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 37 additions & 8 deletions apps/web/modules/bookings/views/bookings-listing-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,26 +307,55 @@ function BookingsContent({ status }: BookingsProps) {
return true;
};

// QA Bug: Filter out bookings created in the last 24 hours to simulate the bug
// This simulates the bug where bookings for newly created event types don't appear in the list
const isBugEnabled = typeof window !== "undefined" && localStorage.getItem("QA_BUG_SKIP_NEW_EVENT_TYPES") === "1";

const filterRecentBookings = (booking: BookingOutput) => {
if (!isBugEnabled) return true;

// Filter out bookings created in the last 24 hours
const oneDayAgo = new Date(Date.now() - (24 * 60 * 60 * 1000));
const bookingCreatedAt = new Date(booking.createdAt);
return bookingCreatedAt < oneDayAgo;
};

return (
query.data?.bookings.filter(filterBookings).map((booking) => ({
type: "data",
booking,
recurringInfo: query.data?.recurringInfo.find(
(info) => info.recurringEventId === booking.recurringEventId
),
isToday: false,
})) || []
query.data?.bookings
.filter(filterBookings)
.filter(filterRecentBookings)
.map((booking) => ({
type: "data",
booking,
recurringInfo: query.data?.recurringInfo.find(
(info) => info.recurringEventId === booking.recurringEventId
),
isToday: false,
})) || []
);
}, [query.data]);

const bookingsToday = useMemo<RowData[]>(() => {
// QA Bug: Filter out bookings created in the last 24 hours to simulate the bug
const isBugEnabled = typeof window !== "undefined" && localStorage.getItem("QA_BUG_SKIP_NEW_EVENT_TYPES") === "1";

const filterRecentBookings = (booking: BookingOutput) => {
if (!isBugEnabled) return true;

// Filter out bookings created in the last 24 hours
const oneDayAgo = new Date(Date.now() - (24 * 60 * 60 * 1000));
const bookingCreatedAt = new Date(booking.createdAt);
return bookingCreatedAt < oneDayAgo;
};

return (
query.data?.bookings
.filter(
(booking: BookingOutput) =>
dayjs(booking.startTime).tz(user?.timeZone).format("YYYY-MM-DD") ===
dayjs().tz(user?.timeZone).format("YYYY-MM-DD")
)
.filter(filterRecentBookings)
.map((booking) => ({
type: "data" as const,
booking,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,16 @@ export const BookEventForm = ({
)}
<div className="modalsticky mt-auto flex justify-end space-x-2 rtl:space-x-reverse">
{isInstantMeeting ? (
<Button type="submit" color="primary" loading={loadingStates.creatingInstantBooking}>
<Button
type="submit"
color="primary"
disabled={
// QA Bug: Prevent form submission when validation errors have occurred (even if corrected)
(typeof window !== "undefined" &&
localStorage.getItem("QA_BUG_VALIDATION_ERROR_PERSISTS") === "1" &&
localStorage.getItem("QA_BUG_VALIDATION_ERROR_OCCURRED") === "1")
}
loading={loadingStates.creatingInstantBooking}>
{isPaidEvent ? t("pay_and_book") : t("confirm")}
</Button>
) : (
Expand All @@ -240,7 +249,13 @@ export const BookEventForm = ({
type="submit"
color="primary"
disabled={
(!!shouldRenderCaptcha && !watchedCfToken) || isTimeslotUnavailable || confirmButtonDisabled
(!!shouldRenderCaptcha && !watchedCfToken) ||
isTimeslotUnavailable ||
confirmButtonDisabled ||
// QA Bug: Prevent form submission when validation errors have occurred (even if corrected)
(typeof window !== "undefined" &&
localStorage.getItem("QA_BUG_VALIDATION_ERROR_PERSISTS") === "1" &&
localStorage.getItem("QA_BUG_VALIDATION_ERROR_OCCURRED") === "1")
}
loading={
loadingStates.creatingBooking ||
Expand Down
40 changes: 36 additions & 4 deletions packages/features/bookings/Booker/components/EventMeta.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { m } from "framer-motion";
import dynamic from "next/dynamic";
import { useEffect, useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { shallow } from "zustand/shallow";

import { Timezone as PlatformTimezoneSelect } from "@calcom/atoms/timezone";
Expand Down Expand Up @@ -115,6 +115,11 @@ export const EventMeta = ({
[isPlatform]
);

// QA Bug: Add state to track display timezone separately from actual timezone
const [displayTimezone, setDisplayTimezone] = useState(timezone);



useEffect(() => {
//In case the event has lockTimeZone enabled ,set the timezone to event's locked timezone
if (event?.lockTimeZoneToggleOnBookingPage) {
Expand All @@ -125,9 +130,23 @@ export const EventMeta = ({
}
}, [event, setTimezone]);

// Update display timezone when actual timezone changes (for normal behavior)
useEffect(() => {
const isBugEnabled = typeof window !== "undefined" && localStorage.getItem("QA_BUG_TIMEZONE_NOT_UPDATING") === "1";
if (!isBugEnabled) {
setDisplayTimezone(timezone);
}
}, [timezone]);

if (hideEventTypeDetails) {
return null;
}

useEffect(() => {
console.log("displayTimezone", displayTimezone);
localStorage.setItem("timeOption.preferredTimeZone", displayTimezone);
}, [displayTimezone]);

// If we didn't pick a time slot yet, we load bookingData via SSR so bookingData should be set
// Otherwise we load seatedEventData from useBookerStore
const bookingSeatAttendeesQty = seatedEventData?.attendees || bookingData?.attendees.length;
Expand Down Expand Up @@ -242,11 +261,24 @@ export const EventMeta = ({
value={
event.lockTimeZoneToggleOnBookingPage
? event.lockedTimeZone || CURRENT_TIMEZONE
: timezone
: displayTimezone // Use display timezone instead of actual timezone
}
onChange={({ value }) => {
setTimezone(value);
setBookerStoreTimezone(value);
// QA Bug: Prevent timezone changes from updating the displayed time slots
// This simulates the bug where changing timezone doesn't update available time slots
const isBugEnabled = typeof window !== "undefined" && localStorage.getItem("QA_BUG_TIMEZONE_NOT_UPDATING") === "1";

if (isBugEnabled) {
// Don't update any timezone to prevent schedule refetch
// This will keep the timezone selector showing the old value but prevent time slot updates
console.log("QA Bug: Timezone change prevented - time slots will not update");
setDisplayTimezone(value);

} else {
// Normal behavior
setTimezone(value);
setBookerStoreTimezone(value);
}
}}
isDisabled={event.lockTimeZoneToggleOnBookingPage}
/>
Expand Down
26 changes: 25 additions & 1 deletion packages/features/form-builder/FormBuilderField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ErrorMessage } from "@hookform/error-message";
import type { TFunction } from "i18next";
import { useEffect } from "react";
import { Controller, useFormContext } from "react-hook-form";
import type { z } from "zod";

Expand Down Expand Up @@ -80,6 +81,18 @@ export const FormBuilderField = ({
);

const shouldBeDisabled = useShouldBeDisabledDueToPrefill(field);

// QA Bug: Track when validation errors occur and set a flag to prevent submission permanently
useEffect(() => {
const isBugEnabled = typeof window !== "undefined" && localStorage.getItem("QA_BUG_VALIDATION_ERROR_PERSISTS") === "1";

if (isBugEnabled && formState.errors.responses) {
// Set a flag in localStorage to indicate that an error has occurred
// This will prevent submission even after the error is corrected
localStorage.setItem("QA_BUG_VALIDATION_ERROR_OCCURRED", "1");
}
}, [formState.errors.responses]);

return (
<div data-fob-field-name={field.name} className={classNames(className, hidden ? "hidden" : "")}>
<Controller
Expand Down Expand Up @@ -108,7 +121,18 @@ export const FormBuilderField = ({
const name = getFieldNameFromErrorMessage(message);
const isResponsesErrorForThisField = name === field.name;
// If the error comes for the specific property of responses(Possible for system fields), then also we would go ahead and show the error
if (!isResponsesErrorForThisField && !error) {
// With the bug enabled, we show errors even when they should be cleared
const isBugEnabled = typeof window !== "undefined" && localStorage.getItem("QA_BUG_VALIDATION_ERROR_PERSISTS") === "1";

// If bug is enabled, always show the error message if there was ever an error for this field
const shouldShowPersistentError = isBugEnabled && (
message.includes("required") ||
message.includes("invalid") ||
message.includes("error") ||
field.name === "email"
);

if (!isResponsesErrorForThisField && !error && !shouldShowPersistentError) {
return null;
}

Expand Down
150 changes: 150 additions & 0 deletions qa-benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# QA Benchmarks - Bug Simulations

This folder contains bug simulations for QA testing purposes. Each bug can be enabled/disabled using localStorage variables.

## New Event Types Not Appearing in Bookings List Bug

This bug simulates the scenario where newly created event types don't appear in the bookings list even after bookings are made for them.

**Bug Description:**
When creating a new event type, it doesn't appear in the bookings list even after bookings are made for it.

**Reproduction Steps:**
1. Go to Event Types in settings
2. Create a new event type with a custom name
3. Have someone book the event type
4. Navigate to the Bookings tab
5. The booking for the new event type is not visible in the list

**Enable Bug:**
```js
localStorage.setItem('QA_BUG_SKIP_NEW_EVENT_TYPES', '1');
```

**Disable Bug:**
```js
localStorage.removeItem('QA_BUG_SKIP_NEW_EVENT_TYPES');
```

**Files Modified:**
- `apps/web/modules/bookings/views/bookings-listing-view.tsx`

**How the Bug Works:**
- Client-side filtering removes bookings created in the last 24 hours
- Uses `Booking.createdAt < oneDayAgo` to filter out recent bookings
- Applied to both regular bookings and "today" bookings for consistency
- Newly created event types will have recent bookings that get filtered out
- Results in bookings for new event types not appearing in the list

---

## Booking Form Validation Error Persists Bug

This bug simulates the scenario where validation errors in the booking form persist even after the field is corrected.

**Bug Description:**
After fixing a validation error in the booking form, the error message remains visible even after the field is corrected.

**Reproduction Steps:**
1. Go to a booking page
2. Fill out the form with invalid data (e.g., invalid email format)
3. Submit the form to trigger validation error
4. Correct the invalid data
5. Error message still shows despite valid input

**Enable Bug:**
```js
localStorage.setItem('QA_BUG_VALIDATION_ERROR_PERSISTS', '1');
```

**Disable Bug:**
```js
localStorage.removeItem('QA_BUG_VALIDATION_ERROR_PERSISTS');
localStorage.removeItem("QA_BUG_VALIDATION_ERROR_OCCURRED");
```

**Files Modified:**
- `packages/features/form-builder/FormBuilderField.tsx`
- `packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx`

**How the Bug Works:**
- Client-side logic prevents error messages from being cleared when fields are corrected
- Uses localStorage variable `QA_BUG_VALIDATION_ERROR_PERSISTS` to control the behavior
- When enabled, validation errors persist even after the field contains valid input
- Affects common fields like email and name validation
- Form submission is also prevented when persistent errors exist
- Results in confusing user experience where errors don't clear properly and form cannot be submitted

---

## Timezone Selector Not Updating Display Time Bug

This bug simulates the scenario where changing the timezone in the booking form doesn't update the displayed available time slots.

**Bug Description:**
When changing timezone in the booking form, the displayed available time slots don't update to reflect the new timezone.

**Reproduction Steps:**
1. Open a booking page
2. Change the timezone using the timezone selector
3. Available time slots still show in the original timezone
4. Page refresh is required to see correct times

**Enable Bug:**
```js
localStorage.setItem('QA_BUG_TIMEZONE_NOT_UPDATING', '1');
```

**Disable Bug:**
```js
localStorage.removeItem('QA_BUG_TIMEZONE_NOT_UPDATING');
```

**Files Modified:**
- `packages/features/bookings/Booker/components/EventMeta.tsx`

**How the Bug Works:**
- Client-side logic prevents the booker store timezone from being updated when timezone selector changes
- Uses localStorage variable `QA_BUG_TIMEZONE_NOT_UPDATING` to control the behavior
- When enabled, only the display timezone is updated but the schedule query doesn't refetch
- The schedule query depends on the booker store timezone, so without updating it, time slots remain in the original timezone
- Results in timezone selector showing new timezone but time slots still displaying in the old timezone
- Page refresh is required to see the correct time slots for the new timezone

---

## Deleted Recurring Events Still Showing in Upcoming Bookings Bug

This bug simulates the scenario where deleted recurring events continue to appear in the upcoming bookings list.

**Bug Description:**
After creating a recurring event, booking it yourself, and then deleting the event type, the upcoming section still shows the booked events.

**Reproduction Steps:**
1. Go to Event Types settings
2. Create a new event type with recurring pattern (e.g., weekly)
3. Book the recurring event yourself for the next 4 weeks
4. Go back to Event Types and delete the event type
5. Navigate to Bookings > Upcoming
6. The deleted recurring events still appear in the upcoming bookings list
7. Events cannot be cancelled or managed since the event type is deleted

---

## Update Availability After Booking Bug

This bug simulates the scenario where updating user availability after a booking is made doesn't cancel the conflicting booked event.

**Bug Description:**
Once there is any new event booked and after that user changes their availability, the calendar doesn't cancel the booked event.

**Reproduction Steps:**
1. Go to event type and create events
2. Book the event
3. Go to bookings tab
4. The booking is available
5. Update the availability (change working hours or add unavailable time)
6. Go to bookings tab - the booking is still there with older time



28 changes: 28 additions & 0 deletions qa-benchmarks/tickets.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Bug,Description,Steps to reproduce,Difficulty
Newly created event types not appearing in bookings list,"When creating a new event type, it doesn't appear in the bookings list even after bookings are made for it","1) Go to Event Types in settings
2) Create a new event type with a custom name
3) Have someone book the event type
4) Navigate to the Bookings tab
5) The booking for the new event type is not visible in the list",Medium
Booking form validation error persists,"After fixing a validation error in the booking form, the error message remains visible even after the field is corrected","1) Go to a booking page
2) Fill out the form with invalid data (e.g., invalid email format)
3) Submit the form to trigger validation error
4) Correct the invalid data
5) Error message still shows despite valid input",Easy
Timezone selector not updating display time,"When changing timezone in the booking form, the displayed available time slots don't update to reflect the new timezone","1) Open a booking page
2) Change the timezone using the timezone selector
3) Available time slots still show in the original timezone
4) Page refresh is required to see correct times",Medium
Deleted recurring events still showing in upcoming bookings,"After creating a recurring event, booking it yourself, and then deleting the event type, the upcoming section still shows the booked events","1) Go to Event Types settings
2) Create a new event type with recurring pattern (e.g., weekly)
3) Book the recurring event yourself for the next 4 weeks
4) Go back to Event Types and delete the event type
5) Navigate to Bookings > Upcoming
6) The deleted recurring events still appear in the upcoming bookings list
7) Events cannot be cancelled or managed since the event type is deleted",Medium
Update availability of user after booking is done,"Once there is any new event booked and after that user changes their availability, the calendar doesn't cancel the booked event","1) Go to event type and create events
2) Book the event
3) Go to bookings tab
4) The booking is available
5) Update the availability (change working hours or add unavailable time)
6) Go to bookings tab - the booking is still there with older time",Medium