deprecatedDropdownMenu.spec.tsx 5.9 KB

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