Cypress test for the profile settings page (#3083)

* Added cypress test for profile settings page

* Updated common selectors

* Updated common text

* Added functions for random names

* Added data-cy attributes for components

* Added verification for the input value

* Added password field validation

* Added common utils file

* Added wait

* Updated login error toast
This commit is contained in:
Ajith KV 2022-06-01 13:42:53 +05:30 committed by GitHub
parent cacce68713
commit cb678190d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 267 additions and 30 deletions

View file

@ -1,15 +1,18 @@
export const commonSelectors={ export const commonSelectors={
toastMessage: ".go318386747", toastMessage: ".go318386747",
appCard: "[data-cy=app-card]", appCard: "[data-cy=app-card]",
editButton: "[data-cy=edit-button]", editButton: "[data-cy=edit-button]",
searchField:"[data-cy=widget-search-box]", searchField:"[data-cy=widget-search-box]",
firstWidget:"[data-cy=widget-list]:eq(0)", firstWidget:"[data-cy=widget-list]:eq(0)",
canvas:"[data-cy=real-canvas]", canvas:"[data-cy=real-canvas]",
appCardOptions: "[data-cy=app-card-menu-icon]", appCardOptions: "[data-cy=app-card-menu-icon]",
deleteApp: "[data-cy=card-options] :nth-child(5)>span", deleteApp: "[data-cy=card-options] :nth-child(5)>span",
confirmButton: "[data-cy=confirm-yes-button]", confirmButton: "[data-cy=confirm-yes-button]",
autoSave: "[data-cy=autosave-indicator]", autoSave: "[data-cy=autosave-indicator]",
skipButton: ".driver-close-btn", skipButton: ".driver-close-btn",
skipInstallationModal: "[data-cy=skip-button]", skipInstallationModal: "[data-cy=skip-button]",
homePageLogo: "[data-cy=home-page-logo]" homePageLogo: "[data-cy=home-page-logo]",
emailField: "[data-cy=email-text-field]",
passwordField: "[data-cy=password-text-field]",
signInButton: "[data-cy=login-button]",
} }

View file

@ -0,0 +1,22 @@
export const profileSelector={
profileDropdown: "[data-cy=dropdown-menu]",
profileLink: "[data-cy=profile-link]",
logoutLink: "[data-cy=logout-link]",
profileElements:{
pageTitle: "[data-cy=page-title]",
profileCard: "[data-cy=card-title-profile]",
firstNameLabel: "[data-cy=first-name-label]",
lastNameLabel: "[data-cy=last-name-label]",
emailLabel: "[data-cy=email-label]",
passwordCard: "[data-cy=card-title-change-password]",
currentPasswordLabel: "[data-cy=current-password-label]",
newPasswordLabel: "[data-cy=new-password-label]",
},
firstNameInput: "[data-cy=first-name-input]",
lastNameInput: "[data-cy=last-name-input]",
emailInput: "[data-cy=email-input]",
updateButton: "[data-cy=update-button]",
changePasswordButton: "[data-cy=change-password-button]",
currentPasswordField: "[data-cy=current-password-input]",
newPasswordField: "[data-cy=new-password-input]",
}

View file

@ -1,9 +1,12 @@
export const path={ export const path={
loginPath:"/login", loginPath: "/login",
profilePath: "/settings"
} }
export const commonText={ export const commonText={
autoSave:"All changes are saved" autoSave: "All changes are saved",
email: "dev@tooljet.io",
password: "password"
} }

View file

@ -0,0 +1,23 @@
export const profileText={
profileElements:{
pageTitle: "Profile Settings",
profileCard: "Profile",
firstNameLabel: "First name ",
lastNameLabel: "Last name",
emailLabel: "Email ",
passwordCard: "Change password",
currentPasswordLabel: "Current password",
newPasswordLabel: "New password",
},
firstName: "The",
lastName: "Developer",
updateButton: "Update",
email: "dev@tooljet.io",
nameSuccessToast: "Details updated!",
nameErrorToast: "Name can't be empty!",
newPassword: "newpassword",
changePasswordButton: "Change password",
passwordErrorToast: "Please verify that you have entered the correct password",
passwordSuccessToast: "Password updated successfully",
loginErrorToast:"Invalid email or password",
}

View file

@ -2,12 +2,18 @@ import faker from 'faker'
export let fake ={}; export let fake ={};
function email(){ function email(){
return (`${faker.name.findName()}@example.com`) return (`${faker.name.findName()}@example.com`);
} }
function password(){ function password(){
return(faker.internet.password()) return(faker.internet.password());
}
function firstName(){
return (faker.name.firstName());
}
function lastName(){
return (faker.name.lastName());
} }
Object.defineProperty(fake, "email", {get:email}); Object.defineProperty(fake, "email", {get:email});
Object.defineProperty(fake, "password", {get:password}); Object.defineProperty(fake, "password", {get:password});
Object.defineProperty(fake, "firstName", {get:firstName});
Object.defineProperty(fake, "lastName", {get:lastName});

View file

@ -0,0 +1,120 @@
import { profileSelector } from "Selectors/profile";
import * as profile from "Support/utils/profile"
import * as common from "Support/utils/common"
import { profileText } from "Texts/profile";
import {commonSelectors} from "Selectors/common";
import { fake } from "Fixtures/fake";
import { commonText } from "Texts/common";
describe("Profile Settings",()=>{
let user;
const randomFirstName = fake.firstName;
const randomLastName = fake.lastName;
beforeEach(()=>{
cy.fixture("credentials/login.json").then(login=>{
user = login;
});
cy.appUILogin();
common.navigateToProfile();
});
it("Should verify the elements on profile settings page and name reset functionality",()=>{
profile.profilePageElements();
cy.get(profileSelector.updateButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.nameSuccessToast);
cy.get(profileSelector.firstNameInput).clear();
cy.get(profileSelector.updateButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.nameErrorToast);
cy.get(profileSelector.lastNameInput).clear();
cy.get(profileSelector.updateButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.nameErrorToast);
cy.clearAndType(profileSelector.firstNameInput , profileText.firstName);
cy.get(profileSelector.updateButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.nameErrorToast);
cy.clearAndType(profileSelector.firstNameInput , randomFirstName);
cy.clearAndType(profileSelector.lastNameInput , randomLastName);
cy.get(profileSelector.updateButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.nameSuccessToast);
cy.get(profileSelector.firstNameInput).should("be.visible").and("have.value", randomFirstName);
cy.get(profileSelector.lastNameInput).should("be.visible").and("have.value", randomLastName);
cy.clearAndType(profileSelector.firstNameInput , profileText.firstName);
cy.clearAndType(profileSelector.lastNameInput , profileText.lastName);
cy.get(profileSelector.updateButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.nameSuccessToast);
cy.get(profileSelector.firstNameInput).should("be.visible").and("have.value", profileText.firstName);
cy.get(profileSelector.lastNameInput).should("be.visible").and("have.value", profileText.lastName);
common.logout();
})
it("Should verify the password reset functionality",()=>{
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage, profileText.passwordErrorToast);
cy.get(profileSelector.currentPasswordField).should("have.value", "");
cy.get(profileSelector.newPasswordField).should("have.value", "");
cy.clearAndType(profileSelector.currentPasswordField, user.password);
cy.get(profileSelector.currentPasswordField).should("have.value", user.password);
cy.get(profileSelector.newPasswordField).should("have.value", "");
cy.wait(500);
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordSuccessToast);
cy.clearAndType(profileSelector.currentPasswordField, profileText.newPassword);
cy.get(profileSelector.currentPasswordField).should("have.value", profileText.newPassword )
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordErrorToast);
cy.get(profileSelector.currentPasswordField).clear();
cy.clearAndType(profileSelector.newPasswordField,profileText.newPassword);
cy.get(profileSelector.newPasswordField).should("have.value", profileText.newPassword )
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordErrorToast);
cy.clearAndType(profileSelector.currentPasswordField, profileText.newPassword);
cy.get(profileSelector.currentPasswordField).should("have.value", profileText.newPassword)
cy.clearAndType(profileSelector.newPasswordField, user.password);
cy.get(profileSelector.newPasswordField).should("have.value", user.password )
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordErrorToast);
cy.clearAndType(profileSelector.currentPasswordField, user.password);
cy.get(profileSelector.currentPasswordField).should("have.value", user.password)
cy.clearAndType(profileSelector.newPasswordField,profileText.newPassword);
cy.get(profileSelector.newPasswordField).should("have.value", profileText.newPassword )
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordSuccessToast);
cy.clearAndType(profileSelector.currentPasswordField, user.password);
cy.get(profileSelector.currentPasswordField).should("have.value", user.password)
cy.clearAndType(profileSelector.newPasswordField,profileText.newPassword);
cy.get(profileSelector.newPasswordField).should("have.value", profileText.newPassword )
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordSuccessToast);
common.logout();
cy.wait(1000);
cy.clearAndType(commonSelectors.emailField, commonText.email);
cy.clearAndType(commonSelectors.passwordField, commonText.password);
cy.get(commonSelectors.signInButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.loginErrorToast);
cy.clearAndType(commonSelectors.passwordField, profileText.newPassword);
cy.get(commonSelectors.signInButton).click();
common.navigateToProfile();
cy.clearAndType(profileSelector.currentPasswordField,profileText.newPassword);
cy.clearAndType(profileSelector.newPasswordField, user.password);
cy.get(profileSelector.changePasswordButton).click();
cy.verifyToastMessage(commonSelectors.toastMessage,profileText.passwordSuccessToast);
common.logout();
cy.login(user.email,user.password);
common.logout();
})
});

