diff --git a/web/app/components/base/ui/dialog/__tests__/index.spec.tsx b/web/app/components/base/ui/dialog/__tests__/index.spec.tsx
new file mode 100644
index 0000000000..eb8cb179a6
--- /dev/null
+++ b/web/app/components/base/ui/dialog/__tests__/index.spec.tsx
@@ -0,0 +1,150 @@
+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
new file mode 100644
index 0000000000..4ccf74209b
--- /dev/null
+++ b/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx
@@ -0,0 +1,322 @@
+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
new file mode 100644
index 0000000000..d9176e26c0
--- /dev/null
+++ b/web/app/components/base/ui/popover/__tests__/index.spec.tsx
@@ -0,0 +1,187 @@
+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
new file mode 100644
index 0000000000..386b25c4f2
--- /dev/null
+++ b/web/app/components/base/ui/select/__tests__/index.spec.tsx
@@ -0,0 +1,263 @@
+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
new file mode 100644
index 0000000000..3432b19eaa
--- /dev/null
+++ b/web/app/components/base/ui/tooltip/__tests__/index.spec.tsx
@@ -0,0 +1,219 @@
+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(
+ ,
+ )
+
+ // 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)
+ })
+})