@@ -9,13 +9,27 @@ import useLogout from './useLogout';
9
9
import useNotify from '../sideEffect/useNotify' ;
10
10
import { AuthProvider } from '../types' ;
11
11
12
- jest . mock ( './useLogout' ) ;
13
- jest . mock ( '../sideEffect/useNotify' ) ;
12
+ let loggedIn = true ;
14
13
15
- const logout = jest . fn ( ) ;
16
- useLogout . mockImplementation ( ( ) => logout ) ;
17
- const notify = jest . fn ( ) ;
18
- useNotify . mockImplementation ( ( ) => notify ) ;
14
+ const authProvider : AuthProvider = {
15
+ login : ( ) => {
16
+ loggedIn = true ;
17
+ return Promise . resolve ( ) ;
18
+ } ,
19
+ logout : jest . fn ( ( ) => {
20
+ loggedIn = false ;
21
+ return Promise . resolve ( ) ;
22
+ } ) ,
23
+ checkAuth : ( ) =>
24
+ loggedIn ? Promise . resolve ( ) : Promise . reject ( 'bad method' ) ,
25
+ checkError : params => {
26
+ if ( params instanceof Error && params . message === 'denied' ) {
27
+ return Promise . reject ( new Error ( 'logout' ) ) ;
28
+ }
29
+ return Promise . resolve ( ) ;
30
+ } ,
31
+ getPermissions : ( ) => Promise . reject ( 'bad method' ) ,
32
+ } ;
19
33
20
34
const TestComponent = ( {
21
35
error,
@@ -32,29 +46,24 @@ const TestComponent = ({
32
46
return < div > { loggedOut ? '' : 'logged in' } </ div > ;
33
47
} ;
34
48
35
- let loggedIn = true ;
49
+ jest . mock ( './useLogout' ) ;
50
+ jest . mock ( '../sideEffect/useNotify' ) ;
36
51
37
- const authProvider : AuthProvider = {
38
- login : ( ) => Promise . reject ( 'bad method' ) ,
39
- logout : ( ) => {
40
- loggedIn = false ;
41
- return Promise . resolve ( ) ;
42
- } ,
43
- checkAuth : ( ) =>
44
- loggedIn ? Promise . resolve ( ) : Promise . reject ( 'bad method' ) ,
45
- checkError : params => {
46
- if ( params instanceof Error && params . message === 'denied' ) {
47
- return Promise . reject ( new Error ( 'logout' ) ) ;
48
- }
49
- return Promise . resolve ( ) ;
50
- } ,
51
- getPermissions : ( ) => Promise . reject ( 'bad method' ) ,
52
- } ;
52
+ //@ts -expect-error
53
+ useLogout . mockImplementation ( ( ) => {
54
+ const logout = ( ) => authProvider . logout ( null ) ;
55
+ return logout ;
56
+ } ) ;
57
+ const notify = jest . fn ( ) ;
58
+ //@ts -expect-error
59
+ useNotify . mockImplementation ( ( ) => notify ) ;
53
60
54
61
describe ( 'useLogoutIfAccessDenied' , ( ) => {
55
62
afterEach ( ( ) => {
56
- logout . mockClear ( ) ;
63
+ //@ts -expect-error
64
+ authProvider . logout . mockClear ( ) ;
57
65
notify . mockClear ( ) ;
66
+ authProvider . login ( '' ) ;
58
67
} ) ;
59
68
60
69
it ( 'should not logout if passed no error' , async ( ) => {
@@ -64,7 +73,7 @@ describe('useLogoutIfAccessDenied', () => {
64
73
</ AuthContext . Provider >
65
74
) ;
66
75
await waitFor ( ( ) => {
67
- expect ( logout ) . toHaveBeenCalledTimes ( 0 ) ;
76
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 0 ) ;
68
77
expect ( notify ) . toHaveBeenCalledTimes ( 0 ) ;
69
78
expect ( queryByText ( 'logged in' ) ) . not . toBeNull ( ) ;
70
79
} ) ;
@@ -77,7 +86,7 @@ describe('useLogoutIfAccessDenied', () => {
77
86
</ AuthContext . Provider >
78
87
) ;
79
88
await waitFor ( ( ) => {
80
- expect ( logout ) . toHaveBeenCalledTimes ( 0 ) ;
89
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 0 ) ;
81
90
expect ( notify ) . toHaveBeenCalledTimes ( 0 ) ;
82
91
expect ( queryByText ( 'logged in' ) ) . not . toBeNull ( ) ;
83
92
} ) ;
@@ -90,7 +99,7 @@ describe('useLogoutIfAccessDenied', () => {
90
99
</ AuthContext . Provider >
91
100
) ;
92
101
await waitFor ( ( ) => {
93
- expect ( logout ) . toHaveBeenCalledTimes ( 1 ) ;
102
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 1 ) ;
94
103
expect ( notify ) . toHaveBeenCalledTimes ( 1 ) ;
95
104
expect ( queryByText ( 'logged in' ) ) . toBeNull ( ) ;
96
105
} ) ;
@@ -104,7 +113,30 @@ describe('useLogoutIfAccessDenied', () => {
104
113
</ AuthContext . Provider >
105
114
) ;
106
115
await waitFor ( ( ) => {
107
- expect ( logout ) . toHaveBeenCalledTimes ( 1 ) ;
116
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 1 ) ;
117
+ expect ( notify ) . toHaveBeenCalledTimes ( 1 ) ;
118
+ expect ( queryByText ( 'logged in' ) ) . toBeNull ( ) ;
119
+ } ) ;
120
+ } ) ;
121
+
122
+ it ( 'should not send multiple notifications if the errors arrive with a delay' , async ( ) => {
123
+ let index = 0 ;
124
+ const delayedAuthProvider = {
125
+ ...authProvider ,
126
+ checkError : ( ) =>
127
+ new Promise < void > ( ( resolve , reject ) => {
128
+ setTimeout ( ( ) => reject ( new Error ( 'foo' ) ) , index * 100 ) ;
129
+ index ++ ; // answers immediately first, then after 100ms the second time
130
+ } ) ,
131
+ } ;
132
+ const { queryByText } = render (
133
+ < AuthContext . Provider value = { delayedAuthProvider } >
134
+ < TestComponent />
135
+ < TestComponent />
136
+ </ AuthContext . Provider >
137
+ ) ;
138
+ await waitFor ( ( ) => {
139
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 2 ) ; /// two logouts, but only one notification
108
140
expect ( notify ) . toHaveBeenCalledTimes ( 1 ) ;
109
141
expect ( queryByText ( 'logged in' ) ) . toBeNull ( ) ;
110
142
} ) ;
@@ -120,7 +152,7 @@ describe('useLogoutIfAccessDenied', () => {
120
152
</ AuthContext . Provider >
121
153
) ;
122
154
await waitFor ( ( ) => {
123
- expect ( logout ) . toHaveBeenCalledTimes ( 1 ) ;
155
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 1 ) ;
124
156
expect ( notify ) . toHaveBeenCalledTimes ( 0 ) ;
125
157
expect ( queryByText ( 'logged in' ) ) . toBeNull ( ) ;
126
158
} ) ;
@@ -140,7 +172,7 @@ describe('useLogoutIfAccessDenied', () => {
140
172
</ AuthContext . Provider >
141
173
) ;
142
174
await waitFor ( ( ) => {
143
- expect ( logout ) . toHaveBeenCalledTimes ( 1 ) ;
175
+ expect ( authProvider . logout ) . toHaveBeenCalledTimes ( 1 ) ;
144
176
expect ( notify ) . toHaveBeenCalledTimes ( 0 ) ;
145
177
expect ( queryByText ( 'logged in' ) ) . toBeNull ( ) ;
146
178
} ) ;
0 commit comments