deprecatedDropdownMenu.spec.jsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import DeprecatedDropdownMenu from 'sentry/components/deprecatedDropdownMenu';
  3. jest.useFakeTimers();
  4. describe('dropdownMenuDeprecated', function () {
  5. let wrapper;
  6. beforeEach(function () {
  7. wrapper = mountWithTheme(
  8. <DeprecatedDropdownMenu>
  9. {({getRootProps, getActorProps, getMenuProps, isOpen}) => (
  10. <span {...getRootProps({})}>
  11. <button {...getActorProps({})}>Open Dropdown</button>
  12. {isOpen && (
  13. <ul {...getMenuProps({})}>
  14. <li>Dropdown Menu Item 1</li>
  15. </ul>
  16. )}
  17. </span>
  18. )}
  19. </DeprecatedDropdownMenu>
  20. );
  21. });
  22. it('renders', function () {
  23. expect(wrapper).toSnapshot();
  24. });
  25. it('can toggle dropdown menu with actor', function () {
  26. wrapper.find('button').simulate('click');
  27. expect(wrapper.state('isOpen')).toBe(true);
  28. expect(wrapper.find('ul')).toHaveLength(1);
  29. wrapper.find('button').simulate('click');
  30. expect(wrapper.state('isOpen')).toBe(false);
  31. expect(wrapper.find('ul')).toHaveLength(0);
  32. });
  33. it('closes dropdown when clicking on anything in menu', function () {
  34. wrapper.find('button').simulate('click');
  35. wrapper.find('li').simulate('click');
  36. expect(wrapper.state('isOpen')).toBe(false);
  37. expect(wrapper.find('ul')).toHaveLength(0);
  38. });
  39. it('closes dropdown when clicking outside of menu', async function () {
  40. wrapper.find('button').simulate('click');
  41. // Simulate click on document
  42. const event = document.createEvent('HTMLEvents');
  43. event.initEvent('click', false, true);
  44. document.body.dispatchEvent(event);
  45. jest.runAllTimers();
  46. await Promise.resolve();
  47. wrapper.update();
  48. expect(wrapper.find('ul')).toHaveLength(0);
  49. });
  50. it('closes dropdown when pressing escape', function () {
  51. wrapper.find('button').simulate('click');
  52. expect(wrapper.state('isOpen')).toBe(true);
  53. wrapper.simulate('keyDown', {key: 'Escape'});
  54. wrapper.find('button').simulate('keyDown', {key: 'Escape'});
  55. expect(wrapper.state('isOpen')).toBe(false);
  56. expect(wrapper.find('ul')).toHaveLength(0);
  57. });
  58. it('ignores "Escape" key if `closeOnEscape` is false', function () {
  59. wrapper = mountWithTheme(
  60. <DeprecatedDropdownMenu closeOnEscape={false}>
  61. {({getRootProps, getActorProps, getMenuProps, isOpen}) => (
  62. <span {...getRootProps({})}>
  63. <button {...getActorProps({})}>Open Dropdown</button>
  64. {isOpen && (
  65. <ul {...getMenuProps({})}>
  66. <li>Dropdown Menu Item 1</li>
  67. </ul>
  68. )}
  69. </span>
  70. )}
  71. </DeprecatedDropdownMenu>
  72. );
  73. wrapper.find('button').simulate('click');
  74. expect(wrapper.state('isOpen')).toBe(true);
  75. wrapper.find('button').simulate('keyDown', {key: 'Escape'});
  76. expect(wrapper.find('ul')).toHaveLength(1);
  77. expect(wrapper.state('isOpen')).toBe(true);
  78. });
  79. it('keeps dropdown open when clicking on anything in menu with `keepMenuOpen` prop', function () {
  80. wrapper = mountWithTheme(
  81. <DeprecatedDropdownMenu keepMenuOpen>
  82. {({getRootProps, getActorProps, getMenuProps, isOpen}) => (
  83. <span {...getRootProps({})}>
  84. <button {...getActorProps({})}>Open Dropdown</button>
  85. {isOpen && (
  86. <ul {...getMenuProps({})}>
  87. <li>Dropdown Menu Item 1</li>
  88. </ul>
  89. )}
  90. </span>
  91. )}
  92. </DeprecatedDropdownMenu>
  93. );
  94. wrapper.find('button').simulate('click');
  95. wrapper.find('li').simulate('click');
  96. expect(wrapper.state('isOpen')).toBe(true);
  97. expect(wrapper.find('ul')).toHaveLength(1);
  98. });
  99. it('render prop getters all extend props and call original onClick handlers', function () {
  100. const rootClick = jest.fn();
  101. const actorClick = jest.fn();
  102. const menuClick = jest.fn();
  103. const addSpy = jest.spyOn(document, 'addEventListener');
  104. const removeSpy = jest.spyOn(document, 'removeEventListener');
  105. wrapper = mountWithTheme(
  106. <DeprecatedDropdownMenu keepMenuOpen>
  107. {({getRootProps, getActorProps, getMenuProps, isOpen}) => (
  108. <span
  109. {...getRootProps({
  110. className: 'root',
  111. onClick: rootClick,
  112. })}
  113. >
  114. <button
  115. {...getActorProps({
  116. className: 'actor',
  117. onClick: actorClick,
  118. })}
  119. >
  120. Open Dropdown
  121. </button>
  122. {isOpen && (
  123. <ul
  124. {...getMenuProps({
  125. className: 'menu',
  126. onClick: menuClick,
  127. })}
  128. >
  129. <li>Dropdown Menu Item 1</li>
  130. </ul>
  131. )}
  132. </span>
  133. )}
  134. </DeprecatedDropdownMenu>
  135. );
  136. expect(wrapper.find('ul')).toHaveLength(0);
  137. wrapper.find('span').simulate('click');
  138. expect(rootClick).toHaveBeenCalled();
  139. wrapper.find('button').simulate('click');
  140. expect(actorClick).toHaveBeenCalled();
  141. wrapper.find('li').simulate('click');
  142. expect(menuClick).toHaveBeenCalled();
  143. // breaks in jest22
  144. // expect(wrapper).toSnapshot();
  145. expect(wrapper.find('ul')).toHaveLength(1);
  146. expect(document.addEventListener).toHaveBeenCalled();
  147. wrapper.unmount();
  148. expect(document.removeEventListener).toHaveBeenCalled();
  149. addSpy.mockRestore();
  150. removeSpy.mockRestore();
  151. });
  152. it('always rendered menus should attach document event listeners only when opened', function () {
  153. const addSpy = jest.spyOn(document, 'addEventListener');
  154. const removeSpy = jest.spyOn(document, 'removeEventListener');
  155. wrapper = mountWithTheme(
  156. <DeprecatedDropdownMenu alwaysRenderMenu>
  157. {({getRootProps, getActorProps, getMenuProps}) => (
  158. <span
  159. {...getRootProps({
  160. className: 'root',
  161. })}
  162. >
  163. <button
  164. {...getActorProps({
  165. className: 'actor',
  166. })}
  167. >
  168. Open Dropdown
  169. </button>
  170. <ul
  171. {...getMenuProps({
  172. className: 'menu',
  173. })}
  174. >
  175. <li>Dropdown Menu Item 1</li>
  176. </ul>
  177. </span>
  178. )}
  179. </DeprecatedDropdownMenu>
  180. );
  181. // Make sure this is only called when menu is open
  182. expect(document.addEventListener).not.toHaveBeenCalled();
  183. wrapper.find('button').simulate('click');
  184. expect(wrapper.state('isOpen')).toBe(true);
  185. expect(document.addEventListener).toHaveBeenCalled();
  186. expect(document.removeEventListener).not.toHaveBeenCalled();
  187. wrapper.find('button').simulate('click');
  188. expect(wrapper.state('isOpen')).toBe(false);
  189. expect(document.removeEventListener).toHaveBeenCalled();
  190. addSpy.mockRestore();
  191. removeSpy.mockRestore();
  192. });
  193. it('does not close nested dropdown on actor clicks', function () {
  194. wrapper = mountWithTheme(
  195. <DeprecatedDropdownMenu isNestedDropdown>
  196. {({getRootProps, getActorProps, getMenuProps}) => (
  197. <span {...getRootProps({})}>
  198. <button {...getActorProps({})}>Open Dropdown</button>
  199. {
  200. <ul {...getMenuProps({})}>
  201. <li data-test-id="menu-item">Dropdown Menu Item 1</li>
  202. </ul>
  203. }
  204. </span>
  205. )}
  206. </DeprecatedDropdownMenu>
  207. );
  208. wrapper.find('button').simulate('mouseEnter');
  209. expect(wrapper.find('[data-test-id="menu-item"]')).toHaveLength(1);
  210. wrapper.find('button').simulate('click');
  211. // Should still be visible.
  212. expect(wrapper.find('[data-test-id="menu-item"]')).toHaveLength(1);
  213. });
  214. });