Skip to content

Commit 5801927

Browse files
authored
Fix: connectionResolver receives incorrect field value when switching between Login and Sign-up tabs (#2697)
### Changes Fixes a bug where connectionResolver callback receives the wrong field value when users switch between Login and Sign-up tabs that have different field types (username vs email). Closes #2631 ### Root Cause The bug was in `src/ui/box/container.jsx` in the `checkConnectionResolver()` method at line 80: **BEFORE** (buggy code) `const userInputValue = c.getFieldValue(lock, 'username') || c.getFieldValue(lock, 'email'); ` This code always prioritized the username field over email, regardless of which screen (Login vs Sign-up) was currently active. Since both field values exist in the global lock state, it would retrieve the Login username even when on the Sign-up screen. ### Solution Modified checkConnectionResolver() to check which screen is currently active and prioritize the appropriate field: **AFTER** (fixed code) ``` const isSignUpScreen = screenName && screenName.includes('signUp'); const userInputValue = databaseUsernameValue(lock, isSignUpScreen ? { emailFirst: true } : {}); ``` ### Testing Manual testing performed - - Verified bug exists in original code - Applied fix and verified bug is resolved - Tested multiple scenarios: - Sign-up with email (email prioritized) - Sign-up with username only (username used) - Login with username (username prioritized) - Login with email (email used) - Switch from Login to Sign-up with pre-filled fields (correct field used) ### Checklist * [x] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) * [x] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) * [x] All code quality tools/guidelines have been run/followed * [x] All relevant assets have been compiled
1 parent e9779d2 commit 5801927

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

src/__tests__/ui/box/container.test.jsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ jest.mock('store/index', () => ({
99

1010
jest.mock('ui/box/chrome', () => mockComponent('chrome'));
1111

12+
jest.mock('connection/database/index', () => ({
13+
databaseUsernameValue: jest.fn()
14+
}));
15+
1216
const mockEvent = {
1317
preventDefault: () => {}
1418
};
@@ -75,14 +79,25 @@ describe('Container', () => {
7579
describe('with a custom `connectionResolver`', () => {
7680
let connectionResolverMock;
7781
let setResolvedConnectionMock;
82+
let databaseUsernameValueMock;
7883

7984
beforeEach(() => {
8085
connectionResolverMock = jest.fn();
8186
setResolvedConnectionMock = jest.fn();
87+
databaseUsernameValueMock = require('connection/database/index').databaseUsernameValue;
88+
89+
// Set default return value for databaseUsernameValue mock
90+
databaseUsernameValueMock.mockReturnValue('[email protected]');
91+
8292
require('core/index').connectionResolver = () => connectionResolverMock;
8393
require('core/index').setResolvedConnection = setResolvedConnectionMock;
8494
});
8595

96+
afterEach(() => {
97+
// Reset mock between tests and restore default return value
98+
databaseUsernameValueMock.mockReset().mockReturnValue('[email protected]');
99+
});
100+
86101
it('calls `connectionResolver` onSubmit', () => {
87102
const c = getContainer();
88103
c.handleSubmit(mockEvent);
@@ -110,6 +125,54 @@ describe('Container', () => {
110125
expect(mock.calls.length).toBe(1);
111126
expect(mock.calls[0]).toMatchSnapshot();
112127
});
128+
129+
it('prioritizes email over username on signUp screen', () => {
130+
databaseUsernameValueMock.mockReturnValue('[email protected]');
131+
132+
const c = getContainer({ screenName: 'main.signUp' });
133+
c.handleSubmit(mockEvent);
134+
135+
// Should call databaseUsernameValue with emailFirst: true
136+
expect(databaseUsernameValueMock).toHaveBeenCalledWith(
137+
expect.anything(),
138+
{ emailFirst: true }
139+
);
140+
141+
// connectionResolver should receive the email value
142+
const { mock } = connectionResolverMock;
143+
expect(mock.calls[0][0]).toBe('[email protected]');
144+
});
145+
146+
it('prioritizes username over email on login screen', () => {
147+
databaseUsernameValueMock.mockReturnValue('testuser');
148+
149+
const c = getContainer({ screenName: 'main.login' });
150+
c.handleSubmit(mockEvent);
151+
152+
// Should call databaseUsernameValue with empty options (default behavior)
153+
expect(databaseUsernameValueMock).toHaveBeenCalledWith(
154+
expect.anything(),
155+
{}
156+
);
157+
158+
// connectionResolver should receive the username value
159+
const { mock } = connectionResolverMock;
160+
expect(mock.calls[0][0]).toBe('testuser');
161+
});
162+
163+
it('uses default behavior when screenName is not main.signUp', () => {
164+
databaseUsernameValueMock.mockReturnValue('defaultvalue');
165+
166+
const c = getContainer({ screenName: 'forgotPassword' });
167+
c.handleSubmit(mockEvent);
168+
169+
// Should call databaseUsernameValue with empty options (default behavior)
170+
expect(databaseUsernameValueMock).toHaveBeenCalledWith(
171+
expect.anything(),
172+
{}
173+
);
174+
});
175+
113176
});
114177

115178
describe('when suppressSubmitOverlay is true', () => {

src/ui/box/container.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { CloseButton } from './button';
55
import * as l from '../../core/index';
66
import * as c from '../../field/index';
77
import { swap, updateEntity } from '../../store/index';
8+
import { databaseUsernameValue } from '../../connection/database/index';
89

910
const badgeSvg = (
1011
<svg focusable="false" width="58px" height="21px" viewBox="0 0 462 168">
@@ -69,15 +70,20 @@ export default class Container extends React.Component {
6970
this.state = { isOpen: false };
7071
}
7172
checkConnectionResolver(done) {
72-
const { contentProps } = this.props;
73+
const { contentProps, screenName } = this.props;
7374
const lock = contentProps.model;
7475
const connectionResolver = l.connectionResolver(lock);
7576
if (!connectionResolver) {
7677
return done();
7778
}
7879
const { connections, id } = lock.get('client').toJS();
7980
const context = { connections, id };
80-
const userInputValue = c.getFieldValue(lock, 'username') || c.getFieldValue(lock, 'email');
81+
82+
// On signUp screen, use emailFirst option to prioritize email over username
83+
// On login screen, use default behavior (username first)
84+
const isSignUpScreen = screenName === 'main.signUp';
85+
const userInputValue = databaseUsernameValue(lock, isSignUpScreen ? { emailFirst: true } : {});
86+
8187
connectionResolver(userInputValue, context, resolvedConnection => {
8288
swap(updateEntity, 'lock', l.id(lock), m => l.setResolvedConnection(m, resolvedConnection));
8389
done();

0 commit comments

Comments
 (0)