qe-fe-automation
Version:
FE test automation framework using cypress
646 lines (603 loc) • 21 kB
text/typescript
import { AUTH_TOKEN, loginRequest } from '../commands';
import { stagingUsers } from '@fixtures/staging-users';
import { AccountRegistrationClient, SuperAdminClient } from './lib';
import { Accept, HttpRequest, HttpStatusCodes } from '../base';
import {
CompanyLoginOptions,
CustomField,
CustomFieldsUtility,
CustomFiledOption,
Logs,
Random,
Timeouts
} from '@utility-lib/index';
import { LoyaltyInfo, CreditCard } from '@flight-modal/index';
import { faker } from '@faker-js/faker';
import { SplitUtility } from '@split-lib/index';
import { Provider_Type, User_Type } from '@support-onboard/index';
import { postChargeableEntity } from './../commerce/commerceCommands';
import { AgencyCurrency, AgencyData, CompanyParams, DEFAULT_LOCALE_EN_US } from '@fixtures/onboard';
const { superAdmin } = stagingUsers;
const superAdminCredentials = Cypress.env('superAdmin').SUPER_ADMIN_PASSWORD;
const onBoardUserCredentials = Cypress.env('newUser').NEW_USER_PASSWORD;
Cypress.Commands.add('initiateCompanyCreationFlow', (companyLoginOptions: CompanyLoginOptions) => {
const {
providers,
users,
locale,
creditCardInfo,
loyaltyInfo,
feeModelInfo,
companyCustomFields,
vip,
companySuffix,
phoneNumber
} = companyLoginOptions;
cy.allure().logStep('Initiate company creation flow');
const email = superAdmin.email;
cy.loginWithAuthToken({ email, password: superAdminCredentials, isSA: true })
.then(() => createCompany(loyaltyInfo, companySuffix))
.then((companyResponse) => checkAndCreateFeeModelForCompany(companyResponse, feeModelInfo))
.then((companyResponse) => updateCompanyParams(companyResponse, companyLoginOptions))
.then((companyResponse) => addUserAgency(companyResponse, feeModelInfo, vip))
.then((agencyResponse) => isUserRegistered(agencyResponse, users, providers))
.then((email) => sendPreSignupEmail(email))
.then((email) => getSignUpToken(email))
.then(({ email, body }) => createAccount(email, body, onBoardUserCredentials))
.then((email) => retrieveUserByEmail(email))
.then(({ userResponse }) => setUserAsVIP(userResponse, vip))
.then(({ userResponse }) => setUserByType(userResponse, users))
.then((email) => loginRequest({ email, password: onBoardUserCredentials }))
.then(() => setTravelFrequency())
.then(() => updateUserInfo())
.then(() => updatePassengerInfoDefault(phoneNumber))
.then((companyResponse) => addPersonalPaymentMethod(companyResponse, creditCardInfo))
.then(() => getAndCheckSplitsForProviders(providers))
.then(() => (locale !== DEFAULT_LOCALE_EN_US ? setLocale(locale) : 'Locale is already set to english'))
.then(() => {
companyCustomFields.forEach((values, companyCustomField) => setCompanyCustomField(companyCustomField, values));
});
});
Cypress.Commands.add('addNewTraveler', (companyDomain: string) => {
const email = Random.randomString(5) + '@' + `${companyDomain}`;
cy.loginWithAuthToken({
email: superAdmin.email,
password: superAdminCredentials,
isSA: true
})
.then(() => sendPreSignupEmail(email))
.then((email) => getSignUpToken(email))
.then(({ email, body }) => createAccount(email, body, onBoardUserCredentials))
.then((email) => loginRequest({ email, password: onBoardUserCredentials }))
.then(() => setTravelFrequency())
.then(() => updateUserInfo())
.then(() => updatePassengerInfoDefault())
.then(() => addPersonalPaymentMethod())
.then(() => cy.task('putDataInCache', { key: 'travelerEmail', data: email }));
});
Cypress.Commands.add('retrieveSignUpToken', (email: string) => {
cy.loginWithAuthToken({
email: superAdmin.email,
password: superAdminCredentials,
isSA: true,
localStorage: false
}).then(() => getSignUpToken(email));
});
Cypress.Commands.add('retrieveUserByEmail', (email: string) => {
cy.loginWithAuthToken({
email: superAdmin.email,
password: superAdminCredentials,
isSA: true,
localStorage: false
}).then(() => retrieveUserByEmail(email));
});
function createCompany(loyaltyInfo?: LoyaltyInfo, companySuffix?: string): Cypress.Chainable<any> {
cy.allure().logStep('Start creating brand new company');
const randomId = Random.randomString(12);
const companyDomain = randomId + '-navan' + companySuffix + '.staging.tripactions.xyz';
const companyName = 'TA_CYPRESS_' + randomId;
const options = {
method: HttpRequest.Post,
url: SuperAdminClient.companiesUrl,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: {
name: companyName,
domain: companyDomain,
loyaltyInfo,
status: 'ACTIVE'
},
retryOnStatusCodeFailure: true
};
return cy
.request(options)
.then((xhr) => Logs.logResponseStatusAndBody(xhr))
.then(({ body, status }) => {
expect(status, 'Successfully created company').to.equal(HttpStatusCodes.Created);
return body;
});
}
function updateCompanyParams(companyResponse: any, companyLoginOptions: CompanyLoginOptions) {
const newCompanyParams: CompanyParams = {
tripProposalEnabled: companyLoginOptions.tripProposal,
chargeBookingFee: true,
chargeTripFee: true
};
const requestBody = {
...companyResponse,
...newCompanyParams
};
cy.log('Update the company with the following parameters: ' + JSON.stringify(newCompanyParams));
return cy
.request({
method: 'PUT',
url: SuperAdminClient.companiesUrl + `/${companyResponse.uuid}`,
headers: {
Authorization: AUTH_TOKEN
},
body: requestBody,
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Company params updated').to.equal(HttpStatusCodes.Ok);
return body;
});
}
function updateUserInfo() {
const userInfo = {
phone_number: '+14157483333',
onboardingCompleted: true
};
cy.log('Update user info with the following parameters: ' + JSON.stringify(userInfo));
return cy
.request({
method: HttpRequest.Patch,
url: AccountRegistrationClient.userInfo,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: userInfo,
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'Updated user info').to.equal(HttpStatusCodes.Ok);
});
}
function checkAndCreateFeeModelForCompany(companyResponse: any, feeModelName: string): Cypress.Chainable<any> {
if (feeModelName?.includes('Fee')) {
cy.log(companyResponse.uuid);
cy.log(feeModelName);
postChargeableEntity(companyResponse.uuid, feeModelName);
}
return cy.wrap(companyResponse);
}
function addUserAgency(companyResponse: any, feeModelInfo: string, vip: boolean): Cypress.Chainable<any> {
const companyUuid = companyResponse.uuid;
const agencyData = getAgencyData(companyResponse, feeModelInfo, vip);
cy.log(feeModelInfo);
cy.task('putDataInCache', { key: 'agencyUuid', data: agencyData.agency.uuid });
if (!feeModelInfo.includes('Fee')) {
cy.log('feeModelInfo does not include FEE');
cy.task('putDataInCache', { key: 'tripFee', data: '5.00' });
}
cy.allure().logStep(`Add user agency for ${companyUuid} company`);
return cy
.request({
method: HttpRequest.Put,
url: SuperAdminClient.travelOpsCompaniesAgencyUrl
.replace('{companyUuid}', companyUuid)
.replace('{agencyUuid}', agencyData.agency.uuid),
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: agencyData,
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Successfully updated company with agency ').to.equal(HttpStatusCodes.Ok);
return body;
});
}
function getAgencyData(companyResponse: any, feeModelInfo: string, vip: boolean) {
const companyUuid = companyResponse?.uuid;
const companyId = companyResponse?.domain?.split('.')[0];
if (vip) {
return AgencyData.generateUSDAgencyVIPData(companyUuid, companyId);
}
if (feeModelInfo.includes(AgencyCurrency.Euro)) {
return AgencyData.generateEURAgencyData(companyUuid, companyId);
}
return AgencyData.generateUSDAgencyData(companyUuid, companyId);
}
function isUserRegistered(
userAgencyResponse: any,
users: User_Type[],
providers: Provider_Type[]
): Cypress.Chainable<any> {
const domain = userAgencyResponse.companyId;
const usersString = getEnumsAsString(users);
const providersString = getEnumsAsString(providers);
const email =
providersString + '_' + usersString + '_' + Random.randomString(3) + '@' + `${domain}` + `.staging.tripactions.xyz`;
cy.task('putDataInCache', { key: 'companyCreationEmail', data: email });
cy.allure().logStep(`Is user is already registered : ${email}`);
return cy
.request({
method: HttpRequest.Get,
url: AccountRegistrationClient.emailInfo,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
qs: { email },
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'User is not registered').to.equal(HttpStatusCodes.Ok);
return email;
});
}
function getEnumsAsString<T extends string | number>(enumArray: T[]) {
let enumsString = '';
enumArray.forEach((enumItem: T) => {
if (enumsString) {
enumsString += '_';
}
enumsString += enumItem.toString();
});
return enumsString;
}
function sendPreSignupEmail(email: string): Cypress.Chainable<any> {
cy.allure().logStep(`Send pre sign up email for ${email}`);
return cy
.request({
method: HttpRequest.Post,
url: AccountRegistrationClient.preSignUpEmail,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
qs: { email },
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'Sign up email triggered').to.equal(HttpStatusCodes.Accepted);
return email;
});
}
function getSignUpToken(email: string): Cypress.Chainable<any> {
cy.allure().logStep(`Retrieve sign up token for ${email}`);
return cy
.request({
method: HttpRequest.Get,
url: SuperAdminClient.retrieveSignupToken,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
qs: { email },
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Signup token retrieved').to.equal(HttpStatusCodes.Ok);
return { email, body };
});
}
function createAccount(email: string, token: string, password: string): Cypress.Chainable<any> {
cy.allure().logStep(`Creating account for ${email}`);
cy.task('putDataInCache', { key: 'userEmail', data: email });
return cy.task('getDataFromCache', 'agencyUuid').then((agencyData) => {
return cy
.request({
method: HttpRequest.Post,
url: AccountRegistrationClient.signUp,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: {
emailVerificationToken: token,
email: email,
familyName: faker.name.lastName().replace(/'/g, ''),
givenName: faker.name.firstName(),
password: password,
agencyCompanyAssociationUuid: agencyData
},
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'Account created').to.equal(HttpStatusCodes.Created);
return email;
});
});
}
function setTravelFrequency(travelFrequency = '1-2 times a month'): Cypress.Chainable<any> {
cy.allure().logStep('Setting travel frequency');
return cy
.request({
method: HttpRequest.Patch,
url: AccountRegistrationClient.userProfile,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: {
travelFrequency: travelFrequency
},
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'Updated travel frequency').to.equal(HttpStatusCodes.Ok);
});
}
function getAndCheckSplitsForProviders(providers: Provider_Type[]): Cypress.Chainable<any> {
cy.allure().logStep('Update splits');
if (AUTH_TOKEN) {
return cy
.request({
method: HttpRequest.Get,
url: AccountRegistrationClient.getSplits,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Updated splits').to.equal(HttpStatusCodes.Ok);
cy.task('putDataInCache', {
key: 'splitList',
data: body
});
SplitUtility.checkOnlyRelevantSplitIsOn(providers);
});
} else {
throw new Error('Please login before calling api endpoints');
}
}
function updatePassengerInfoDefault(phoneNumber = '+12029064406'): Cypress.Chainable<any> {
cy.allure().logStep('Update passenger information');
const firstName = faker.name.firstName();
const lastName = faker.name.lastName().replace(/'/g, '');
const travelerName = firstName + ' ' + lastName;
cy.task('putDataInCache', {
key: 'travelerName',
data: travelerName
});
return cy
.request({
method: HttpRequest.Put,
url: AccountRegistrationClient.passengerInfo,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: {
givenName: firstName,
familyName: lastName,
passport: {
countryOfCitizenship: 'US',
number: '31195855',
countryOfIssue: 'US',
issuedOn: '2020-12-12',
expiresOn: '2030-12-12'
},
birthdate: '1990-07-17',
gender: 'X',
secondaryGender: 'MALE',
contact: {
phone: {
number: phoneNumber
}
}
},
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'Update passenger default information').to.equal(HttpStatusCodes.Ok);
});
}
function addPersonalPaymentMethod(
companyResponse?: any,
creditCardInfo?: CreditCard,
current_attempt = 1
): Cypress.Chainable<any> {
cy.allure().logStep('Add personal payment method');
const creditCard = creditCardInfo
? creditCardInfo
: {
fullName: 'JMeter',
givenName: faker.name.firstName(),
familyName: faker.name.lastName().replace(/'/g, ''),
number: '4242424242424242',
expirationMonth: '1',
expirationYear: '2026',
cvc: '123'
};
return cy
.request({
method: HttpRequest.Post,
url: AccountRegistrationClient.paymentMethod,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: {
billingAddress: {
addressLine1: 'Strawinskylaan',
addressLine2: '1337',
state: 'AL',
city: 'Amsterdam',
country: 'NL',
postalCode: '1337AM'
},
creditCard,
nickname: 'Corporate Visa Card'
},
failOnStatusCode: false
})
.then(({ status, body }) => {
if ((status === 500 || status === 504) && current_attempt < 5) {
cy.allure().logStep('Retrying adding personal payment method, attempt: ' + current_attempt);
cy.wait(Timeouts.MEDIUM_TIMEOUT_20_SEC.timeout);
cy.allure().logStep('Applied wait time: ' + Timeouts.MEDIUM_TIMEOUT_20_SEC.timeout);
addPersonalPaymentMethod(companyResponse, creditCardInfo, ++current_attempt);
}
expect(status, 'Payment method updated').to.equal(HttpStatusCodes.Created);
cy.task('putDataInCache', { key: 'paymentMethod', data: body });
const paymentMethodUuId = body.uuid;
cy.task('putDataInCache', { key: 'paymentMethodUuId', data: paymentMethodUuId });
});
}
function setUserByType(userResponse: any, users: User_Type[]): Cypress.Chainable<any> | PromiseLike<string> {
users.forEach((user) => {
if (user === 'admin' || user === 'programManager') {
cy.allure().logStep('Set user as ' + users.toString());
return cy
.request({
method: HttpRequest.Patch,
url: SuperAdminClient.adminUsers + `/${userResponse.uuid}`,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: getUserAvailableObject(users),
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Set user as ' + users.toString()).to.equal(HttpStatusCodes.Ok);
return body.email;
});
}
});
return new Cypress.Promise((resolve) => {
resolve(userResponse.email);
});
}
function setUserAsVIP(userResponse: any, vip: boolean): Cypress.Chainable<any> | PromiseLike<any> {
if (vip) {
cy.allure().logStep(`Set user as VIP = ${vip}`);
return cy
.request({
method: HttpRequest.Patch,
url: SuperAdminClient.adminUsers + `/${userResponse.uuid}`,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: { vip: true },
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Set user as VIP').to.equal(HttpStatusCodes.Ok);
cy.log('Returned response email : ' + body.email);
cy.task('putDataInCache', {
key: 'userResponse',
data: userResponse
}).then(() => {
return { userResponse };
});
});
}
return new Cypress.Promise((resolve) => {
resolve({ userResponse });
});
}
function getUserAvailableObject(users: User_Type[]): any {
const userParameters: { [key in User_Type]?: boolean } = {};
users.forEach((user) => {
userParameters[user] = true;
});
return userParameters;
}
function retrieveUserByEmail(email: string, current_attempt = 1): Cypress.Chainable<any> {
cy.allure().logStep('Retrieve user by email');
cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout); // Wait newly created user to sync
return cy
.request({
method: HttpRequest.Get,
url: SuperAdminClient.adminUsers,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
qs: {
q: email,
size: 12
},
retryOnStatusCodeFailure: true
})
.then(({ body, status }) => {
expect(status, 'Retrieve user by email').to.equal(HttpStatusCodes.Ok);
const response = body?._embedded?.users;
if (!response) {
// Temporary logging to track the response body without an array of users. To be deleted later
Logs.logToCypressAndAllure(
`Request: ${HttpRequest.Get} ${SuperAdminClient.adminUsers}\n Response body: ${JSON.stringify(body)}`
);
}
const userResponse = response?.find(function (user: any) {
cy.log('Returned response email : ' + user.email);
return user.email === email.toLowerCase();
});
if (!userResponse) {
if (current_attempt > 3) {
cy.log(`User response return empty after ${current_attempt} attempts`);
throw new Error(`User response return empty after ${current_attempt} attempts`);
} else {
++current_attempt;
cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
cy.log('Retrying since user response return empty. Attempt: ' + current_attempt);
return retrieveUserByEmail(email, current_attempt);
}
}
cy.task('putDataInCache', {
key: 'userResponse',
data: userResponse
}).then(() => {
return { userResponse };
});
});
}
function setLocale(locale: string): Cypress.Chainable<any> {
cy.allure().logStep('Setting locale for user');
return cy
.request({
method: HttpRequest.Patch,
url: AccountRegistrationClient.userInfo,
headers: {
Authorization: AUTH_TOKEN,
contentType: Accept.ApplicationJson
},
body: {
locale: locale
},
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(status, 'Updated locale').to.equal(HttpStatusCodes.Ok);
});
}
function setCompanyCustomField(companyCustomField: CustomField, options: CustomFiledOption[]) {
return cy
.request({
method: HttpRequest.Post,
url: AccountRegistrationClient.customFields,
headers: {
Authorization: AUTH_TOKEN,
Accept: Accept.ApplicationJson
},
body: CustomFieldsUtility.generateCompanyTripPurposeData(companyCustomField, options),
retryOnStatusCodeFailure: true
})
.then(({ status }) => {
expect(
status,
`Custom field ${companyCustomField} updated with values: ${options.map((option) => option.value)}`
).to.equal(HttpStatusCodes.Ok);
});
}