View file

@ -0,0 +1,14 @@
import { path } from "Texts/common";
import { profileSelector } from "Selectors/profile";
export const navigateToProfile=()=>{
cy.get(profileSelector.profileDropdown).invoke("show");
cy.contains("Profile").click();
cy.url().should("include", path.profilePath);
};
export const logout=()=>{
cy.get(profileSelector.profileDropdown).invoke("show");
cy.contains("Logout").click();
cy.url().should("include",path.loginPath);
};

View file

@ -0,0 +1,16 @@
import { profileSelector } from "Selectors/profile";
import { profileText } from "Texts/profile";
export const profilePageElements = () =>{
for(const elements in profileSelector.profileElements ){
cy.get(profileSelector.profileElements[elements]).should("be.visible").and("have.text",profileText.profileElements[elements]);
}
cy.get(profileSelector.updateButton).should("be.visible").and("have.text", profileText.updateButton);
cy.get(profileSelector.changePasswordButton).should("be.visible").and("have.text", profileText.changePasswordButton);
cy.get(profileSelector.firstNameInput).should("be.visible").and("have.value", profileText.firstName);
cy.get(profileSelector.lastNameInput).should("be.visible").and("have.value", profileText.lastName);
cy.get(profileSelector.emailInput).should("be.visible").and("have.value", profileText.email);
cy.get(profileSelector.currentPasswordField).should("be.visible").should("be.visible");
cy.get(profileSelector.newPasswordField).should("be.visible").should("be.visible");
};

