test(web): add high-quality unit tests for Base UI wrapper primitives (#32904)

This commit is contained in:
yyh 2026-03-03 18:21:33 +08:00 committed by GitHub
parent 7f67e1a2fc
commit 3a8ff301fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 785 additions and 0 deletions

View File

@ -0,0 +1,70 @@
import { Dialog as BaseDialog } from '@base-ui/react/dialog'
import { render, screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest'
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogTitle,
DialogTrigger,
} from '../index'
describe('Dialog wrapper', () => {
describe('Rendering', () => {
it('should render dialog content when dialog is open', () => {
render(
<Dialog open>
<DialogContent>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Description</DialogDescription>
</DialogContent>
</Dialog>,
)
const dialog = screen.getByRole('dialog')
expect(dialog).toHaveTextContent('Dialog Title')
expect(dialog).toHaveTextContent('Dialog Description')
})
})
describe('Props', () => {
it('should not render close button when closable is omitted', () => {
render(
<Dialog open>
<DialogContent>
<span>Dialog body</span>
</DialogContent>
</Dialog>,
)
expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument()
})
it('should render close button when closable is true', () => {
render(
<Dialog open>
<DialogContent closable>
<span>Dialog body</span>
</DialogContent>
</Dialog>,
)
const dialog = screen.getByRole('dialog')
const closeButton = screen.getByRole('button', { name: 'Close' })
expect(dialog).toContainElement(closeButton)
expect(closeButton).toHaveAttribute('aria-label', 'Close')
})
})
describe('Exports', () => {
it('should map dialog aliases to the matching base dialog primitives', () => {
expect(Dialog).toBe(BaseDialog.Root)
expect(DialogTrigger).toBe(BaseDialog.Trigger)
expect(DialogTitle).toBe(BaseDialog.Title)
expect(DialogDescription).toBe(BaseDialog.Description)
expect(DialogClose).toBe(BaseDialog.Close)
})
})
})

View File

@ -0,0 +1,294 @@
import { Menu } from '@base-ui/react/menu'
import { fireEvent, render, screen, within } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from '../index'
describe('dropdown-menu wrapper', () => {
describe('alias exports', () => {
it('should map direct aliases to the corresponding Menu primitive when importing menu roots', () => {
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(DropdownMenuRadioGroup).toBe(Menu.RadioGroup)
})
})
describe('DropdownMenuContent', () => {
it('should position content at bottom-end with default placement when props are omitted', () => {
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent positionerProps={{ 'role': 'group', 'aria-label': 'content positioner' }}>
<DropdownMenuItem>Content action</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>,
)
const positioner = screen.getByRole('group', { name: 'content positioner' })
const popup = screen.getByRole('menu')
expect(positioner).toHaveAttribute('data-side', 'bottom')
expect(positioner).toHaveAttribute('data-align', 'end')
expect(within(popup).getByRole('menuitem', { name: 'Content action' })).toBeInTheDocument()
})
it('should apply custom placement when custom positioning props are provided', () => {
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent
placement="top-start"
sideOffset={12}
alignOffset={-3}
positionerProps={{ 'role': 'group', 'aria-label': 'custom content positioner' }}
>
<DropdownMenuItem>Custom content</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>,
)
const positioner = screen.getByRole('group', { name: 'custom content positioner' })
const popup = screen.getByRole('menu')
expect(positioner).toHaveAttribute('data-side', 'top')
expect(positioner).toHaveAttribute('data-align', 'start')
expect(within(popup).getByRole('menuitem', { name: 'Custom content' })).toBeInTheDocument()
})
it('should forward passthrough attributes and handlers when positionerProps and popupProps are provided', () => {
const handlePositionerMouseEnter = vi.fn()
const handlePopupClick = vi.fn()
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent
positionerProps={{
'role': 'group',
'aria-label': 'dropdown content positioner',
'id': 'dropdown-content-positioner',
'onMouseEnter': handlePositionerMouseEnter,
}}
popupProps={{
role: 'menu',
id: 'dropdown-content-popup',
onClick: handlePopupClick,
}}
>
<DropdownMenuItem>Passthrough content</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>,
)
const positioner = screen.getByRole('group', { name: 'dropdown content positioner' })
const popup = screen.getByRole('menu')
fireEvent.mouseEnter(positioner)
fireEvent.click(popup)
expect(positioner).toHaveAttribute('id', 'dropdown-content-positioner')
expect(popup).toHaveAttribute('id', 'dropdown-content-popup')
expect(handlePositionerMouseEnter).toHaveBeenCalledTimes(1)
expect(handlePopupClick).toHaveBeenCalledTimes(1)
})
})
describe('DropdownMenuSubContent', () => {
it('should position sub-content at left-start with default placement when props are omitted', () => {
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuSub open>
<DropdownMenuSubTrigger>More actions</DropdownMenuSubTrigger>
<DropdownMenuSubContent positionerProps={{ 'role': 'group', 'aria-label': 'sub positioner' }}>
<DropdownMenuItem>Sub action</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>,
)
const positioner = screen.getByRole('group', { name: 'sub positioner' })
expect(positioner).toHaveAttribute('data-side', 'left')
expect(positioner).toHaveAttribute('data-align', 'start')
expect(screen.getByRole('menuitem', { name: 'Sub action' })).toBeInTheDocument()
})
it('should apply custom placement and forward passthrough props for sub-content when custom props are provided', () => {
const handlePositionerFocus = vi.fn()
const handlePopupClick = vi.fn()
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuSub open>
<DropdownMenuSubTrigger>More actions</DropdownMenuSubTrigger>
<DropdownMenuSubContent
placement="right-end"
sideOffset={6}
alignOffset={2}
positionerProps={{
'role': 'group',
'aria-label': 'dropdown sub positioner',
'id': 'dropdown-sub-positioner',
'onFocus': handlePositionerFocus,
}}
popupProps={{
role: 'menu',
id: 'dropdown-sub-popup',
onClick: handlePopupClick,
}}
>
<DropdownMenuItem>Custom sub action</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>,
)
const positioner = screen.getByRole('group', { name: 'dropdown sub positioner' })
const popup = screen.getByRole('menu', { name: 'More actions' })
fireEvent.focus(positioner)
fireEvent.click(popup)
expect(positioner).toHaveAttribute('data-side', 'right')
expect(positioner).toHaveAttribute('data-align', 'end')
expect(positioner).toHaveAttribute('id', 'dropdown-sub-positioner')
expect(popup).toHaveAttribute('id', 'dropdown-sub-popup')
expect(handlePositionerFocus).toHaveBeenCalledTimes(1)
expect(handlePopupClick).toHaveBeenCalledTimes(1)
})
})
describe('DropdownMenuSubTrigger', () => {
it('should render submenu trigger content when trigger children are provided', () => {
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuSub open>
<DropdownMenuSubTrigger>Trigger item</DropdownMenuSubTrigger>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>,
)
expect(screen.getByRole('menuitem', { name: 'Trigger item' })).toBeInTheDocument()
})
it.each([true, false])('should remain interactive and not leak destructive prop when destructive is %s', (destructive) => {
const handleClick = vi.fn()
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuSub open>
<DropdownMenuSubTrigger
destructive={destructive}
aria-label="submenu action"
id={`submenu-trigger-${String(destructive)}`}
onClick={handleClick}
>
Trigger item
</DropdownMenuSubTrigger>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>,
)
const subTrigger = screen.getByRole('menuitem', { name: 'submenu action' })
fireEvent.click(subTrigger)
expect(subTrigger).toHaveAttribute('id', `submenu-trigger-${String(destructive)}`)
expect(subTrigger).not.toHaveAttribute('destructive')
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
describe('DropdownMenuItem', () => {
it.each([true, false])('should remain interactive and not leak destructive prop when destructive is %s', (destructive) => {
const handleClick = vi.fn()
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
destructive={destructive}
aria-label="menu action"
id={`menu-item-${String(destructive)}`}
onClick={handleClick}
>
Item label
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>,
)
const item = screen.getByRole('menuitem', { name: 'menu action' })
fireEvent.click(item)
expect(item).toHaveAttribute('id', `menu-item-${String(destructive)}`)
expect(item).not.toHaveAttribute('destructive')
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
describe('DropdownMenuSeparator', () => {
it('should forward passthrough props and handlers when separator props are provided', () => {
const handleMouseEnter = vi.fn()
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuSeparator
aria-label="actions divider"
id="menu-separator"
onMouseEnter={handleMouseEnter}
/>
</DropdownMenuContent>
</DropdownMenu>,
)
const separator = screen.getByRole('separator', { name: 'actions divider' })
fireEvent.mouseEnter(separator)
expect(separator).toHaveAttribute('id', 'menu-separator')
expect(handleMouseEnter).toHaveBeenCalledTimes(1)
})
it('should keep surrounding menu rows rendered when separator is placed between items', () => {
render(
<DropdownMenu open>
<DropdownMenuTrigger aria-label="menu trigger">Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>First action</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Second action</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>,
)
expect(screen.getByRole('menuitem', { name: 'First action' })).toBeInTheDocument()
expect(screen.getByRole('menuitem', { name: 'Second action' })).toBeInTheDocument()
expect(screen.getAllByRole('separator')).toHaveLength(1)
})
})
})

View File

@ -0,0 +1,107 @@
import { Popover as BasePopover } from '@base-ui/react/popover'
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import {
Popover,
PopoverClose,
PopoverContent,
PopoverDescription,
PopoverTitle,
PopoverTrigger,
} from '..'
describe('PopoverContent', () => {
describe('Placement', () => {
it('should use bottom placement and default offsets when placement props are not provided', () => {
render(
<Popover open>
<PopoverTrigger aria-label="popover trigger">Open</PopoverTrigger>
<PopoverContent
positionerProps={{ 'role': 'group', 'aria-label': 'default positioner' }}
popupProps={{ 'role': 'dialog', 'aria-label': 'default popover' }}
>
<span>Default content</span>
</PopoverContent>
</Popover>,
)
const positioner = screen.getByRole('group', { name: 'default positioner' })
const popup = screen.getByRole('dialog', { name: 'default popover' })
expect(positioner).toHaveAttribute('data-side', 'bottom')
expect(positioner).toHaveAttribute('data-align', 'center')
expect(popup).toHaveTextContent('Default content')
})
it('should apply parsed custom placement and custom offsets when placement props are provided', () => {
render(
<Popover open>
<PopoverTrigger aria-label="popover trigger">Open</PopoverTrigger>
<PopoverContent
placement="top-end"
sideOffset={14}
alignOffset={6}
positionerProps={{ 'role': 'group', 'aria-label': 'custom positioner' }}
popupProps={{ 'role': 'dialog', 'aria-label': 'custom popover' }}
>
<span>Custom placement content</span>
</PopoverContent>
</Popover>,
)
const positioner = screen.getByRole('group', { name: 'custom positioner' })
const popup = screen.getByRole('dialog', { name: 'custom popover' })
expect(positioner).toHaveAttribute('data-side', 'top')
expect(positioner).toHaveAttribute('data-align', 'end')
expect(popup).toHaveTextContent('Custom placement content')
})
})
describe('Passthrough props', () => {
it('should forward positionerProps and popupProps when passthrough props are provided', () => {
const onPopupClick = vi.fn()
render(
<Popover open>
<PopoverTrigger aria-label="popover trigger">Open</PopoverTrigger>
<PopoverContent
positionerProps={{
'role': 'group',
'aria-label': 'popover positioner',
'id': 'popover-positioner-id',
}}
popupProps={{
'id': 'popover-popup-id',
'role': 'dialog',
'aria-label': 'popover content',
'onClick': onPopupClick,
}}
>
<span>Popover body</span>
</PopoverContent>
</Popover>,
)
const positioner = screen.getByRole('group', { name: 'popover positioner' })
const popup = screen.getByRole('dialog', { name: 'popover content' })
fireEvent.click(popup)
expect(positioner).toHaveAttribute('id', 'popover-positioner-id')
expect(popup).toHaveAttribute('id', 'popover-popup-id')
expect(onPopupClick).toHaveBeenCalledTimes(1)
})
})
})
describe('Popover aliases', () => {
describe('Export mapping', () => {
it('should map aliases to the matching base popover primitives when wrapper exports are imported', () => {
expect(Popover).toBe(BasePopover.Root)
expect(PopoverTrigger).toBe(BasePopover.Trigger)
expect(PopoverClose).toBe(BasePopover.Close)
expect(PopoverTitle).toBe(BasePopover.Title)
expect(PopoverDescription).toBe(BasePopover.Description)
})
})
})

View File

@ -0,0 +1,219 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../index'
const renderOpenSelect = ({
triggerProps = {},
contentProps = {},
onValueChange,
}: {
triggerProps?: Record<string, unknown>
contentProps?: Record<string, unknown>
onValueChange?: (value: string | null) => void
} = {}) => {
return render(
<Select open defaultValue="seattle" onValueChange={onValueChange}>
<SelectTrigger aria-label="city select" {...triggerProps}>
<SelectValue />
</SelectTrigger>
<SelectContent
positionerProps={{
'role': 'group',
'aria-label': 'select positioner',
}}
popupProps={{
'role': 'dialog',
'aria-label': 'select popup',
}}
listProps={{
'role': 'listbox',
'aria-label': 'select list',
}}
{...contentProps}
>
<SelectItem value="seattle">Seattle</SelectItem>
<SelectItem value="new-york">New York</SelectItem>
</SelectContent>
</Select>,
)
}
describe('Select wrappers', () => {
describe('SelectTrigger', () => {
it('should render clear button when clearable is true and loading is false', () => {
renderOpenSelect({
triggerProps: { clearable: true },
})
expect(screen.getByRole('button', { name: /clear selection/i })).toBeInTheDocument()
})
it('should hide clear button when loading is true', () => {
renderOpenSelect({
triggerProps: { clearable: true, loading: true },
})
expect(screen.queryByRole('button', { name: /clear selection/i })).not.toBeInTheDocument()
})
it('should forward native trigger props when trigger props are provided', () => {
renderOpenSelect({
triggerProps: {
'aria-label': 'Choose option',
'disabled': true,
},
})
const trigger = screen.getByRole('combobox', { name: 'Choose option' })
expect(trigger).toBeDisabled()
})
it('should call onClear and stop click propagation when clear button is clicked', () => {
const onClear = vi.fn()
const onTriggerClick = vi.fn()
renderOpenSelect({
triggerProps: {
clearable: true,
onClear,
onClick: onTriggerClick,
},
})
fireEvent.click(screen.getByRole('button', { name: /clear selection/i }))
expect(onClear).toHaveBeenCalledTimes(1)
expect(onTriggerClick).not.toHaveBeenCalled()
})
it('should stop mouse down propagation when clear button receives mouse down', () => {
const onTriggerMouseDown = vi.fn()
renderOpenSelect({
triggerProps: {
clearable: true,
onMouseDown: onTriggerMouseDown,
},
})
fireEvent.mouseDown(screen.getByRole('button', { name: /clear selection/i }))
expect(onTriggerMouseDown).not.toHaveBeenCalled()
})
it('should not throw when clear button is clicked without onClear handler', () => {
renderOpenSelect({
triggerProps: { clearable: true },
})
const clearButton = screen.getByRole('button', { name: /clear selection/i })
expect(() => fireEvent.click(clearButton)).not.toThrow()
})
})
describe('SelectContent', () => {
it('should use default placement when placement is not provided', () => {
renderOpenSelect()
const positioner = screen.getByRole('group', { name: 'select positioner' })
expect(positioner).toHaveAttribute('data-side', 'bottom')
expect(positioner).toHaveAttribute('data-align', 'start')
})
it('should apply custom placement when placement props are provided', () => {
renderOpenSelect({
contentProps: {
placement: 'top-end',
sideOffset: 12,
alignOffset: 6,
},
})
const positioner = screen.getByRole('group', { name: 'select positioner' })
expect(positioner).toHaveAttribute('data-side', 'top')
expect(positioner).toHaveAttribute('data-align', 'end')
})
it('should forward passthrough props to positioner popup and list when passthrough props are provided', () => {
const onPositionerMouseEnter = vi.fn()
const onPopupClick = vi.fn()
const onListFocus = vi.fn()
render(
<Select open defaultValue="seattle">
<SelectTrigger aria-label="city select">
<SelectValue />
</SelectTrigger>
<SelectContent
positionerProps={{
'role': 'group',
'aria-label': 'select positioner',
'id': 'select-positioner',
'onMouseEnter': onPositionerMouseEnter,
}}
popupProps={{
'role': 'dialog',
'aria-label': 'select popup',
'id': 'select-popup',
'onClick': onPopupClick,
}}
listProps={{
'role': 'listbox',
'aria-label': 'select list',
'id': 'select-list',
'onFocus': onListFocus,
}}
>
<SelectItem value="seattle">Seattle</SelectItem>
</SelectContent>
</Select>,
)
const positioner = screen.getByRole('group', { name: 'select positioner' })
const popup = screen.getByRole('dialog', { name: 'select popup' })
const list = screen.getByRole('listbox', { name: 'select list' })
fireEvent.mouseEnter(positioner)
fireEvent.click(popup)
fireEvent.focus(list)
expect(positioner).toHaveAttribute('id', 'select-positioner')
expect(popup).toHaveAttribute('id', 'select-popup')
expect(list).toHaveAttribute('id', 'select-list')
expect(onPositionerMouseEnter).toHaveBeenCalledTimes(1)
expect(onPopupClick).toHaveBeenCalledTimes(1)
expect(onListFocus).toHaveBeenCalledTimes(1)
})
})
describe('SelectItem', () => {
it('should render options when children are provided', () => {
renderOpenSelect()
expect(screen.getByRole('option', { name: 'Seattle' })).toBeInTheDocument()
expect(screen.getByRole('option', { name: 'New York' })).toBeInTheDocument()
})
it('should not call onValueChange when disabled item is clicked', () => {
const onValueChange = vi.fn()
render(
<Select open defaultValue="seattle" onValueChange={onValueChange}>
<SelectTrigger aria-label="city select">
<SelectValue />
</SelectTrigger>
<SelectContent listProps={{ 'role': 'listbox', 'aria-label': 'select list' }}>
<SelectItem value="seattle">Seattle</SelectItem>
<SelectItem value="new-york" disabled aria-label="Disabled New York">
New York
</SelectItem>
</SelectContent>
</Select>,
)
fireEvent.click(screen.getByRole('option', { name: 'Disabled New York' }))
expect(onValueChange).not.toHaveBeenCalled()
})
})
})

View File

@ -0,0 +1,95 @@
import { Tooltip as BaseTooltip } from '@base-ui/react/tooltip'
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../index'
describe('TooltipContent', () => {
describe('Placement and offsets', () => {
it('should use default top placement when placement is not provided', () => {
render(
<Tooltip open>
<TooltipTrigger aria-label="tooltip trigger">Trigger</TooltipTrigger>
<TooltipContent role="tooltip" aria-label="default tooltip">
Tooltip body
</TooltipContent>
</Tooltip>,
)
const popup = screen.getByRole('tooltip', { name: 'default tooltip' })
expect(popup).toHaveAttribute('data-side', 'top')
expect(popup).toHaveAttribute('data-align', 'center')
expect(popup).toHaveTextContent('Tooltip body')
})
it('should apply custom placement when placement props are provided', () => {
render(
<Tooltip open>
<TooltipTrigger aria-label="tooltip trigger">Trigger</TooltipTrigger>
<TooltipContent
placement="bottom-start"
sideOffset={16}
alignOffset={6}
role="tooltip"
aria-label="custom tooltip"
>
Custom tooltip body
</TooltipContent>
</Tooltip>,
)
const popup = screen.getByRole('tooltip', { name: 'custom tooltip' })
expect(popup).toHaveAttribute('data-side', 'bottom')
expect(popup).toHaveAttribute('data-align', 'start')
expect(popup).toHaveTextContent('Custom tooltip body')
})
})
describe('Variant and popup props', () => {
it('should render popup content when variant is plain', () => {
render(
<Tooltip open>
<TooltipTrigger aria-label="tooltip trigger">Trigger</TooltipTrigger>
<TooltipContent variant="plain" role="tooltip" aria-label="plain tooltip">
Plain tooltip body
</TooltipContent>
</Tooltip>,
)
expect(screen.getByRole('tooltip', { name: 'plain tooltip' })).toHaveTextContent('Plain tooltip body')
})
it('should forward popup props and handlers when popup props are provided', () => {
const onMouseEnter = vi.fn()
render(
<Tooltip open>
<TooltipTrigger aria-label="tooltip trigger">Trigger</TooltipTrigger>
<TooltipContent
id="tooltip-popup-id"
role="tooltip"
aria-label="help text"
data-track-id="tooltip-track"
onMouseEnter={onMouseEnter}
>
Tooltip body
</TooltipContent>
</Tooltip>,
)
const popup = screen.getByRole('tooltip', { name: 'help text' })
fireEvent.mouseEnter(popup)
expect(popup).toHaveAttribute('id', 'tooltip-popup-id')
expect(popup).toHaveAttribute('data-track-id', 'tooltip-track')
expect(onMouseEnter).toHaveBeenCalledTimes(1)
})
})
})
describe('Tooltip aliases', () => {
it('should map alias exports to BaseTooltip components when wrapper exports are imported', () => {
expect(TooltipProvider).toBe(BaseTooltip.Provider)
expect(Tooltip).toBe(BaseTooltip.Root)
expect(TooltipTrigger).toBe(BaseTooltip.Trigger)
})
})