diff --git a/src/login/LoginFailure.jsx b/src/login/LoginFailure.jsx
index 08cd02f8..06cdb1f1 100644
--- a/src/login/LoginFailure.jsx
+++ b/src/login/LoginFailure.jsx
@@ -23,6 +23,13 @@ const LoginFailureMessage = (props) => {
const { context, errorCode, value } = props.loginError;
let errorList;
let link;
+ const resetLink = (
+ <>
+
+ {intl.formatMessage(messages['login.incorrect.credentials.error.reset.link.text'])}
+
+ >
+ );
switch (errorCode) {
case NON_COMPLIANT_PASSWORD_EXCEPTION: {
@@ -87,60 +94,52 @@ const LoginFailureMessage = (props) => {
);
break;
case FAILED_LOGIN_ATTEMPT: {
- const resetLink = (
-
- {intl.formatMessage(messages['login.failed.link.text'])}
-
- );
errorList = (
- <>
-
- {intl.formatMessage(messages['login.incorrect.credentials.error'])}
-
-
- {intl.formatMessage(messages['login.failed.attempt.error'], { remainingAttempts: context.remainingAttempts })}
-
-
-
-
- >
+ ,
+ remainingAttempts: {context.remainingAttempts},
+ warning: Warning: ,
+ allowedFailureAttempts: {context.allowedFailureAttempts} consecutive,
+ resetLink,
+ }}
+ />
);
break;
}
case ACCOUNT_LOCKED_OUT: {
- const resetLink = (
-
- {intl.formatMessage(messages['login.failed.link.text'])}
-
- );
errorList = (
- <>
-
- {intl.formatMessage(messages['login.locked.out.error.message'], { lockedOutPeriod: context.lockedOutPeriod })}
-
-
-
-
- >
+ ,
+ resetLink,
+ blockText: Your account {props.loginError.email} is blocked for 30 minutes due to reaching the maximum {context.allowedFailureAttempts} failed login attempts.
,
+ }}
+ />
);
break;
}
case INCORRECT_EMAIL_PASSWORD:
- errorList = (
-
- {intl.formatMessage(messages['login.incorrect.credentials.error'])}
-
- );
+ if (context.failureCount <= 1) {
+ errorList = intl.formatMessage(messages['login.incorrect.credentials.error']);
+ } else if (context.failureCount === 2) {
+ errorList = (
+
+ );
+ }
break;
default:
// TODO: use errorCode instead of processing error messages on frontend
@@ -167,7 +166,7 @@ const LoginFailureMessage = (props) => {
}
return (
-
+
{intl.formatMessage(messages['login.failure.header.title'])}
{ errorList }
diff --git a/src/login/messages.jsx b/src/login/messages.jsx
index 900abf8c..ff546bab 100644
--- a/src/login/messages.jsx
+++ b/src/login/messages.jsx
@@ -178,16 +178,16 @@ const messages = defineMessages({
defaultMessage: 'contact {platformName} support',
description: 'Link text used in inactive user error message to go to learner help center',
},
- 'login.failed.link.text': {
- id: 'login.failed.link.text',
- defaultMessage: 'here',
- description: 'Link text used in failed login attempt user error message to reset password',
- },
'login.incorrect.credentials.error': {
id: 'login.incorrect.credentials.error',
- defaultMessage: 'Email or password is incorrect.',
+ defaultMessage: 'The username, email or password you entered is incorrect. Please try again.',
description: 'Error message for incorrect email or password',
},
+ 'login.incorrect.credentials.error.with.reset.link': {
+ id: 'login.incorrect.credentials.error.with.reset.link',
+ defaultMessage: 'The username, email or password you entered is incorrect. Please try again or {resetLink}.',
+ description: 'Error message for incorrect email or password with reset link',
+ },
'login.failed.attempt.error': {
id: 'login.failed.attempt.error',
defaultMessage: 'You have {remainingAttempts} more sign in attempts before your account is temporarily locked.',
@@ -203,6 +203,11 @@ const messages = defineMessages({
defaultMessage: 'Please fill in the fields below.',
description: 'Login form empty input user message',
},
+ 'login.incorrect.credentials.error.reset.link.text': {
+ id: 'login.incorrect.credentials.error.reset.link.text',
+ defaultMessage: 'reset your password',
+ description: 'Reset password link text for incorrect email or password credentials',
+ },
});
export default messages;
diff --git a/src/login/tests/LoginFailure.test.jsx b/src/login/tests/LoginFailure.test.jsx
index 1690aa27..bbae064c 100644
--- a/src/login/tests/LoginFailure.test.jsx
+++ b/src/login/tests/LoginFailure.test.jsx
@@ -10,6 +10,8 @@ import {
INTERNAL_SERVER_ERROR,
INVALID_FORM,
NON_COMPLIANT_PASSWORD_EXCEPTION,
+ FAILED_LOGIN_ATTEMPT,
+ INCORRECT_EMAIL_PASSWORD,
} from '../data/constants';
const IntlLoginFailureMessage = injectIntl(LoginFailureMessage);
@@ -64,6 +66,74 @@ describe('LoginFailureMessage', () => {
expect(loginFailureMessage.find('#login-failure-alert').find('a').props().href).toEqual('https://support.edx.org/');
});
+ it('test match failed login attempt error', () => {
+ props = {
+ loginError: {
+ email: 'text@example.com',
+ errorCode: FAILED_LOGIN_ATTEMPT,
+ context: {
+ remainingAttempts: 3,
+ allowedFailureAttempts: 6,
+ resetLink: '/reset',
+ },
+ },
+ };
+
+ const loginFailureMessage = mount(
+
+
+ ,
+ );
+ const expectedMessage = 'We couldn\'t sign you in.The username, email or password you entered is incorrect. Please try again or '
+ + 'reset your password Attempts remaining: 3 Warning: After 6 consecutive unsuccessful login attempts, your account will be locked.';
+
+ expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
+ });
+
+ it('test match failed login error first attempt', () => {
+ props = {
+ loginError: {
+ email: 'text@example.com',
+ errorCode: INCORRECT_EMAIL_PASSWORD,
+ context: {
+ failureCount: 1,
+ resetLink: '/reset',
+ },
+ },
+ };
+
+ const loginFailureMessage = mount(
+
+
+ ,
+ );
+ const expectedMessage = 'We couldn\'t sign you in.The username, email or password you entered is incorrect. Please try again.';
+
+ expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
+ });
+
+ it('test match failed login error second attempt', () => {
+ props = {
+ loginError: {
+ email: 'text@example.com',
+ errorCode: INCORRECT_EMAIL_PASSWORD,
+ context: {
+ failureCount: 2,
+ resetLink: '/reset',
+ },
+ },
+ };
+
+ const loginFailureMessage = mount(
+
+
+ ,
+ );
+ const expectedMessage = 'We couldn\'t sign you in.The username, email or password you entered is incorrect. Please try again or reset your password.';
+
+ expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
+ });
+
it('should match rate limit error message', () => {
props = {
loginError: {