Files
calendar/apps/web/playwright/system-segments.e2e.ts
T
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2266301469 feat: implement system filter segments for data tables (#22939)
* feat: implement default filter segments for data tables

- Add defaultSegmentId column to UserFilterSegmentPreference table
- Support mixed segment ID types (number for user segments, string for default segments)
- Add DefaultFilterSegment and CombinedFilterSegment types
- Update useSegments hook to handle default segments with date range recalculation
- Modify FilterSegmentSelect to group and display default segments separately
- Add default segments to bookings view (My Bookings, Upcoming Bookings)
- Prevent editing/deleting of default segments in SaveFilterSegmentButton
- Update DataTableProvider to support defaultSegments prop
- Update parsers and repository to handle mixed segment ID types

Implements frontend-only default segments as specified in the requirements.

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* chore: update ESLint dependencies to resolve configuration issues

- Update eslint-config-next and @typescript-eslint packages to latest versions
- Fix dependency compatibility issues that were blocking pre-commit hooks

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* revert eslint change

* some changes

* refactor: implement discriminated union for segment types

- Update SegmentIdentifier to use discriminated union with 'custom' vs 'default' types
- Refactor setSegmentId to accept object parameters: { id: string; type: 'default' } | { id: number; type: 'custom' }
- Update type definitions with DefaultFilterSegment, CustomFilterSegment, and CombinedFilterSegment
- Modify useSegments hook to handle new segment type structure
- Update FilterSegmentSelect component to work with discriminated unions
- Refactor database preference handling to store segment type alongside ID
- Add proper type safety throughout the data flow
- Remove description property from DefaultFilterSegment type

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: update unit test to expect discriminated union format for preferredSegmentId

The test was expecting preferredSegmentId to be a number, but after the discriminated union refactor it now returns { id: number, type: 'custom' } for custom segments. Updated the assertion to use toEqual() for deep object comparison.

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: correct SegmentIdentifier type to exclude undefined

- Remove null from SegmentIdentifier type definition since null/undefined indicate absence of identifier
- Update DataTableProvider and useSegments to handle SegmentIdentifier | null properly
- Fix type safety while maintaining discriminated union functionality
- Ensure setAndPersistSegmentId accepts null values for clearing segments

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* remove unused segment

* a little update

* feat: add default- prefix to default segment IDs for clearer type identification

- Update 'my_bookings' to 'default-my_bookings'
- Update 'upcoming-bookings' to 'default-upcoming-bookings'
- Makes it easier to verify segment type by looking at the ID string
- Maintains all existing discriminated union functionality

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: rename segment types from default/custom to system/user for better semantics

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: update unit test to expect 'user' type instead of 'custom' in discriminated union

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: complete type renaming from default/custom to system/user across all component files

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: update segment ID prefix from default- to system- to match type naming

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* remove unused segment

* some fixes

* revert schema change

* rename defaultSegmentId to systemSegmentId

* renaming

* fix save button

* remove as any

* clean up prisma migrations

* type fixes

* many fixes

* remove icon property

* fix infinite rendering

* fix race condition

* re-visiting useSegments implementation WIP

* extract useElementByClassName

* add e2e tests

* fix a bug that the created segment was not selected automatically

* add useSegments to /insights and fix e2e test

* fix type error

* fix type error

* apply feedback

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-08-22 10:18:18 +03:00

121 lines
4.2 KiB
TypeScript

import { expect } from "@playwright/test";
import type { Page } from "@playwright/test";
import { addFilter, selectSegment, expectSegmentCleared, expectSegmentSelected } from "./filter-helpers";
import { test } from "./lib/fixtures";
test.describe.configure({ mode: "parallel" });
test.afterEach(async ({ users }) => {
await users.deleteAll();
});
/**
* Navigate to bookings page with specific status
*/
async function navigateToBookings(page: Page, status = "upcoming") {
// Wait for the bookings API response like existing tests do
const bookingsGetResponse = page.waitForResponse((response) =>
/\/api\/trpc\/bookings\/get.*/.test(response.url())
);
await page.goto(`/bookings/${status}`, { waitUntil: "domcontentloaded" });
await bookingsGetResponse;
}
test.describe("System Segments", () => {
test.describe("Core Functionality", () => {
test("My Bookings system segment filters to current user's bookings only", async ({ page, users }) => {
const user1 = await users.create({ username: "user1" });
// Create some bookings for user (this would need booking setup)
// For now, we'll test the filter application
await user1.apiLogin();
await navigateToBookings(page);
await selectSegment(page, "My Bookings");
await expectSegmentSelected(page, "My Bookings");
// Verify the userId filter is applied (check URL or filter indicators)
const url = page.url();
expect(url).toContain("activeFilters");
});
test("System segments show only Duplicate option in submenu", async ({ page, users }) => {
const user = await users.create();
await user.apiLogin();
await navigateToBookings(page);
await page.getByTestId("filter-segment-select").click();
await page
.locator('[data-testid="filter-segment-select-content"] [role="menuitem"]')
.filter({ hasText: "My Bookings" })
.locator('[data-testid="filter-segment-select-submenu-button"]')
.click();
const submenu = page.getByTestId("filter-segment-select-submenu-content");
await expect(submenu.getByText("Duplicate")).toBeVisible();
await expect(submenu.getByText("Rename")).toBeHidden();
await expect(submenu.getByText("Delete")).toBeHidden();
});
});
test.describe("State Persistence", () => {
test("System segment selection persists across page visits", async ({ page, users }) => {
const owner = await users.create(undefined, { hasTeam: true });
await owner.apiLogin();
// Visit bookings page and select system segment
await navigateToBookings(page);
await selectSegment(page, "My Bookings");
await expectSegmentSelected(page, "My Bookings");
// Revisit the page - should preserve selection
await navigateToBookings(page);
await expectSegmentSelected(page, "My Bookings");
});
test("Cleared system segment state persists (no default selection after manual clear)", async ({
page,
users,
}) => {
const owner = await users.create(undefined, { hasTeam: true });
await owner.apiLogin();
await navigateToBookings(page);
// Select system segment
await selectSegment(page, "My Bookings");
await expectSegmentSelected(page, "My Bookings");
// Unselect system segment
await selectSegment(page, "My Bookings");
// Revisit the page - should NOT have any segment selected
await navigateToBookings(page);
await expectSegmentCleared(page);
});
});
test.describe("Auto-clear Behavior", () => {
test("Manual filter clears system segment selection", async ({ page, users }) => {
const user = await users.create(undefined, { hasTeam: true });
await user.apiLogin();
await navigateToBookings(page);
// Select system segment
await selectSegment(page, "My Bookings");
await expectSegmentSelected(page, "My Bookings");
// Apply manual filter - this should clear system segment
await addFilter(page, "eventTypeId");
await page.keyboard.press("Escape");
await expectSegmentCleared(page);
// Verify filter is still applied
await expect(page.getByTestId("filter-popover-trigger-eventTypeId")).toBeVisible();
});
});
});