View file

@ -61,7 +61,9 @@ function SettingsPage(props) {
<div className="row align-items-center"> <div className="row align-items-center">
<div className="col"> <div className="col">
<div className="page-pretitle"></div> <div className="page-pretitle"></div>
<h2 className="page-title">Profile Settings</h2> <h2 className="page-title" data-cy="page-title">
Profile Settings
</h2>
</div> </div>
</div> </div>
</div> </div>
@ -71,13 +73,17 @@ function SettingsPage(props) {
<div className="container-xl"> <div className="container-xl">
<div className="card"> <div className="card">
<div className="card-header"> <div className="card-header">
<h3 className="card-title">Profile</h3> <h3 className="card-title" data-cy="card-title-profile">
Profile
</h3>
</div> </div>
<div className="card-body"> <div className="card-body">
<div className="row"> <div className="row">
<div className="col"> <div className="col">
<div className="mb-3"> <div className="mb-3">
<label className="form-label">First name </label> <label className="form-label" data-cy="first-name-label">
First name{' '}
</label>
<input <input
type="text" type="text"
className="form-control" className="form-control"
@ -85,12 +91,15 @@ function SettingsPage(props) {
placeholder="Enter first name" placeholder="Enter first name"
value={firstName} value={firstName}
onChange={(event) => setFirstName(event.target.value)} onChange={(event) => setFirstName(event.target.value)}
data-cy="first-name-input"
/> />
</div> </div>
</div> </div>
<div className="col"> <div className="col">
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Last name</label> <label className="form-label" data-cy="last-name-label">
Last name
</label>
<input <input
type="text" type="text"
className="form-control" className="form-control"
@ -98,14 +107,25 @@ function SettingsPage(props) {
placeholder="Enter last name" placeholder="Enter last name"
value={lastName} value={lastName}
onChange={(event) => setLastName(event.target.value)} onChange={(event) => setLastName(event.target.value)}
data-cy="last-name-input"
/> />
</div> </div>
</div> </div>
<div className="row"> <div className="row">
<div className="col-6"> <div className="col-6">
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Email </label> <label className="form-label" data-cy="email-label">
<input type="text" className="form-control" name="email" value={email} readOnly disabled /> Email{' '}
</label>
<input
type="text"
className="form-control"
name="email"
value={email}
readOnly
disabled
data-cy="email-input"
/>
</div> </div>
</div> </div>
</div> </div>
@ -115,6 +135,7 @@ function SettingsPage(props) {
href="#" href="#"
className={'btn btn-primary' + (updateInProgress ? ' btn-loading' : '')} className={'btn btn-primary' + (updateInProgress ? ' btn-loading' : '')}
onClick={updateDetails} onClick={updateDetails}
data-cy="update-button"
> >
Update Update
</a> </a>
@ -126,13 +147,17 @@ function SettingsPage(props) {
<br /> <br />
<div className="card"> <div className="card">
<div className="card-header"> <div className="card-header">
<h3 className="card-title">Change password</h3> <h3 className="card-title" data-cy="card-title-change-password">
Change password
</h3>
</div> </div>
<div className="card-body"> <div className="card-body">
<div className="row"> <div className="row">
<div className="col"> <div className="col">
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Current password</label> <label className="form-label" data-cy="current-password-label">
Current password
</label>
<input <input
type="password" type="password"
className="form-control" className="form-control"
@ -140,12 +165,15 @@ function SettingsPage(props) {
placeholder="Enter current password" placeholder="Enter current password"
value={currentpassword} value={currentpassword}
onChange={(event) => setCurrentPassword(event.target.value)} onChange={(event) => setCurrentPassword(event.target.value)}
data-cy="current-password-input"
/> />
</div> </div>
</div> </div>
<div className="col"> <div className="col">
<div className="mb-3"> <div className="mb-3">
<label className="form-label">New password</label> <label className="form-label" data-cy="new-password-label">
New password
</label>
<input <input
type="password" type="password"
className="form-control" className="form-control"
@ -154,6 +182,7 @@ function SettingsPage(props) {
value={newPassword} value={newPassword}
onChange={(event) => setNewPassword(event.target.value)} onChange={(event) => setNewPassword(event.target.value)}
onKeyPress={newPasswordKeyPressHandler} onKeyPress={newPasswordKeyPressHandler}
data-cy="new-password-input"
/> />
</div> </div>
</div> </div>
@ -162,6 +191,7 @@ function SettingsPage(props) {
href="#" href="#"
className={'btn btn-primary' + (passwordChangeInProgress ? ' btn-loading' : '')} className={'btn btn-primary' + (passwordChangeInProgress ? ' btn-loading' : '')}
onClick={changePassword} onClick={changePassword}
data-cy="change-password-button"
> >
Change password Change password
</a> </a>

View file

@ -61,7 +61,7 @@ export const Header = function Header({ switchDarkMode, darkMode }) {
</span> </span>
</div> </div>
</a> </a>
<div className="dropdown-menu dropdown-menu-end dropdown-menu-arrow end-0"> <div className="dropdown-menu dropdown-menu-end dropdown-menu-arrow end-0" data-cy="dropdown-menu">
<Link <Link
data-testid="settingsBtn" data-testid="settingsBtn"
to="#" to="#"