import React from 'react'; import { Dropdown } from '../../../client/components/dropdown/dropdown.jsx'; import { renderDropdown, setupDropdownTestLifecycle } from './dropdown.testUtils.js'; setupDropdownTestLifecycle(); describe('Dropdown structure', ()=>{ it('renders expected structure, classes, and accessibility roles', async ()=>{ const { host, cleanup } = await renderDropdown( ); const wrapper = host.querySelector('.menu-wrapper'); const trigger = wrapper.querySelector('button.menu-item.blue'); const menu = wrapper.querySelector('.menu-list'); expect(wrapper).toBeTruthy(); expect(wrapper.className).toContain('extra-class'); expect(wrapper.getAttribute('role')).toBe('none'); expect(trigger.getAttribute('aria-haspopup')).toBe('menu'); expect(trigger.getAttribute('role')).toBe('menuitem'); expect(menu.getAttribute('role')).toBe('menu'); expect(menu.getAttribute('popover')).toBe('auto'); await cleanup(); }); it('creates ids and popovertarget values that match and are unique per instance', async ()=>{ const { host, cleanup } = await renderDropdown(
); const triggers = Array.from(host.querySelectorAll('.menu-wrapper > .menu-item')); const menus = Array.from(host.querySelectorAll('.menu-list')); const menuIds = menus.map((menu)=>menu.id); expect(triggers).toHaveLength(2); expect(menus).toHaveLength(2); expect(new Set(menuIds).size).toBe(2); expect(triggers[0].getAttribute('popovertarget')).toBe(menuIds[0]); expect(triggers[1].getAttribute('popovertarget')).toBe(menuIds[1]); expect(triggers[0].id).toBe(`${menuIds[0]}-trigger`); await cleanup(); }); it('applies css anchor styles to trigger and menu', async ()=>{ const { host, cleanup } = await renderDropdown( ); const trigger = host.querySelector('.menu-wrapper > .menu-item'); const menu = host.querySelector('.menu-list'); const menuId = menu.id; expect(trigger.getAttribute('style')).toBe(`anchor-name: --${menuId}`); expect(menu.getAttribute('style')).toBe(`position-anchor: --${menuId}`); await cleanup(); }); it('disables the trigger when no children are present', async ()=>{ const { host, cleanup } = await renderDropdown(); expect(host.querySelector('.menu-wrapper > .menu-item').disabled).toBe(true); await cleanup(); }); it('renders icon class and default caret', async ()=>{ const { host, cleanup } = await renderDropdown( ); const trigger = host.querySelector('.menu-wrapper > .menu-item'); expect(trigger.querySelector('i.fas.fa-star')).toBeTruthy(); expect(trigger.querySelector('i.caret').className).toContain('fa-caret-down'); await cleanup(); }); it('renders a custom trigger when provided', async ()=>{ const { host, cleanup } = await renderDropdown( Open Menu}> ); const trigger = host.querySelector('.menu-wrapper > .menu-item'); expect(trigger.querySelector('.custom-trigger')).toBeTruthy(); expect(trigger.querySelector('.caret')).toBeFalsy(); await cleanup(); }); it('supports nested submenus to at least 3 levels deep', async ()=>{ const { host, cleanup } = await renderDropdown( ); const triggers = Array.from(host.querySelectorAll('.menu-wrapper > .menu-item')); const menus = Array.from(host.querySelectorAll('.menu-list')); expect(triggers).toHaveLength(3); expect(menus).toHaveLength(3); for (const trigger of triggers) { const targetId = trigger.getAttribute('popovertarget'); expect(targetId).toBeTruthy(); expect(host.querySelector(`#${targetId}`)).toBeTruthy(); } expect(triggers[1].querySelector('.caret').className).toContain('fa-caret-right'); expect(triggers[2].querySelector('.caret').className).toContain('fa-caret-right'); await cleanup(); }); });