qe-fe-automation
Version:
FE test automation framework using cypress
231 lines (216 loc) • 8.66 kB
text/typescript
import dayjs from 'dayjs';
import { createGuestDetails } from '@support-user/index';
import { UserModal } from '../lib/user-modal';
import { Timeouts, TripTileType, utilitySelector } from '@utility-lib/index';
const selectors = {
givenNameInput: 'input[formcontrolname="givenName"]',
familyNameInput: 'input[formcontrolname="familyName"]',
genderInput: 'ta-select[formcontrolname="gender"] .ta-select',
birthdayInput: 'input[placeholder="MM/DD/YYYY"]',
birthdayField: 'ta-date-input[formcontrolname="birthdate"] input',
phoneInput: 'ta-phone-input[formcontrolname="mobilePhone"]',
phoneValue: 'input.ta-phone-input__template',
saveFooterButton: '[data-testid="stickyPrimaryButton"]',
passportIssuingInput: 'ta-country-select[formcontrolname="countryOfIssue"]',
passportCitizenshipInput: 'ta-country-select[formcontrolname="countryOfCitizenship"]',
passportDateIssued: 'ta-date-input[formcontrolname="issuedOn"]',
passportDateExpired: 'ta-date-input[formcontrolname="expiresOn"]',
passportNumber: 'input[formcontrolname="number"]'
};
interface Passport {
country: string;
issue: string;
expire: string;
number: string;
}
export class TravelerModal {
static interceptApis(numRetries: number, aliasName: string): void {
if (numRetries === 0) {
throw new Error(`Could not find property '${'givenName'}' after multiple attempts`);
}
cy.intercept('GET', '/api/user/passenger').as(aliasName);
cy.allure().logStep('Visit profile page on traveler tab');
this.visitPage();
cy.wait(`@${aliasName}`).then((interception) => {
const response = interception.response;
if (response && Object.prototype.hasOwnProperty.call(response.body, 'givenName')) {
// Response has the expected property, proceed with the test
cy.wrap(response.body['givenName']).as('givenName');
} else {
// Response is missing the expected property, retry after 1 second with a new intercept
cy.log('Bad API response, retrying...');
cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
TravelerModal.interceptApis(numRetries - 1, aliasName);
}
});
}
static visitPage(): void {
cy.allure().logStep('Visit profile page on traveler tab');
cy.visit('app/user2/profile?tab=traveler');
}
static getTravelerInfo(): void {
cy.wait('@travelerInfo').then((interception) => {
// Gets traveler's current information and saves them as aliases
const response = interception.response;
if (response) {
const properties = ['givenName', 'familyName', 'gender', 'birthdate'];
properties.forEach((property) => {
cy.wrap(response.body)
.should('have.property', property)
.as(`org${property.charAt(0).toUpperCase()}${property.slice(1)}`);
});
cy.wrap(response.body)
.should('have.nested.property', 'contact.phone.number')
.as('orgPhoneNumber');
}
});
}
static compareTravelerInfo(): void {
cy.reload();
const aliasName = 'newTravelerInfo';
TravelerModal.interceptApis(3, aliasName);
cy.wait(`@${aliasName}`).then((interception) => {
// Gets traveler's new information and saves them as new aliases
const response = interception.response;
function setAliasForProperty(propertyName: string) {
cy.wrap(response?.body)
.should('have.property', propertyName)
.as(`new${propertyName.charAt(0).toUpperCase()}${propertyName.slice(1)}`);
}
if (response) {
setAliasForProperty('givenName');
setAliasForProperty('familyName');
setAliasForProperty('gender');
setAliasForProperty('birthdate');
cy.wrap(response.body)
.should('have.nested.property', 'contact.phone.number')
.as('newPhoneNumber');
}
});
// Confirms on the API level that the traveler's info has been updated
const properties = {
orgGivenName: 'newGivenName',
orgFamilyName: 'newFamilyName',
orgGender: 'newGender',
orgBirthdate: 'newBirthdate',
orgPhoneNumber: 'newPhoneNumber'
};
// Confirms that the UI is also displaying the updated traveler's info
this.compareUIProperties(selectors.givenNameInput, properties.orgGivenName);
this.compareUIProperties(selectors.familyNameInput, properties.orgFamilyName);
// Phone, Birthday and Gender require unique comparisons
cy.get(selectors.phoneValue)
.invoke('val')
.then((displayedPhoneNumber) => {
const phoneStr = displayedPhoneNumber?.toString().replace(/[\s⚊]+/g, '');
cy.get('@newPhoneNumber').then((value) => {
expect(phoneStr).to.equal(value);
});
});
cy.get(selectors.birthdayInput)
.invoke('val')
.then((displayedBirthday) => {
const dateStr = displayedBirthday?.toString();
const formattedDate = dayjs(dateStr).format('YYYY-MM-DD');
cy.get('@newBirthdate').then((value) => {
expect(formattedDate).to.equal(value);
});
});
cy.get('@newGender').then((value1) => {
cy.get(selectors.genderInput)
.invoke('attr', 'value')
.then((value2) => {
if (value2) {
const uppercaseValue2 = value2.toUpperCase().trim();
expect(value1).to.equal(uppercaseValue2);
}
});
});
}
static compareAPIProperties(oldAlias: string, newAlias: string) {
cy.get('@' + oldAlias).then((value1) => {
cy.get('@' + newAlias).then((value2) => {
expect(value1).to.not.equal(value2);
});
});
}
static compareUIProperties(selector: string, newAlias: string) {
cy.get(selector)
.invoke('val')
.then((value1) => {
cy.get('@' + newAlias).then((value2) => {
expect(value1).to.equal(value2);
});
});
}
static createNewTravelerInfo(
travelerType: TripTileType,
gender: 'MALE' | 'FEMALE',
age: number
) {
const {
givenName = '',
familyName = '',
phoneNumber = ''
} = createGuestDetails(age, gender, travelerType);
// The /api/user/passenger API only stores the first 11 numbers of a phone number, so we'll trim the phone number here down to 11 characters (with a '+')
const maxLength = 12;
cy.wrap(phoneNumber)
.invoke('substring', 0, maxLength)
.then((number) => {
const trimNumber = number;
// Adds and saves new traveler information
cy.get(selectors.birthdayField).clear();
UserModal.fillTravelerName(givenName, familyName);
UserModal.fillBirthday(age);
UserModal.fillGender(gender);
UserModal.fillPhoneNumber(trimNumber);
cy.get(selectors.saveFooterButton).click();
});
}
static updatePassportInfo(passport: Passport) {
const { country, issue, expire, number } = passport;
// Enters generated passport information into the passport fields
cy.get(selectors.passportIssuingInput).type(
'{selectall}{backspace}' + country + '{enter}'
);
cy.get(selectors.passportCitizenshipInput).type(
'{selectall}{backspace}' + country + '{enter}'
);
cy.get(selectors.passportDateIssued).type('{selectall}{backspace}' + issue);
cy.get(selectors.passportDateExpired).type('{selectall}{backspace}' + expire);
cy.get(selectors.passportNumber).type('{selectall}{backspace}' + number);
cy.get(selectors.saveFooterButton).click();
}
static verifyUpdatedPassportInfo(passport: Passport) {
const { country, issue, expire, number } = passport;
cy.reload();
cy.get(selectors.passportIssuingInput)
.find(utilitySelector.inputSelector)
.should('have.value', country);
cy.get(selectors.passportCitizenshipInput)
.find(utilitySelector.inputSelector)
.should('have.value', country);
cy.get(selectors.passportDateIssued)
.find(utilitySelector.inputSelector)
.invoke('val')
.then((value1) => {
const dateStr = value1?.toString();
const passportFormattedIssueDate = dayjs(dateStr, 'MMM D, YYYY').format(
'MMDDYYYY'
);
expect(passportFormattedIssueDate).to.equal(issue);
});
cy.get(selectors.passportDateExpired)
.find(utilitySelector.inputSelector)
.invoke('val')
.then((value) => {
const dateStr = value?.toString();
const passportFormattedExpiredDate = dayjs(dateStr, 'MMM D, YYYY').format(
'MMDDYYYY'
);
expect(passportFormattedExpiredDate).to.equal(expire);
});
cy.get(selectors.passportNumber).should('have.value', number);
}
}