@@ -6,8 +6,10 @@ import { useClickAway } from '../use-click-away';
6
6
7
7
describe ( 'useClickAway' , ( ) => {
8
8
let handler ;
9
+ let wrapper ;
9
10
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' ) ] ;
11
13
12
14
// Create a fake component to mount in tests that uses the hook
13
15
function FakeComponent ( { enabled = true } ) {
@@ -22,13 +24,21 @@ describe('useClickAway', () => {
22
24
}
23
25
24
26
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 ;
26
32
}
27
33
28
34
beforeEach ( ( ) => {
29
35
handler = sinon . stub ( ) ;
30
36
} ) ;
31
37
38
+ afterEach ( ( ) => {
39
+ wrapper . unmount ( ) ;
40
+ } ) ;
41
+
32
42
events . forEach ( event => {
33
43
it ( `should invoke callback once for events outside of element (${ event . type } )` , ( ) => {
34
44
const wrapper = createComponent ( ) ;
@@ -50,9 +60,7 @@ describe('useClickAway', () => {
50
60
// is not called again
51
61
assert . calledOnce ( handler ) ;
52
62
} ) ;
53
- } ) ;
54
63
55
- events . forEach ( event => {
56
64
it ( `should not invoke callback on events inside of container (${ event . type } )` , ( ) => {
57
65
const wrapper = createComponent ( ) ;
58
66
const button = wrapper . find ( 'button' ) ;
@@ -62,7 +70,25 @@ describe('useClickAway', () => {
62
70
} ) ;
63
71
wrapper . update ( ) ;
64
72
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 ) ;
66
92
} ) ;
67
93
} ) ;
68
94
} ) ;
0 commit comments