papercut-fix: perform login on enter button press for basic auth (#434)
Signed-off-by: Vishwas Rajashekar <vrajashe@cisco.com>
This commit is contained in:
parent
743d4fe073
commit
8311d59e53
@ -24,14 +24,14 @@ afterEach(() => {
|
||||
|
||||
describe('Signin component automatic navigation', () => {
|
||||
it('navigates to homepage when user is already logged in', async () => {
|
||||
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => {}} isLoggedIn={true} setIsLoggedIn={() => {}} />);
|
||||
render(<SignIn isLoggedIn={true} setIsLoggedIn={() => {}} />);
|
||||
await expect(mockedUsedNavigate).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
|
||||
it('navigates to homepage when auth is disabled', async () => {
|
||||
// mock request to check auth
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { http: {} } });
|
||||
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => {}} isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
@ -48,7 +48,7 @@ describe('Sign in form', () => {
|
||||
});
|
||||
|
||||
it('should change username and password values on user input', async () => {
|
||||
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => {}} isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
fireEvent.change(usernameInput, { target: { value: 'test' } });
|
||||
@ -59,7 +59,7 @@ describe('Sign in form', () => {
|
||||
});
|
||||
|
||||
it('should display error if username and password values are empty after change', async () => {
|
||||
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => {}} isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.click(usernameInput);
|
||||
@ -74,24 +74,154 @@ describe('Sign in form', () => {
|
||||
await waitFor(() => expect(passwordError).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('should log in the user and navigate to homepage if login is successful', async () => {
|
||||
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => {}} isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
const submitButton = await screen.findByText('Continue');
|
||||
it('should log in the user and navigate to homepage if login is successful using button', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(usernameInput, 'test');
|
||||
userEvent.type(passwordInput, 'test');
|
||||
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: {} } });
|
||||
const submitButton = await screen.findByText('Continue');
|
||||
fireEvent.click(submitButton);
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
});
|
||||
|
||||
it('should should display login error if login not successful', async () => {
|
||||
render(<SignIn isAuthEnabled={true} setIsAuthEnabled={() => {}} isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
const submitButton = await screen.findByText('Continue');
|
||||
jest.spyOn(api, 'get').mockRejectedValue({ status: 401, data: {} });
|
||||
it('should display an error if username is blank and login is attempted using button', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(passwordInput, 'test');
|
||||
const submitButton = await screen.findByTestId('basic-auth-submit-btn');
|
||||
fireEvent.click(submitButton);
|
||||
const errorDisplay = await screen.findByText(/Authentication Failed/i);
|
||||
|
||||
await waitFor(() => expect(screen.queryByText(/enter a username/i)).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText(/enter a password/i)).not.toBeInTheDocument());
|
||||
await waitFor(() => {
|
||||
expect(errorDisplay).toBeInTheDocument();
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error if password is blank and login is attempted using button', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
userEvent.type(usernameInput, 'test');
|
||||
const submitButton = await screen.findByTestId('basic-auth-submit-btn');
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => expect(screen.queryByText(/enter a username/i)).not.toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText(/enter a password/i)).toBeInTheDocument());
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error if username and password are both blank and login is attempted using button', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const submitButton = await screen.findByTestId('basic-auth-submit-btn');
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => expect(screen.queryByText(/enter a username/i)).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText(/enter a password/i)).toBeInTheDocument());
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should log in the user and navigate to homepage if login is successful using enter key on username field', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(usernameInput, 'test');
|
||||
userEvent.type(passwordInput, 'test');
|
||||
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: {} } });
|
||||
userEvent.type(usernameInput, '{enter}');
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
});
|
||||
|
||||
it('should log in the user and navigate to homepage if login is successful using enter key on password field', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(usernameInput, 'test');
|
||||
userEvent.type(passwordInput, 'test');
|
||||
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: {} } });
|
||||
userEvent.type(passwordInput, '{enter}');
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error if username is blank and login is attempted using enter key', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(passwordInput, 'test');
|
||||
userEvent.type(passwordInput, '{enter}');
|
||||
|
||||
await waitFor(() => expect(screen.queryByText(/enter a username/i)).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText(/enter a password/i)).not.toBeInTheDocument());
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error if password is blank and login is attempted using enter key', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
userEvent.type(usernameInput, 'test');
|
||||
userEvent.type(usernameInput, '{enter}');
|
||||
|
||||
await waitFor(() => expect(screen.queryByText(/enter a username/i)).not.toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText(/enter a password/i)).toBeInTheDocument());
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error if username and password are both blank and login is attempted using enter key', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(passwordInput, '{enter}');
|
||||
|
||||
await waitFor(() => expect(screen.queryByText(/enter a username/i)).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText(/enter a password/i)).toBeInTheDocument());
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should should display login error if login not successful', async () => {
|
||||
render(<SignIn isLoggedIn={false} setIsLoggedIn={() => {}} />);
|
||||
|
||||
const usernameInput = await screen.findByLabelText(/^Username/i);
|
||||
const passwordInput = await screen.findByLabelText(/^Enter Password/i);
|
||||
userEvent.type(usernameInput, 'test');
|
||||
userEvent.type(passwordInput, 'test');
|
||||
|
||||
jest.spyOn(api, 'get').mockRejectedValue({ status: 401, data: {} });
|
||||
|
||||
const submitButton = await screen.findByText('Continue');
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText(/Authentication Failed/i)).toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(mockedUsedNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -149,8 +149,8 @@ const useStyles = makeStyles(() => ({
|
||||
export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading = () => {} }) {
|
||||
const [usernameError, setUsernameError] = useState(null);
|
||||
const [passwordError, setPasswordError] = useState(null);
|
||||
const [username, setUsername] = useState(null);
|
||||
const [password, setPassword] = useState(null);
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [requestProcessing, setRequestProcessing] = useState(false);
|
||||
const [requestError, setRequestError] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@ -228,13 +228,20 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading =
|
||||
});
|
||||
};
|
||||
|
||||
const handleClick = (event) => {
|
||||
event.preventDefault();
|
||||
if (Object.keys(authMethods).includes('htpasswd')) {
|
||||
const handleBasicAuthSubmit = () => {
|
||||
setRequestError(false);
|
||||
const isUsernameValid = handleUsernameValidation(username);
|
||||
const isPasswordValid = handlePasswordValidation(password);
|
||||
if (Object.keys(authMethods).includes('htpasswd') && isUsernameValid && isPasswordValid) {
|
||||
handleBasicAuth();
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = (event) => {
|
||||
event.preventDefault();
|
||||
handleBasicAuthSubmit();
|
||||
};
|
||||
|
||||
const handleGuestClick = () => {
|
||||
setRequestProcessing(false);
|
||||
setRequestError(false);
|
||||
@ -251,35 +258,55 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading =
|
||||
);
|
||||
};
|
||||
|
||||
const handleUsernameValidation = (username) => {
|
||||
let isValid = true;
|
||||
if (username === '') {
|
||||
setUsernameError('Please enter a username');
|
||||
isValid = false;
|
||||
} else {
|
||||
setUsernameError(null);
|
||||
}
|
||||
return isValid;
|
||||
};
|
||||
|
||||
const handlePasswordValidation = (password) => {
|
||||
let isValid = true;
|
||||
if (password === '') {
|
||||
setPasswordError('Please enter a password');
|
||||
isValid = false;
|
||||
} else {
|
||||
setPasswordError(null);
|
||||
}
|
||||
return isValid;
|
||||
};
|
||||
|
||||
const handleChange = (event, type) => {
|
||||
event.preventDefault();
|
||||
setRequestError(false);
|
||||
|
||||
const val = event.target?.value;
|
||||
const isEmpty = val === '';
|
||||
|
||||
switch (type) {
|
||||
case 'username':
|
||||
setUsername(val);
|
||||
if (isEmpty) {
|
||||
setUsernameError('Please enter a username');
|
||||
} else {
|
||||
setUsernameError(null);
|
||||
}
|
||||
handleUsernameValidation(val);
|
||||
break;
|
||||
case 'password':
|
||||
setPassword(val);
|
||||
if (isEmpty) {
|
||||
setPasswordError('Please enter a password');
|
||||
} else {
|
||||
setPasswordError(null);
|
||||
}
|
||||
handlePasswordValidation(val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoginInputFieldKeyDown = (event) => {
|
||||
const keyPressed = event.key;
|
||||
if (keyPressed === 'Enter') {
|
||||
handleBasicAuthSubmit();
|
||||
}
|
||||
};
|
||||
|
||||
const renderThirdPartyLoginMethods = () => {
|
||||
let isGoogle = isObject(authMethods.openid?.providers?.google);
|
||||
// let isGitlab = isObject(authMethods.openid?.providers?.gitlab);
|
||||
@ -315,7 +342,7 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading =
|
||||
{Object.keys(authMethods).length > 1 &&
|
||||
Object.keys(authMethods).includes('openid') &&
|
||||
Object.keys(authMethods.openid.providers).length > 0 && (
|
||||
<Divider className={classes.divider} data-testId="openid-divider">
|
||||
<Divider className={classes.divider} data-testid="openid-divider">
|
||||
or
|
||||
</Divider>
|
||||
)}
|
||||
@ -334,6 +361,7 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading =
|
||||
onInput={(e) => handleChange(e, 'username')}
|
||||
error={usernameError != null}
|
||||
helperText={usernameError}
|
||||
onKeyDown={(e) => handleLoginInputFieldKeyDown(e)}
|
||||
/>
|
||||
<TextField
|
||||
margin="normal"
|
||||
@ -349,6 +377,7 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading =
|
||||
onInput={(e) => handleChange(e, 'password')}
|
||||
error={passwordError != null}
|
||||
helperText={passwordError}
|
||||
onKeyDown={(e) => handleLoginInputFieldKeyDown(e)}
|
||||
/>
|
||||
{requestProcessing && <CircularProgress style={{ marginTop: 20 }} color="secondary" />}
|
||||
{requestError && (
|
||||
@ -357,7 +386,13 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading =
|
||||
</Alert>
|
||||
)}
|
||||
<div>
|
||||
<Button fullWidth variant="contained" className={classes.continueButton} onClick={handleClick}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.continueButton}
|
||||
onClick={handleClick}
|
||||
data-testid="basic-auth-submit-btn"
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user