@@ -6,8 +6,10 @@ import { useClickAway } from '../use-click-away';
66
77describe ( 'useClickAway' , ( ) => {
88 let handler ;
9+ let wrapper ;
910
10- const events = [ new Event ( 'mousedown' ) , new Event ( 'click' ) ] ;
11+ const event = name => new Event ( name , { bubbles : true } ) ;
12+ const events = [ event ( 'mousedown' ) , event ( 'click' ) ] ;
1113
1214 // Create a fake component to mount in tests that uses the hook
1315 function FakeComponent ( { enabled = true } ) {
@@ -22,13 +24,21 @@ describe('useClickAway', () => {
2224 }
2325
2426 function createComponent ( props ) {
25- return mount ( < FakeComponent { ...props } /> ) ;
27+ const container = document . createElement ( 'div' ) ;
28+ document . body . append ( container ) ;
29+
30+ wrapper = mount ( < FakeComponent { ...props } /> , { attachTo : container } ) ;
31+ return wrapper ;
2632 }
2733
2834 beforeEach ( ( ) => {
2935 handler = sinon . stub ( ) ;
3036 } ) ;
3137
38+ afterEach ( ( ) => {
39+ wrapper . unmount ( ) ;
40+ } ) ;
41+
3242 events . forEach ( event => {
3343 it ( `should invoke callback once for events outside of element (${ event . type } )` , ( ) => {
3444 const wrapper = createComponent ( ) ;
@@ -50,9 +60,7 @@ describe('useClickAway', () => {
5060 // is not called again
5161 assert . calledOnce ( handler ) ;
5262 } ) ;
53- } ) ;
5463
55- events . forEach ( event => {
5664 it ( `should not invoke callback on events inside of container (${ event . type } )` , ( ) => {
5765 const wrapper = createComponent ( ) ;
5866 const button = wrapper . find ( 'button' ) ;
@@ -62,7 +70,25 @@ describe('useClickAway', () => {
6270 } ) ;
6371 wrapper . update ( ) ;
6472
65- assert . equal ( handler . callCount , 0 ) ;
73+ assert . notCalled ( handler ) ;
74+ } ) ;
75+
76+ it ( `should not invoke callback if clicked element is removed from container (${ event . type } )` , ( ) => {
77+ const wrapper = createComponent ( ) ;
78+ const button = wrapper . find ( 'button' ) . getDOMNode ( ) ;
79+
80+ act ( ( ) => {
81+ button . addEventListener ( event . type , ( ) => {
82+ // Remove the button from the DOM before next listeners are invoked,
83+ // to simulate what happens if the clicked element was removed as a
84+ // result of a state update + re-render in a child component
85+ button . remove ( ) ;
86+ } ) ;
87+ button . dispatchEvent ( event ) ;
88+ } ) ;
89+ wrapper . update ( ) ;
90+
91+ assert . notCalled ( handler ) ;
6692 } ) ;
6793 } ) ;
6894} ) ;
0 commit comments