Skip to content

Commit f52ac10

Browse files
fix(react): hub listener fix (#2183)
* Add logs * [REVERT] Enable publish to experimental * trigger ci * Add logger inside the hub.listen * Add name to the listner * Add more logging around useAuthenticator effect * Disable terser * Add isListening logger * Revert "Add isListening logger" This reverts commit 6b8a77f. * Add isListening logger * Add mount console logs * Remove useRef * Remove POC scripts * Remove debug statements * Unit test attempt * Add test for listenToAuthHub * Create yellow-apricots-divide.md Co-authored-by: Caleb Pollman <[email protected]>
1 parent 780a793 commit f52ac10

File tree

5 files changed

+116
-7
lines changed

5 files changed

+116
-7
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@aws-amplify/ui-react": patch
3+
---
4+
5+
Ensure hub listener is correctly attached on React 18 Strict Mode.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { render } from '@testing-library/react';
2+
import * as React from 'react';
3+
import { Hub } from 'aws-amplify';
4+
5+
import { Provider } from '../';
6+
7+
const hubListenSpy = jest.spyOn(Hub, 'listen');
8+
9+
describe('Authenticator.Provider', () => {
10+
it('listens to Auth Hub events on init', () => {
11+
render(
12+
<Provider>
13+
<></>
14+
</Provider>
15+
);
16+
17+
expect(hubListenSpy).toBeCalledTimes(1);
18+
expect(hubListenSpy).toHaveBeenCalledWith(
19+
'auth',
20+
expect.any(Function),
21+
'authenticator-hub-handler'
22+
);
23+
});
24+
});

packages/react/src/components/Authenticator/hooks/useAuthenticator/index.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ export const Provider = ({
106106

107107
const { service: activeService } = value;
108108

109-
const isListening = React.useRef(false);
110109
React.useEffect(() => {
111-
if (isListening.current) return;
112-
113-
isListening.current = true;
114110
return listenToAuthHub(activeService);
115111
}, [activeService]);
116112

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { listenToAuthHub } from '../utils';
2+
import { Hub } from 'aws-amplify';
3+
4+
const authenticatedStateMachine = {
5+
getSnapshot: () => ({
6+
// this is the state.matches function
7+
matches: (state: string) => state === 'authenticated.idle',
8+
}),
9+
send: jest.fn(),
10+
};
11+
12+
const unauthenticatedStateMachine = {
13+
getSnapshot: () => ({
14+
// this is the state.matches function
15+
matches: (state: string) => state === 'signIn',
16+
}),
17+
send: jest.fn(),
18+
};
19+
20+
const sendSpy = jest.spyOn(authenticatedStateMachine, 'send');
21+
22+
describe('listenToAuthHub', () => {
23+
beforeEach(() => {
24+
sendSpy.mockClear();
25+
});
26+
27+
it('responds to token refresh event when state is authenticated', () => {
28+
const unsubscribe = listenToAuthHub(authenticatedStateMachine as any);
29+
30+
Hub.dispatch('auth', { event: 'tokenRefresh' });
31+
expect(sendSpy).toBeCalledWith('TOKEN_REFRESH');
32+
33+
unsubscribe();
34+
});
35+
36+
it('ignores token refresh event when state is unauthenticated', () => {
37+
const unsubscribe = listenToAuthHub(unauthenticatedStateMachine as any);
38+
39+
Hub.dispatch('auth', { event: 'tokenRefresh' });
40+
expect(sendSpy).not.toHaveBeenCalled();
41+
42+
unsubscribe();
43+
});
44+
45+
it('responds to signOut event when state is authenticated', () => {
46+
const unsubscribe = listenToAuthHub(authenticatedStateMachine as any);
47+
48+
Hub.dispatch('auth', { event: 'signOut' });
49+
expect(sendSpy).toBeCalledWith('SIGN_OUT');
50+
51+
unsubscribe();
52+
});
53+
54+
it('ignores token refresh event when state is unauthenticated', () => {
55+
const unsubscribe = listenToAuthHub(unauthenticatedStateMachine as any);
56+
57+
Hub.dispatch('auth', { event: 'signOut' });
58+
expect(sendSpy).not.toHaveBeenCalled();
59+
60+
unsubscribe();
61+
});
62+
63+
it('signs user out when token refresh failed in authenticated state', () => {
64+
const unsubscribe = listenToAuthHub(authenticatedStateMachine as any);
65+
66+
Hub.dispatch('auth', { event: 'tokenRefresh_failure' });
67+
expect(sendSpy).toBeCalledWith('SIGN_OUT');
68+
69+
unsubscribe();
70+
});
71+
72+
it('ignores token refresh failure event when state is unauthenticated', () => {
73+
const unsubscribe = listenToAuthHub(unauthenticatedStateMachine as any);
74+
75+
Hub.dispatch('auth', { event: 'tokenRefresh_failure' });
76+
expect(sendSpy).not.toHaveBeenCalled();
77+
78+
unsubscribe();
79+
});
80+
});

packages/ui/src/helpers/authenticator/utils.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ export const listenToAuthHub = (
6868
service: AuthInterpreter,
6969
handler: HubHandler = defaultAuthHubHandler
7070
) => {
71-
return Hub.listen('auth', (data) => {
72-
handler(data, service);
73-
});
71+
return Hub.listen(
72+
'auth',
73+
(data) => {
74+
handler(data, service);
75+
},
76+
'authenticator-hub-handler'
77+
);
7478
};
7579

7680
export const hasSpecialChars = (password: string) =>

0 commit comments

Comments
 (0)