Skip to content

Commit

Permalink
MM-15008 E2E: Test forgot password for email with valid account on se…
Browse files Browse the repository at this point in the history
…rver (mattermost#2853)

* E2E: Test forgot password for email with valid account on server

* update per feedback re:using new user
  • Loading branch information
saturninoabril authored and sudheerDev committed May 31, 2019
1 parent ad9a0a3 commit 672201c
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 18 deletions.
5 changes: 4 additions & 1 deletion components/login/login_controller/login_controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,10 @@ class LoginController extends React.Component {
);
} else if (extraParam === Constants.PASSWORD_CHANGE) {
return (
<div className='alert alert-success'>
<div
id='passwordUpdatedSuccess'
className='alert alert-success'
>
<SuccessIcon/>
<FormattedMessage
id='login.passwordChanged'
Expand Down
3 changes: 3 additions & 0 deletions components/password_reset_form/password_reset_form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,19 @@ class PasswordResetForm extends React.Component {
</p>
<div className={formClass}>
<LocalizedInput
id='resetPasswordInput'
type='password'
className='form-control'
name='password'
ref='password'
placeholder={{id: t('password_form.pwd'), defaultMessage: 'Password'}}
spellCheck='false'
autoFocus={true}
/>
</div>
{error}
<button
id='resetPasswordButton'
type='submit'
className='btn btn-primary'
>
Expand Down
25 changes: 11 additions & 14 deletions components/password_reset_send_link.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// See LICENSE.txt for license information.

import $ from 'jquery';
import PropTypes from 'prop-types';
import React from 'react';
import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';
Expand All @@ -15,18 +14,17 @@ import LocalizedInput from 'components/localized_input/localized_input';

import {t} from 'utils/i18n.jsx';

class PasswordResetSendLink extends React.Component {
export default class PasswordResetSendLink extends React.Component {
constructor(props) {
super(props);

this.handleSendLink = this.handleSendLink.bind(this);

this.state = {
error: '',
updateText: '',
};
}
handleSendLink(e) {

handleSendLink = (e) => {
e.preventDefault();

var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
Expand All @@ -53,7 +51,10 @@ class PasswordResetSendLink extends React.Component {
this.setState({
error: null,
updateText: (
<div className='reset-form alert alert-success'>
<div
id='passwordResetEmailSent'
className='reset-form alert alert-success'
>
<FormattedMessage
id='password_send.link'
defaultMessage='If the account exists, a password reset email will be sent to:'
Expand All @@ -79,6 +80,7 @@ class PasswordResetSendLink extends React.Component {
}
);
}

render() {
var error = null;
if (this.state.error) {
Expand Down Expand Up @@ -114,16 +116,19 @@ class PasswordResetSendLink extends React.Component {
</p>
<div className={formClass}>
<LocalizedInput
id='passwordResetEmailInput'
type='email'
className='form-control'
name='email'
ref='email'
placeholder={{id: t('password_send.email'), defaultMessage: 'Email'}}
spellCheck='false'
autoFocus={true}
/>
</div>
{error}
<button
id='passwordResetButton'
type='submit'
className='btn btn-primary'
>
Expand All @@ -139,11 +144,3 @@ class PasswordResetSendLink extends React.Component {
);
}
}

PasswordResetSendLink.defaultProps = {
};
PasswordResetSendLink.propTypes = {
params: PropTypes.object.isRequired,
};

export default PasswordResetSendLink;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import users from '../../fixtures/users.json';
import * as TIMEOUTS from '../../fixtures/timeouts';

const reUrl = /(https?:\/\/[^ ]*)/;
import {reUrl} from '../../utils';

const user1 = users['user-1'];
const user2 = users['user-2'];
Expand Down
132 changes: 132 additions & 0 deletions cypress/integration/signin_authentication/forgot_password_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

// ***************************************************************
// - [#] indicates a test step (e.g. 1. Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************

/*eslint max-nested-callbacks: ["error", 5]*/

import {reUrl} from '../../utils';

const feedbackEmail = '[email protected]';

describe('Signin/Authentication', () => {
before(() => {
cy.apiUpdateConfig({EmailSettings: {FeedbackEmail: feedbackEmail}});
});

it('SA15008 - Sign In Forgot password - Email address has account on server', () => {
cy.loginAsNewUser().then((user) => {
cy.apiLogout();

resetPasswordAndLogin(user, feedbackEmail);
});
});
});

function verifyForgotPasswordEmail(response, toUser, fromEmail) {
const isoDate = new Date().toISOString().substring(0, 10);
const {data, status} = response;

// * Should return success status
expect(status).to.equal(200);

// * Verify that email is addressed to user-1
expect(data.to.length).to.equal(1);
expect(data.to[0]).to.contain(toUser.email);

// * Verify that email is from default feedback email
expect(data.from).to.contain(fromEmail);

// * Verify that date is current
expect(data.date).to.contain(isoDate);

// * Verify that the email subject is correct
expect(data.subject).to.equal('[Mattermost] Reset your password');

// * Verify that the email body is correct
const bodyText = data.body.text.split('\r\n');
expect(bodyText.length).to.equal(14);
expect(bodyText[1]).to.equal('You requested a password reset');
expect(bodyText[4]).to.equal('To change your password, click "Reset Password" below.');
expect(bodyText[5]).to.contain('If you did not mean to reset your password, please ignore this email and your password will remain the same. The password reset link expires in 24 hours.');
expect(bodyText[7]).to.contain('Reset Password');
expect(bodyText[9]).to.contain('Any questions at all, mail us any time: [email protected]');
expect(bodyText[10]).to.equal('Best wishes,');
expect(bodyText[11]).to.equal('The Mattermost Team');
expect(bodyText[13]).to.equal('To change your notification preferences, log in to your team site and go to Account Settings > Notifications.');
}

function resetPasswordAndLogin(user, fromEmail) {
const newPassword = 'newpasswd';

// # Visit '/'
cy.visit('/');

// * Verify that it redirects to /login
cy.url().should('contain', '/login');

// * Verify that forgot password link is present
// # Click forgot password link
cy.get('#login_forgot > a').should('be.visible').and('have.text', 'I forgot my password').click();

// * Verify that it redirects to /reset_password
cy.url().should('contain', '/reset_password');

// * Verify that the focus is set to passwordResetEmailInput
cy.focused().should('have.attr', 'id', 'passwordResetEmailInput');

// # Type user email into email input field and click reset button
cy.get('#passwordResetEmailInput').type(user.email);
cy.get('#passwordResetButton').click();

// * Should show that the password reset email is sent
cy.get('#passwordResetEmailSent').should('be.visible').within(() => {
cy.get('span').first().should('have.text', 'If the account exists, a password reset email will be sent to:');
cy.get('div b').first().should('have.text', user.email);
cy.get('span').last().should('have.text', 'Please check your inbox.');
});

cy.task('getRecentEmail', {username: user.username}).then((response) => {
// * Verify contents password reset email
verifyForgotPasswordEmail(response, user, fromEmail);

const bodyText = response.data.body.text.split('\r\n');
const passwordResetLink = bodyText[7].match(reUrl)[0];
const token = passwordResetLink.split('token=')[1];

// * Verify length of a token
expect(token.length).to.equal(64);

// # Visit password reset link (e.g. click on email link)
cy.visit(passwordResetLink);
cy.url().should('contain', '/reset_password_complete?token=');

// * Verify that the focus is set to resetPasswordInput
cy.focused().should('have.attr', 'id', 'resetPasswordInput');

// # Type new password and click reset button
cy.get('#resetPasswordInput').type(newPassword);
cy.get('#resetPasswordButton').click();

// * Verify that it redirects to /login?extra=password_change
cy.url().should('contain', '/login?extra=password_change');

// * Should show that the password is updated successfully
cy.get('#passwordUpdatedSuccess').should('be.visible').and('have.text', ' Password updated successfully');

// # Type email and new password, then click login button
cy.get('#loginId').should('be.visible').type(user.username);
cy.get('#loginPassword').should('be.visible').type(newPassword);
cy.get('#loginButton').click();

// * Verify that it successfully logged in and redirects to /ad-1/channels/town-square
cy.url().should('contain', '/ad-1/channels/town-square');

// # Logout
cy.apiLogout();
});
}
11 changes: 9 additions & 2 deletions cypress/support/api_commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ Cypress.Commands.add('apiSaveThemePreference', (value = JSON.stringify(theme.def
});
});

// *****************************************************************************
// Users
// https://api.mattermost.com/#tag/users
// *****************************************************************************

/**
* Creates a new user via the API, adds them to 3 teams, and sets preference to bypass tutorial.
* Then logs in as the user
Expand All @@ -238,7 +243,7 @@ Cypress.Commands.add('apiSaveThemePreference', (value = JSON.stringify(theme.def
Cypress.Commands.add('loginAsNewUser', (user = {}) => {
const timestamp = Date.now();

const {email = `newE2ETestUser${timestamp}@mattermost.com`, username = `NewE2ETestUser${timestamp}`, password = 'password123'} = user;
const {email = `newe2etestuser${timestamp}@sample.mattermost.com`, username = `NewE2ETestUser${timestamp}`, password = 'password123'} = user;

// # Login as sysadmin to make admin requests
cy.apiLogin('sysadmin');
Expand Down Expand Up @@ -292,7 +297,8 @@ Cypress.Commands.add('loginAsNewUser', (user = {}) => {
});

// *****************************************************************************
// Pinned Posts
// Posts
// https://api.mattermost.com/#tag/posts
// *****************************************************************************

/**
Expand All @@ -310,6 +316,7 @@ Cypress.Commands.add('apiUnpinPosts', (postId) => {

// *****************************************************************************
// System config
// https://api.mattermost.com/#tag/system
// *****************************************************************************

Cypress.Commands.add('apiUpdateConfig', (newSettings = {}) => {
Expand Down
2 changes: 2 additions & 0 deletions cypress/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}

export const reUrl = /(https?:\/\/[^ ]*)/;

0 comments on commit 672201c

Please sign in to comment.