From 6e7103f6d3a5834ab80ac1092aba9c97fa51f51f Mon Sep 17 00:00:00 2001 From: yyh Date: Mon, 2 Mar 2026 19:20:40 +0800 Subject: [PATCH] Revert "test(web): add unit tests for base ui primitive wrappers" This reverts commit 03180ffc2cffbda3eb4e5e6376ba14e35534cc41. --- .../base/ui/dialog/__tests__/index.spec.tsx | 150 -------- .../ui/dropdown-menu/__tests__/index.spec.tsx | 322 ------------------ .../base/ui/popover/__tests__/index.spec.tsx | 187 ---------- .../base/ui/select/__tests__/index.spec.tsx | 263 -------------- .../base/ui/tooltip/__tests__/index.spec.tsx | 219 ------------ 5 files changed, 1141 deletions(-) delete mode 100644 web/app/components/base/ui/dialog/__tests__/index.spec.tsx delete mode 100644 web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx delete mode 100644 web/app/components/base/ui/popover/__tests__/index.spec.tsx delete mode 100644 web/app/components/base/ui/select/__tests__/index.spec.tsx delete mode 100644 web/app/components/base/ui/tooltip/__tests__/index.spec.tsx diff --git a/web/app/components/base/ui/dialog/__tests__/index.spec.tsx b/web/app/components/base/ui/dialog/__tests__/index.spec.tsx deleted file mode 100644 index eb8cb179a6..0000000000 --- a/web/app/components/base/ui/dialog/__tests__/index.spec.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import type { ComponentPropsWithoutRef } from 'react' -import { Dialog as BaseDialog } from '@base-ui/react/dialog' -import { render, screen } from '@testing-library/react' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogTitle, - DialogTrigger, -} from '../index' - -type PrimitiveProps = ComponentPropsWithoutRef<'div'> - -vi.mock('@base-ui/react/dialog', () => { - const createPrimitive = (testId: string) => { - return vi.fn(({ children, ...props }: PrimitiveProps) => ( -
- {children} -
- )) - } - - return { - Dialog: { - Root: createPrimitive('base-dialog-root'), - Trigger: createPrimitive('base-dialog-trigger'), - Title: createPrimitive('base-dialog-title'), - Description: createPrimitive('base-dialog-description'), - Close: createPrimitive('base-dialog-close'), - Portal: createPrimitive('base-dialog-portal'), - Backdrop: createPrimitive('base-dialog-backdrop'), - Popup: createPrimitive('base-dialog-popup'), - }, - } -}) - -describe('Dialog wrapper', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - // Rendering behavior for wrapper-specific structure and content. - describe('Rendering', () => { - it('should render backdrop and popup when DialogContent is rendered', () => { - // Arrange - const contentText = 'dialog body' - - // Act - render( - - {contentText} - , - ) - - // Assert - expect(screen.getByTestId('base-dialog-portal')).toBeInTheDocument() - expect(screen.getByTestId('base-dialog-backdrop')).toBeInTheDocument() - expect(screen.getByTestId('base-dialog-popup')).toBeInTheDocument() - expect(screen.getByText(contentText)).toBeInTheDocument() - }) - - it('should apply default wrapper class names when no override classes are provided', () => { - // Arrange - render( - - content - , - ) - - // Act - const backdrop = screen.getByTestId('base-dialog-backdrop') - const popup = screen.getByTestId('base-dialog-popup') - - // Assert - expect(backdrop).toHaveClass('fixed', 'inset-0', 'z-50', 'bg-background-overlay') - expect(backdrop).toHaveClass('transition-opacity', 'duration-150') - expect(backdrop).toHaveClass('data-[ending-style]:opacity-0', 'data-[starting-style]:opacity-0') - - expect(popup).toHaveClass('fixed', 'left-1/2', 'top-1/2', 'z-50') - expect(popup).toHaveClass('max-h-[80dvh]', 'w-[480px]', 'max-w-[calc(100vw-2rem)]') - expect(popup).toHaveClass('-translate-x-1/2', '-translate-y-1/2') - expect(popup).toHaveClass('rounded-2xl', 'border-[0.5px]', 'bg-components-panel-bg', 'p-6', 'shadow-xl') - expect(popup).toHaveClass('transition-all', 'duration-150') - expect(popup).toHaveClass( - 'data-[ending-style]:scale-95', - 'data-[starting-style]:scale-95', - 'data-[ending-style]:opacity-0', - 'data-[starting-style]:opacity-0', - ) - }) - }) - - // Props behavior for class merging and custom styling. - describe('Props', () => { - it('should merge overlayClassName and className with default classes when overrides are provided', () => { - // Arrange - const overlayClassName = 'custom-overlay opacity-90' - const className = 'custom-popup max-w-[640px]' - - // Act - render( - - content - , - ) - - const backdrop = screen.getByTestId('base-dialog-backdrop') - const popup = screen.getByTestId('base-dialog-popup') - - // Assert - expect(backdrop).toHaveClass('fixed', 'inset-0', 'custom-overlay', 'opacity-90') - expect(popup).toHaveClass('fixed', 'left-1/2', 'custom-popup', 'max-w-[640px]') - expect(popup).not.toHaveClass('max-w-[calc(100vw-2rem)]') - }) - - it('should render children inside popup when children are provided', () => { - // Arrange - const childText = 'child content' - - // Act - render( - -
{childText}
-
, - ) - - const popup = screen.getByTestId('base-dialog-popup') - - // Assert - expect(popup).toContainElement(screen.getByText(childText)) - }) - }) - - // Export mapping ensures wrapper aliases point to base primitives. - describe('Exports', () => { - it('should map dialog aliases to the matching base dialog primitives', () => { - // Arrange - const basePrimitives = BaseDialog - - // Act & Assert - expect(Dialog).toBe(basePrimitives.Root) - expect(DialogTrigger).toBe(basePrimitives.Trigger) - expect(DialogTitle).toBe(basePrimitives.Title) - expect(DialogDescription).toBe(basePrimitives.Description) - expect(DialogClose).toBe(basePrimitives.Close) - }) - }) -}) diff --git a/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx b/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx deleted file mode 100644 index 4ccf74209b..0000000000 --- a/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx +++ /dev/null @@ -1,322 +0,0 @@ -import type { Placement } from '@floating-ui/react' -import { Menu } from '@base-ui/react/menu' -import { render, screen } from '@testing-library/react' -import { parsePlacement } from '@/app/components/base/ui/placement' -import { - DropdownMenu, - DropdownMenuCheckboxItem, - DropdownMenuCheckboxItemIndicator, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuGroupLabel, - DropdownMenuItem, - DropdownMenuPortal, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, - DropdownMenuRadioItemIndicator, - DropdownMenuSeparator, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuTrigger, -} from '../index' - -vi.mock('@base-ui/react/menu', async () => { - const React = await import('react') - - type PrimitiveProps = React.HTMLAttributes & { - children?: React.ReactNode - } - - type PositionerProps = PrimitiveProps & { - side?: string - align?: string - sideOffset?: number - alignOffset?: number - } - - const createPrimitive = (testId: string) => { - const Primitive = React.forwardRef(({ children, ...props }, ref) => { - return React.createElement('div', { ref, 'data-testid': testId, ...props }, children) - }) - Primitive.displayName = testId - return Primitive - } - - const Positioner = React.forwardRef(({ children, side, align, sideOffset, alignOffset, ...props }, ref) => { - return React.createElement( - 'div', - { - ref, - 'data-testid': 'menu-positioner', - 'data-side': side, - 'data-align': align, - 'data-side-offset': sideOffset, - 'data-align-offset': alignOffset, - ...props, - }, - children, - ) - }) - Positioner.displayName = 'menu-positioner' - - const Menu = { - Root: createPrimitive('menu-root'), - Portal: createPrimitive('menu-portal'), - Trigger: createPrimitive('menu-trigger'), - SubmenuRoot: createPrimitive('menu-submenu-root'), - Group: createPrimitive('menu-group'), - GroupLabel: createPrimitive('menu-group-label'), - RadioGroup: createPrimitive('menu-radio-group'), - RadioItem: createPrimitive('menu-radio-item'), - RadioItemIndicator: createPrimitive('menu-radio-item-indicator'), - CheckboxItem: createPrimitive('menu-checkbox-item'), - CheckboxItemIndicator: createPrimitive('menu-checkbox-item-indicator'), - Positioner, - Popup: createPrimitive('menu-popup'), - SubmenuTrigger: createPrimitive('menu-submenu-trigger'), - Item: createPrimitive('menu-item'), - Separator: createPrimitive('menu-separator'), - } - - return { Menu } -}) - -vi.mock('@/app/components/base/ui/placement', () => ({ - parsePlacement: vi.fn((placement: Placement) => { - const [side, align] = placement.split('-') as [string, string | undefined] - return { - side: side as 'top' | 'right' | 'bottom' | 'left', - align: (align ?? 'center') as 'start' | 'center' | 'end', - } - }), -})) - -describe('dropdown-menu wrapper', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - // Ensures exported aliases stay aligned with the wrapped Menu primitives. - describe('alias exports', () => { - it('should map each alias export to the corresponding Menu primitive', () => { - // Arrange - - // Act - - // Assert - expect(DropdownMenu).toBe(Menu.Root) - expect(DropdownMenuPortal).toBe(Menu.Portal) - expect(DropdownMenuTrigger).toBe(Menu.Trigger) - expect(DropdownMenuSub).toBe(Menu.SubmenuRoot) - expect(DropdownMenuGroup).toBe(Menu.Group) - expect(DropdownMenuGroupLabel).toBe(Menu.GroupLabel) - expect(DropdownMenuRadioGroup).toBe(Menu.RadioGroup) - expect(DropdownMenuRadioItem).toBe(Menu.RadioItem) - expect(DropdownMenuRadioItemIndicator).toBe(Menu.RadioItemIndicator) - expect(DropdownMenuCheckboxItem).toBe(Menu.CheckboxItem) - expect(DropdownMenuCheckboxItemIndicator).toBe(Menu.CheckboxItemIndicator) - }) - }) - - describe('DropdownMenuContent', () => { - it('should use default placement and offsets when props are omitted', () => { - // Arrange - const parsePlacementMock = vi.mocked(parsePlacement) - - // Act - render( - - content child - , - ) - - // Assert - const positioner = screen.getByTestId('menu-positioner') - const popup = screen.getByTestId('menu-popup') - - expect(parsePlacementMock).toHaveBeenCalledTimes(1) - expect(parsePlacementMock).toHaveBeenCalledWith('bottom-end') - expect(positioner).toHaveAttribute('data-side', 'bottom') - expect(positioner).toHaveAttribute('data-align', 'end') - expect(positioner).toHaveAttribute('data-side-offset', '4') - expect(positioner).toHaveAttribute('data-align-offset', '0') - expect(positioner).toHaveClass('outline-none') - expect(popup).toHaveClass('rounded-xl') - expect(popup).toHaveClass('py-1') - expect(screen.getByText('content child')).toBeInTheDocument() - }) - - it('should parse custom placement and merge custom class names', () => { - // Arrange - const parsePlacementMock = vi.mocked(parsePlacement) - - // Act - render( - - custom content - , - ) - - // Assert - const positioner = screen.getByTestId('menu-positioner') - const popup = screen.getByTestId('menu-popup') - - expect(parsePlacementMock).toHaveBeenCalledTimes(1) - expect(parsePlacementMock).toHaveBeenCalledWith('top-start') - expect(positioner).toHaveAttribute('data-side', 'top') - expect(positioner).toHaveAttribute('data-align', 'start') - expect(positioner).toHaveAttribute('data-side-offset', '12') - expect(positioner).toHaveAttribute('data-align-offset', '-3') - expect(positioner).toHaveClass('outline-none') - expect(positioner).toHaveClass('content-positioner-custom') - expect(popup).toHaveClass('content-popup-custom') - expect(screen.getByText('custom content')).toBeInTheDocument() - }) - }) - - describe('DropdownMenuSubContent', () => { - it('should use the default sub-content placement and offsets', () => { - // Arrange - const parsePlacementMock = vi.mocked(parsePlacement) - - // Act - render( - - sub content child - , - ) - - // Assert - const positioner = screen.getByTestId('menu-positioner') - expect(parsePlacementMock).toHaveBeenCalledTimes(1) - expect(parsePlacementMock).toHaveBeenCalledWith('left-start') - expect(positioner).toHaveAttribute('data-side', 'left') - expect(positioner).toHaveAttribute('data-align', 'start') - expect(positioner).toHaveAttribute('data-side-offset', '4') - expect(positioner).toHaveAttribute('data-align-offset', '0') - expect(positioner).toHaveClass('outline-none') - expect(screen.getByText('sub content child')).toBeInTheDocument() - }) - - it('should parse custom placement and merge popup class names', () => { - // Arrange - const parsePlacementMock = vi.mocked(parsePlacement) - - // Act - render( - - custom sub content - , - ) - - // Assert - const positioner = screen.getByTestId('menu-positioner') - const popup = screen.getByTestId('menu-popup') - - expect(parsePlacementMock).toHaveBeenCalledTimes(1) - expect(parsePlacementMock).toHaveBeenCalledWith('right-end') - expect(positioner).toHaveAttribute('data-side', 'right') - expect(positioner).toHaveAttribute('data-align', 'end') - expect(positioner).toHaveAttribute('data-side-offset', '6') - expect(positioner).toHaveAttribute('data-align-offset', '2') - expect(positioner).toHaveClass('outline-none') - expect(positioner).toHaveClass('sub-positioner-custom') - expect(popup).toHaveClass('sub-popup-custom') - }) - }) - - describe('DropdownMenuSubTrigger', () => { - it('should merge className and apply destructive style when destructive is true', () => { - // Arrange - - // Act - render( - - Trigger item - , - ) - - // Assert - const subTrigger = screen.getByTestId('menu-submenu-trigger') - expect(subTrigger).toHaveClass('mx-1') - expect(subTrigger).toHaveClass('sub-trigger-custom') - expect(subTrigger).toHaveClass('text-text-destructive') - }) - - it('should not apply destructive style when destructive is false', () => { - // Arrange - - // Act - render( - - Trigger item - , - ) - - // Assert - expect(screen.getByTestId('menu-submenu-trigger')).not.toHaveClass('text-text-destructive') - }) - }) - - describe('DropdownMenuItem', () => { - it('should merge className and apply destructive style when destructive is true', () => { - // Arrange - - // Act - render( - - Item label - , - ) - - // Assert - const item = screen.getByTestId('menu-item') - expect(item).toHaveClass('mx-1') - expect(item).toHaveClass('item-custom') - expect(item).toHaveClass('text-text-destructive') - }) - - it('should not apply destructive style when destructive is false', () => { - // Arrange - - // Act - render( - - Item label - , - ) - - // Assert - expect(screen.getByTestId('menu-item')).not.toHaveClass('text-text-destructive') - }) - }) - - describe('DropdownMenuSeparator', () => { - it('should merge custom class names with default separator classes', () => { - // Arrange - - // Act - render() - - // Assert - const separator = screen.getByTestId('menu-separator') - expect(separator).toHaveClass('my-1') - expect(separator).toHaveClass('h-px') - expect(separator).toHaveClass('bg-divider-regular') - expect(separator).toHaveClass('separator-custom') - }) - }) -}) diff --git a/web/app/components/base/ui/popover/__tests__/index.spec.tsx b/web/app/components/base/ui/popover/__tests__/index.spec.tsx deleted file mode 100644 index d9176e26c0..0000000000 --- a/web/app/components/base/ui/popover/__tests__/index.spec.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import type { Placement } from '@floating-ui/react' -import type { ComponentPropsWithoutRef, ReactNode } from 'react' -import { render, screen } from '@testing-library/react' -import { PopoverContent } from '..' - -type ParsedPlacement = { - side: 'top' | 'bottom' | 'left' | 'right' - align: 'start' | 'center' | 'end' -} - -type PositionerMockProps = ComponentPropsWithoutRef<'div'> & { - side?: ParsedPlacement['side'] - align?: ParsedPlacement['align'] - sideOffset?: number - alignOffset?: number -} - -const positionerPropsSpy = vi.fn<(props: PositionerMockProps) => void>() -const popupClassNameSpy = vi.fn<(className: string | undefined) => void>() -const parsePlacementMock = vi.fn<(placement: Placement) => ParsedPlacement>() - -vi.mock('@base-ui/react/popover', () => { - const Root = ({ children, ...props }: ComponentPropsWithoutRef<'div'>) => ( -
{children}
- ) - - const Trigger = ({ children, ...props }: ComponentPropsWithoutRef<'button'>) => ( - - ) - - const Close = ({ children, ...props }: ComponentPropsWithoutRef<'button'>) => ( - - ) - - const Title = ({ children, ...props }: ComponentPropsWithoutRef<'h2'>) => ( -

{children}

- ) - - const Description = ({ children, ...props }: ComponentPropsWithoutRef<'p'>) => ( -

{children}

- ) - - const Portal = ({ children }: { children?: ReactNode }) => ( -
{children}
- ) - - const Positioner = ({ children, ...props }: PositionerMockProps) => { - positionerPropsSpy(props) - return ( -
- {children} -
- ) - } - - const Popup = ({ children, className }: ComponentPropsWithoutRef<'div'>) => { - popupClassNameSpy(className) - return ( -
- {children} -
- ) - } - - return { - Popover: { - Root, - Trigger, - Close, - Title, - Description, - Portal, - Positioner, - Popup, - }, - } -}) - -vi.mock('@/app/components/base/ui/placement', () => ({ - parsePlacement: (placement: Placement) => parsePlacementMock(placement), -})) - -describe('PopoverContent', () => { - beforeEach(() => { - vi.clearAllMocks() - parsePlacementMock.mockReturnValue({ - side: 'bottom', - align: 'center', - }) - }) - - describe('Default props', () => { - it('should use bottom placement and default offsets when optional props are not provided', () => { - // Arrange - render( - - Default content - , - ) - - // Act - const positioner = screen.getByTestId('mock-positioner') - - // Assert - expect(parsePlacementMock).toHaveBeenCalledTimes(1) - expect(parsePlacementMock).toHaveBeenCalledWith('bottom') - expect(positionerPropsSpy).toHaveBeenCalledWith( - expect.objectContaining({ - side: 'bottom', - align: 'center', - sideOffset: 8, - alignOffset: 0, - }), - ) - expect(positioner).toHaveClass('outline-none') - expect(screen.getByText('Default content')).toBeInTheDocument() - }) - }) - - describe('Placement parsing', () => { - it('should use parsePlacement output and forward custom placement offsets to Positioner', () => { - // Arrange - parsePlacementMock.mockReturnValue({ - side: 'left', - align: 'end', - }) - - // Act - render( - - Parsed content - , - ) - - // Assert - expect(parsePlacementMock).toHaveBeenCalledTimes(1) - expect(parsePlacementMock).toHaveBeenCalledWith('top-end') - expect(positionerPropsSpy).toHaveBeenCalledWith( - expect.objectContaining({ - side: 'left', - align: 'end', - sideOffset: 14, - alignOffset: 6, - }), - ) - }) - }) - - describe('ClassName behavior', () => { - it('should merge custom className values into Positioner and Popup class names', () => { - // Arrange - render( - - Styled content - , - ) - - // Act - const positioner = screen.getByTestId('mock-positioner') - const popup = screen.getByTestId('mock-popup') - - // Assert - expect(positioner).toHaveClass('outline-none') - expect(positioner).toHaveClass('custom-positioner') - expect(popup).toHaveClass('rounded-xl') - expect(popup).toHaveClass('custom-popup') - expect(popupClassNameSpy).toHaveBeenCalledWith(expect.stringContaining('custom-popup')) - }) - }) - - describe('Children rendering', () => { - it('should render children inside Popup', () => { - // Arrange - render( - - - , - ) - - // Act - const popup = screen.getByTestId('mock-popup') - - // Assert - expect(popup).toContainElement(screen.getByRole('button', { name: 'Child action' })) - }) - }) -}) diff --git a/web/app/components/base/ui/select/__tests__/index.spec.tsx b/web/app/components/base/ui/select/__tests__/index.spec.tsx deleted file mode 100644 index 386b25c4f2..0000000000 --- a/web/app/components/base/ui/select/__tests__/index.spec.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import type { Placement } from '@floating-ui/react' -import type { - ButtonHTMLAttributes, - HTMLAttributes, - ReactNode, -} from 'react' -import { render, screen } from '@testing-library/react' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { - SelectContent, - SelectItem, - SelectTrigger, -} from '../index' - -type ParsedPlacement = { - side: 'top' | 'bottom' | 'left' | 'right' - align: 'start' | 'center' | 'end' -} - -const { mockParsePlacement } = vi.hoisted(() => ({ - mockParsePlacement: vi.fn<(placement: Placement) => ParsedPlacement>(), -})) - -vi.mock('@/app/components/base/ui/placement', () => ({ - parsePlacement: mockParsePlacement, -})) - -vi.mock('@base-ui/react/select', () => { - type WithChildren = { children?: ReactNode } - type PositionerProps = HTMLAttributes & { - side?: 'top' | 'bottom' | 'left' | 'right' - align?: 'start' | 'center' | 'end' - sideOffset?: number - alignOffset?: number - } - - const Root = ({ children }: WithChildren) =>
{children}
- const Value = ({ children }: WithChildren) => {children} - const Group = ({ children }: WithChildren) =>
{children}
- const GroupLabel = ({ children }: WithChildren) =>
{children}
- const Separator = (props: HTMLAttributes) =>
- - const Trigger = ({ children, ...props }: ButtonHTMLAttributes) => ( - - ) - const Icon = ({ children, ...props }: HTMLAttributes) => ( - - {children} - - ) - - const Portal = ({ children }: WithChildren) =>
{children}
- const Positioner = ({ - children, - side, - align, - sideOffset, - alignOffset, - className, - ...props - }: PositionerProps) => ( -
- {children} -
- ) - const Popup = ({ children, ...props }: HTMLAttributes) => ( -
- {children} -
- ) - const List = ({ children, ...props }: HTMLAttributes) => ( -
- {children} -
- ) - - const Item = ({ children, ...props }: HTMLAttributes) => ( -
- {children} -
- ) - const ItemText = ({ children, ...props }: HTMLAttributes) => ( - - {children} - - ) - const ItemIndicator = ({ children, ...props }: HTMLAttributes) => ( - - {children} - - ) - - return { - Select: { - Root, - Value, - Group, - GroupLabel, - Separator, - Trigger, - Icon, - Portal, - Positioner, - Popup, - List, - Item, - ItemText, - ItemIndicator, - }, - } -}) - -describe('Select wrappers', () => { - beforeEach(() => { - vi.clearAllMocks() - mockParsePlacement.mockReturnValue({ side: 'bottom', align: 'start' }) - }) - - // Covers trigger-level wrapper behavior. - describe('SelectTrigger', () => { - it('should forward trigger props when trigger props are provided', () => { - // Arrange - render( - - Trigger Label - , - ) - - // Assert - const trigger = screen.getByTestId('custom-trigger') - expect(trigger).toBeDisabled() - expect(trigger).toHaveAttribute('aria-label', 'Choose option') - expect(trigger).toHaveAttribute('data-testid', 'custom-trigger') - }) - - it('should compose default and custom class names when className is provided', () => { - // Arrange & Act - render(Trigger Label) - - // Assert - const trigger = screen.getByTestId('base-select-trigger') - expect(trigger).toHaveClass('group') - expect(trigger).toHaveClass('h-8') - expect(trigger).toHaveClass('custom-trigger-class') - }) - - it('should render children and icon when content is provided', () => { - // Arrange & Act - render(Trigger Label) - - // Assert - expect(screen.getByText('Trigger Label')).toBeInTheDocument() - expect(screen.getByTestId('base-select-icon')).toBeInTheDocument() - }) - }) - - // Covers content placement parsing and positioner forwarding. - describe('SelectContent', () => { - it('should call parsePlacement with default placement when placement is not provided', () => { - // Arrange - mockParsePlacement.mockReturnValueOnce({ side: 'bottom', align: 'start' }) - - // Act - render(
Option A
) - - // Assert - expect(mockParsePlacement).toHaveBeenCalledWith('bottom-start') - }) - - it('should pass parsed side align and offsets to Positioner when custom placement and offsets are provided', () => { - // Arrange - mockParsePlacement.mockReturnValueOnce({ side: 'top', align: 'end' }) - - // Act - render( - -
Option A
-
, - ) - - // Assert - const positioner = screen.getByTestId('base-select-positioner') - expect(mockParsePlacement).toHaveBeenCalledWith('top-end') - expect(positioner).toHaveAttribute('data-side', 'top') - expect(positioner).toHaveAttribute('data-align', 'end') - expect(positioner).toHaveAttribute('data-side-offset', '12') - expect(positioner).toHaveAttribute('data-align-offset', '6') - }) - - it('should compose positioner popup and list class names when custom class props are provided', () => { - // Arrange & Act - render( - -
Option A
-
, - ) - - // Assert - expect(screen.getByTestId('base-select-positioner')).toHaveClass('outline-none', 'custom-positioner') - expect(screen.getByTestId('base-select-popup')).toHaveClass('rounded-xl', 'custom-popup') - expect(screen.getByTestId('base-select-list')).toHaveClass('max-h-80', 'custom-list') - }) - - it('should render children inside list when children are provided', () => { - // Arrange & Act - render( - - Option A - , - ) - - // Assert - const list = screen.getByTestId('base-select-list') - expect(list).toContainElement(screen.getByTestId('list-child')) - }) - }) - - // Covers option item wrapper behavior. - describe('SelectItem', () => { - it('should forward props and compose class names when item props are provided', () => { - // Arrange & Act - render( - - Seattle - , - ) - - // Assert - const item = screen.getByTestId('city-option-item') - expect(item).toHaveAttribute('aria-label', 'City option') - expect(item).toHaveAttribute('data-testid', 'city-option-item') - expect(item).toHaveClass('h-8') - expect(item).toHaveClass('custom-item-class') - }) - - it('should render item text and indicator when children are provided', () => { - // Arrange & Act - render(Seattle) - - // Assert - expect(screen.getByTestId('base-select-item-text')).toHaveTextContent('Seattle') - expect(screen.getByTestId('base-select-item-indicator')).toBeInTheDocument() - }) - }) -}) diff --git a/web/app/components/base/ui/tooltip/__tests__/index.spec.tsx b/web/app/components/base/ui/tooltip/__tests__/index.spec.tsx deleted file mode 100644 index 3432b19eaa..0000000000 --- a/web/app/components/base/ui/tooltip/__tests__/index.spec.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import type { Placement } from '@floating-ui/react' -import type { HTMLAttributes, ReactNode } from 'react' -import { Tooltip as BaseTooltip } from '@base-ui/react/tooltip' -import { render, screen } from '@testing-library/react' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { parsePlacement } from '@/app/components/base/ui/placement' -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../index' - -type MockPortalProps = { - children: ReactNode -} - -type MockPositionerProps = { - children: ReactNode - side: string - align: string - sideOffset: number - alignOffset: number - className?: string -} - -type MockPopupProps = HTMLAttributes & { - children: ReactNode - className?: string -} - -vi.mock('@/app/components/base/ui/placement', () => ({ - parsePlacement: vi.fn(), -})) - -vi.mock('@base-ui/react/tooltip', () => ({ - Tooltip: { - Portal: ({ children }: MockPortalProps) => ( -
{children}
- ), - Positioner: ({ - children, - side, - align, - sideOffset, - alignOffset, - className, - }: MockPositionerProps) => ( -
- {children} -
- ), - Popup: ({ children, className, ...props }: MockPopupProps) => ( -
- {children} -
- ), - Provider: ({ children }: MockPortalProps) => ( -
{children}
- ), - Root: ({ children }: MockPortalProps) => ( -
{children}
- ), - Trigger: ({ children }: MockPortalProps) => ( - - ), - }, -})) - -const mockParsePlacement = vi.mocked(parsePlacement) - -describe('TooltipContent', () => { - beforeEach(() => { - vi.clearAllMocks() - mockParsePlacement.mockReturnValue({ side: 'top', align: 'center' }) - }) - - describe('Placement and offsets', () => { - it('should use default placement and offsets when optional props are not provided', () => { - // Arrange - render(Tooltip body) - - // Act - const positioner = screen.getByTestId('tooltip-positioner') - - // Assert - expect(mockParsePlacement).toHaveBeenCalledWith('top') - expect(positioner).toHaveAttribute('data-side', 'top') - expect(positioner).toHaveAttribute('data-align', 'center') - expect(positioner).toHaveAttribute('data-side-offset', '8') - expect(positioner).toHaveAttribute('data-align-offset', '0') - }) - - it('should use parsed placement and custom offsets when placement props are provided', () => { - // Arrange - mockParsePlacement.mockReturnValue({ side: 'bottom', align: 'start' }) - const customPlacement: Placement = 'bottom-start' - - // Act - render( - - Tooltip body - , - ) - const positioner = screen.getByTestId('tooltip-positioner') - - // Assert - expect(mockParsePlacement).toHaveBeenCalledWith(customPlacement) - expect(positioner).toHaveAttribute('data-side', 'bottom') - expect(positioner).toHaveAttribute('data-align', 'start') - expect(positioner).toHaveAttribute('data-side-offset', '16') - expect(positioner).toHaveAttribute('data-align-offset', '6') - }) - }) - - describe('Class behavior', () => { - it('should merge the positioner className with wrapper base class', () => { - // Arrange - render(Tooltip body) - - // Act - const positioner = screen.getByTestId('tooltip-positioner') - - // Assert - expect(positioner).toHaveClass('outline-none') - expect(positioner).toHaveClass('custom-positioner') - }) - - it('should apply default variant popup classes and merge popupClassName when variant is default', () => { - // Arrange - render( - - Tooltip body - , - ) - - // Act - const popup = screen.getByTestId('tooltip-popup') - - // Assert - expect(popup.className).toContain('bg-components-panel-bg') - expect(popup.className).toContain('rounded-md') - expect(popup).toHaveClass('custom-popup') - }) - - it('should avoid default variant popup classes when variant is plain', () => { - // Arrange - render( - - Tooltip body - , - ) - - // Act - const popup = screen.getByTestId('tooltip-popup') - - // Assert - expect(popup).toHaveClass('plain-popup') - expect(popup.className).not.toContain('bg-components-panel-bg') - expect(popup.className).not.toContain('rounded-md') - }) - }) - - describe('Popup prop forwarding', () => { - it('should forward popup props to BaseTooltip.Popup when popup props are provided', () => { - // Arrange - render( - - Tooltip body - , - ) - - // Act - const popup = screen.getByTestId('tooltip-popup') - - // Assert - expect(popup).toHaveAttribute('id', 'popup-id') - expect(popup).toHaveAttribute('role', 'tooltip') - expect(popup).toHaveAttribute('aria-label', 'help text') - expect(popup).toHaveAttribute('data-track-id', 'tooltip-track') - }) - }) -}) - -describe('Tooltip aliases', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - it('should map alias exports to BaseTooltip components when wrapper exports are imported', () => { - // Arrange - const provider = BaseTooltip.Provider - const root = BaseTooltip.Root - const trigger = BaseTooltip.Trigger - - // Act - const exportedProvider = TooltipProvider - const exportedTooltip = Tooltip - const exportedTrigger = TooltipTrigger - - // Assert - expect(exportedProvider).toBe(provider) - expect(exportedTooltip).toBe(root) - expect(exportedTrigger).toBe(trigger) - }) -})