-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add reset password forms (#414)
* fix: update UI version * feat: show differnt success message for password on success, refactor * feat: add request password request and reset pages * fix: update strict typescript and layout * fix: add tests for request password request * fix: udpate transaltion strings * fix: update translation strings * fix: all tests for the full functionality * fix: all tests for the full functionality * fix: improve email adornment * fix: add button to go to forgot password page if error occurs * fix: add better screen that check the validity of the jwt * fix: jwt token tests * fix: sign in password test fix * fix: use a different domain for the redirection link * fix: update workflow * fix: run instanbul in test mode * fix: update config * fix: update config and script * fix: update env vars * fix: force build instrument * fix: add a trycatch for invalid tokens * fix: email constant and simplify rendering condition * fix: apply review comments * fix: translate requirements text * fix: url in test * fix: rename hook file --------- Co-authored-by: spaenleh <[email protected]>
- Loading branch information
Showing
49 changed files
with
1,187 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { REQUEST_PASSWORD_RESET_PATH } from '../../src/config/paths'; | ||
import { | ||
REQUEST_PASSWORD_RESET_EMAIL_FIELD_HELPER_ID, | ||
REQUEST_PASSWORD_RESET_EMAIL_FIELD_ID, | ||
REQUEST_PASSWORD_RESET_ERROR_MESSAGE_ID, | ||
REQUEST_PASSWORD_RESET_SUBMIT_BUTTON_ID, | ||
REQUEST_PASSWORD_RESET_SUCCESS_MESSAGE_ID, | ||
} from '../../src/config/selectors'; | ||
import { MEMBERS } from '../fixtures/members'; | ||
|
||
describe('Request password reset', () => { | ||
it('For existing member', () => { | ||
cy.setUpApi(); | ||
cy.visit(REQUEST_PASSWORD_RESET_PATH); | ||
// request password reset for an existing member | ||
cy.get(`#${REQUEST_PASSWORD_RESET_EMAIL_FIELD_ID}`).type( | ||
MEMBERS.GRAASP.email, | ||
); | ||
cy.get(`#${REQUEST_PASSWORD_RESET_SUBMIT_BUTTON_ID}`).click(); | ||
cy.get(`#${REQUEST_PASSWORD_RESET_SUCCESS_MESSAGE_ID}`).should( | ||
'be.visible', | ||
); | ||
}); | ||
it('For non-email', () => { | ||
cy.setUpApi(); | ||
cy.visit(REQUEST_PASSWORD_RESET_PATH); | ||
|
||
cy.get(`#${REQUEST_PASSWORD_RESET_EMAIL_FIELD_ID}`).type( | ||
MEMBERS.WRONG_EMAIL.email, | ||
); | ||
|
||
// click the button to trigger the validation | ||
cy.get(`#${REQUEST_PASSWORD_RESET_SUBMIT_BUTTON_ID}`).click(); | ||
cy.get(`#${REQUEST_PASSWORD_RESET_SUBMIT_BUTTON_ID}`).should('be.disabled'); | ||
|
||
cy.get(`#${REQUEST_PASSWORD_RESET_EMAIL_FIELD_HELPER_ID}`).should( | ||
'contain.text', | ||
'This does not look like a valid email address', | ||
); | ||
}); | ||
it('For non-member', () => { | ||
cy.setUpApi({ shouldFailRequestPasswordReset: true }); | ||
cy.visit(REQUEST_PASSWORD_RESET_PATH); | ||
|
||
cy.get(`#${REQUEST_PASSWORD_RESET_EMAIL_FIELD_ID}`).type( | ||
MEMBERS.GRAASP.email, | ||
); | ||
|
||
cy.get(`#${REQUEST_PASSWORD_RESET_SUBMIT_BUTTON_ID}`).click(); | ||
|
||
// expect the backend to fail the request because the captcha was not sent | ||
cy.get(`#${REQUEST_PASSWORD_RESET_ERROR_MESSAGE_ID}`).should( | ||
'contain.text', | ||
'There was an error making your request', | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { RESET_PASSWORD_PATH } from '../../src/config/paths'; | ||
import { | ||
RESET_PASSWORD_ERROR_MESSAGE_ID, | ||
RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ERROR_TEXT_ID, | ||
RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ID, | ||
RESET_PASSWORD_NEW_PASSWORD_FIELD_ERROR_TEXT_ID, | ||
RESET_PASSWORD_NEW_PASSWORD_FIELD_ID, | ||
RESET_PASSWORD_SUBMIT_BUTTON_ID, | ||
RESET_PASSWORD_SUCCESS_MESSAGE_ID, | ||
RESET_PASSWORD_TOKEN_ERROR_ID, | ||
} from '../../src/config/selectors'; | ||
import { MEMBERS } from '../fixtures/members'; | ||
import { generateJWT } from './util'; | ||
|
||
describe('Reset password', () => { | ||
describe('With valid token', () => { | ||
it('With strong password', () => { | ||
cy.setUpApi(); | ||
|
||
// this allows to run async code in cypress | ||
cy.wrap(null).then(async () => { | ||
const token = await generateJWT('1234'); | ||
cy.visit(`${RESET_PASSWORD_PATH}?t=${token}`); | ||
}); | ||
|
||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_FIELD_ID}`).type( | ||
MEMBERS.GRAASP.password, | ||
); | ||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ID}`).type( | ||
MEMBERS.GRAASP.password, | ||
); | ||
cy.get(`#${RESET_PASSWORD_SUBMIT_BUTTON_ID}`).click(); | ||
cy.get(`#${RESET_PASSWORD_SUCCESS_MESSAGE_ID}`).should('be.visible'); | ||
}); | ||
|
||
it('With weak password', () => { | ||
cy.setUpApi(); | ||
|
||
// this allows to run async code in cypress | ||
cy.wrap(null).then(async () => { | ||
const token = await generateJWT('1234'); | ||
cy.visit(`${RESET_PASSWORD_PATH}?t=${token}`); | ||
}); | ||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_FIELD_ID}`).type('weak'); | ||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ID}`).type( | ||
'weak', | ||
); | ||
cy.get(`#${RESET_PASSWORD_SUBMIT_BUTTON_ID}`).click(); | ||
cy.get(`#${RESET_PASSWORD_SUBMIT_BUTTON_ID}`).should('be.disabled'); | ||
|
||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_FIELD_ERROR_TEXT_ID}`).should( | ||
'contain.text', | ||
'This password is too weak', | ||
); | ||
|
||
cy.get( | ||
`#${RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ERROR_TEXT_ID}`, | ||
).should('contain.text', 'This password is too weak'); | ||
}); | ||
|
||
it('Without matching passwords', () => { | ||
cy.setUpApi(); | ||
|
||
// this allows to run async code in cypress | ||
cy.wrap(null).then(async () => { | ||
const token = await generateJWT('1234'); | ||
cy.visit(`${RESET_PASSWORD_PATH}?t=${token}`); | ||
}); | ||
|
||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_FIELD_ID}`).type('aPassword1'); | ||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ID}`).type( | ||
'aPassword2', | ||
); | ||
cy.get(`#${RESET_PASSWORD_SUBMIT_BUTTON_ID}`).click(); | ||
cy.get(`#${RESET_PASSWORD_SUBMIT_BUTTON_ID}`).should('be.disabled'); | ||
|
||
cy.get( | ||
`#${RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ERROR_TEXT_ID}`, | ||
).should('contain.text', 'The passwords do not match.'); | ||
}); | ||
|
||
it('With server error', () => { | ||
cy.setUpApi({ shouldFailResetPassword: true }); | ||
|
||
// this allows to run async code in cypress | ||
cy.wrap(null).then(async () => { | ||
const token = await generateJWT('1234'); | ||
cy.visit(`${RESET_PASSWORD_PATH}?t=${token}`); | ||
}); | ||
|
||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_FIELD_ID}`).type('aPassword1'); | ||
cy.get(`#${RESET_PASSWORD_NEW_PASSWORD_CONFIRMATION_FIELD_ID}`).type( | ||
'aPassword1', | ||
); | ||
|
||
cy.get(`#${RESET_PASSWORD_SUBMIT_BUTTON_ID}`).click(); | ||
|
||
// the backend fails the request (token is not valid for example) | ||
cy.get(`#${RESET_PASSWORD_ERROR_MESSAGE_ID}`).should( | ||
'contain.text', | ||
'An error prevented the password reset operation.', | ||
); | ||
}); | ||
}); | ||
|
||
describe('Invalid token', () => { | ||
it('Without token', () => { | ||
cy.setUpApi(); | ||
cy.visit(RESET_PASSWORD_PATH); | ||
|
||
// a rough error message is displayed when the url does not | ||
// contain the required query string argument `t` containing the token | ||
cy.get(`#${RESET_PASSWORD_TOKEN_ERROR_ID}`).should( | ||
'contain.text', | ||
'No token was provided or the provided token is expired.', | ||
); | ||
}); | ||
|
||
it('Not a JWT token', () => { | ||
cy.setUpApi(); | ||
cy.visit(`${RESET_PASSWORD_PATH}?t=${'1234'}`); | ||
|
||
// a rough error message is displayed when the url does not | ||
// contain the required query string argument `t` containing the token | ||
cy.get(`#${RESET_PASSWORD_TOKEN_ERROR_ID}`).should( | ||
'contain.text', | ||
'No token was provided or the provided token is expired.', | ||
); | ||
}); | ||
|
||
it('Expired token', () => { | ||
cy.setUpApi(); | ||
|
||
// this allows to run async code in cypress | ||
cy.wrap(null).then(async () => { | ||
const token = await generateJWT('1234', '25h ago'); | ||
cy.visit(`${RESET_PASSWORD_PATH}?t=${token}`); | ||
}); | ||
|
||
// a rough error message is displayed when the url does not | ||
// contain the required query string argument `t` containing the token | ||
cy.get(`#${RESET_PASSWORD_TOKEN_ERROR_ID}`).should( | ||
'contain.text', | ||
'No token was provided or the provided token is expired.', | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.