deprecatedDropdownMenu.spec.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import type {ComponentProps} from 'react';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import DeprecatedDropdownMenu from 'sentry/components/deprecatedDropdownMenu';
  4. describe('dropdownMenuDeprecated', function () {
  5. function DeprecatedDropdownImplementation(
  6. props: Partial<ComponentProps<typeof DeprecatedDropdownMenu>> = {}
  7. ) {
  8. return (
  9. <DeprecatedDropdownMenu {...props}>
  10. {({getRootProps, getActorProps, getMenuProps, isOpen}) => (
  11. <span {...getRootProps({})}>
  12. <button {...getActorProps({})}>Open Dropdown</button>
  13. {isOpen && (
  14. <ul {...getMenuProps({})}>
  15. <li>Dropdown Menu Item 1</li>
  16. </ul>
  17. )}
  18. </span>
  19. )}
  20. </DeprecatedDropdownMenu>
  21. );
  22. }
  23. it('renders', function () {
  24. const {container} = render(<DeprecatedDropdownImplementation />);
  25. expect(container).toSnapshot();
  26. });
  27. it('can toggle dropdown menu with actor', async function () {
  28. render(<DeprecatedDropdownImplementation />);
  29. await userEvent.click(screen.getByRole('button'));
  30. expect(screen.getByRole('listbox')).toBeInTheDocument();
  31. await userEvent.click(screen.getByRole('button'));
  32. expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
  33. });
  34. it('closes dropdown when clicking on anything in menu', async function () {
  35. render(<DeprecatedDropdownImplementation />);
  36. await userEvent.click(screen.getByRole('button'));
  37. await userEvent.click(screen.getByRole('listitem'));
  38. expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
  39. });
  40. it('closes dropdown when clicking outside of menu', async function () {
  41. render(
  42. <div data-test-id="outside-element">
  43. <DeprecatedDropdownImplementation />
  44. </div>
  45. );
  46. await userEvent.click(screen.getByRole('button'));
  47. await userEvent.click(screen.getByTestId('outside-element'));
  48. expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
  49. });
  50. it('closes dropdown when pressing escape', async function () {
  51. render(<DeprecatedDropdownImplementation />);
  52. await userEvent.click(screen.getByRole('button'));
  53. await userEvent.keyboard('{Escape}');
  54. expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
  55. });
  56. it('ignores "Escape" key if `closeOnEscape` is false', async function () {
  57. render(<DeprecatedDropdownImplementation closeOnEscape={false} />);
  58. await userEvent.click(screen.getByRole('button'));
  59. await userEvent.keyboard('{Escape}');
  60. expect(screen.getByRole('listbox')).toBeInTheDocument();
  61. });
  62. it('keeps dropdown open when clicking on anything in menu with `keepMenuOpen` prop', async function () {
  63. render(<DeprecatedDropdownImplementation keepMenuOpen />);
  64. await userEvent.click(screen.getByRole('button'));
  65. await userEvent.click(screen.getByRole('listitem'));
  66. expect(screen.getByRole('listbox')).toBeInTheDocument();
  67. });
  68. it('render prop getters all extend props and call original onClick handlers', async function () {
  69. const rootClick = jest.fn();
  70. const actorClick = jest.fn();
  71. const menuClick = jest.fn();
  72. render(
  73. <DeprecatedDropdownMenu keepMenuOpen>
  74. {({getRootProps, getActorProps, getMenuProps, isOpen}) => (
  75. <span {...getRootProps({onClick: rootClick})} data-test-id="root">
  76. <button {...getActorProps({onClick: actorClick})} data-test-id="actor">
  77. Open Dropdown
  78. </button>
  79. {isOpen && (
  80. <ul {...getMenuProps({onClick: menuClick})} data-test-id="menu">
  81. <li>Dropdown Menu Item 1</li>
  82. </ul>
  83. )}
  84. </span>
  85. )}
  86. </DeprecatedDropdownMenu>
  87. );
  88. expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
  89. await userEvent.click(screen.getByTestId('root'));
  90. expect(rootClick).toHaveBeenCalled();
  91. await userEvent.click(screen.getByTestId('actor'));
  92. expect(actorClick).toHaveBeenCalled();
  93. await userEvent.click(screen.getByTestId('menu'));
  94. expect(menuClick).toHaveBeenCalled();
  95. expect(screen.queryByRole('listbox')).toBeInTheDocument();
  96. });
  97. it('always rendered menus should attach document event listeners only when opened', async function () {
  98. const addSpy = jest.spyOn(document, 'addEventListener');
  99. const removeSpy = jest.spyOn(document, 'removeEventListener');
  100. render(
  101. <DeprecatedDropdownMenu alwaysRenderMenu>
  102. {({getRootProps, getActorProps, getMenuProps}) => (
  103. <span {...getRootProps({className: 'root'})}>
  104. <button {...getActorProps({className: 'actor'})}>Open Dropdown</button>
  105. <ul {...getMenuProps({className: 'menu'})}>
  106. <li>Dropdown Menu Item 1</li>
  107. </ul>
  108. </span>
  109. )}
  110. </DeprecatedDropdownMenu>
  111. );
  112. // Make sure this is only called when menu is open
  113. expect(addSpy).not.toHaveBeenCalled();
  114. await userEvent.click(screen.getByRole('button'));
  115. expect(addSpy).toHaveBeenCalled();
  116. expect(removeSpy).not.toHaveBeenCalled();
  117. await userEvent.click(screen.getByRole('button'));
  118. expect(removeSpy).toHaveBeenCalled();
  119. addSpy.mockRestore();
  120. removeSpy.mockRestore();
  121. });
  122. it('does not close nested dropdown on actor clicks', async function () {
  123. render(
  124. <DeprecatedDropdownMenu isNestedDropdown>
  125. {({getRootProps, getActorProps, getMenuProps}) => (
  126. <span {...getRootProps({})}>
  127. <button {...getActorProps({})}>Open Dropdown</button>
  128. <ul {...getMenuProps({})}>
  129. <li data-test-id="menu-item">Dropdown Menu Item 1</li>
  130. </ul>
  131. </span>
  132. )}
  133. </DeprecatedDropdownMenu>
  134. );
  135. await userEvent.hover(screen.getByRole('button'));
  136. expect(screen.getByTestId('menu-item')).toBeInTheDocument();
  137. await userEvent.click(screen.getByRole('button'));
  138. // Should still be visible.
  139. expect(screen.getByTestId('menu-item')).toBeInTheDocument();
  140. });
  141. });