UNPKG

qe-fe-automation

Version:
392 lines (378 loc) 16.8 kB
import { createGuestDetails } from '@support-user/index'; import { UserModal, ProfileInterceptApis, TravelerModal } from '@profile-lib/index'; import { TripTileType, Timeouts, Random } from '@utility-lib/index'; import { SharedIntercepts } from '@intercepts-lib/shared_intercepts'; const selectors = { // Selectors for contact info section givenNameInput: 'input[formcontrolname="givenName"]', familyNameInput: 'input[formcontrolname="familyName"]', phoneInput: 'ta-phone-input[formcontrolname="mobilePhone"]', workPhoneInput: 'ta-phone-input[formcontrolname="workPhoneNumber"]', phoneValue: 'input.ta-phone-input__template', personalEmailValue: 'input[formcontrolname="alternateEmail"]', workEmailValue: 'input[formcontrolname="email"]', loyaltyButton: '#mat-checkbox-1 > .mat-checkbox-layout > .mat-checkbox-inner-container', loyaltyButtonStatus: 'ta-checkbox[formcontrolname="marketingCommEmailOptIn"] input', saveFooterButton: '[data-testid="stickyPrimaryButton"]', // Selectors for Delegate info section asDelegateCheckbox: 'ta-checkbox[formcontrolname="iAmDelegateForCheckbox"]', asDelegateInput: 'ta-user-group-simple[formcontrolname="iAmDelegateForUsers"] input', asDelegateEntry: 'ta-user-group-simple[formcontrolname="iAmDelegateForUsers"] span.ta-user-tag-simple__name', asDelegateRemove: 'ta-user-group-simple[formcontrolname="iAmDelegateForUsers"] .ta-user-tag-simple__remove', setDelegateCheckbox: 'ta-checkbox[formcontrolname="myDelegatesCheckbox"]', setDelegateInput: 'ta-user-group-simple[formcontrolname="myDelegatesUsers"] input', setDelegateEntry: 'ta-user-group-simple[formcontrolname="myDelegatesUsers"] span.ta-user-tag-simple__name', setDelegateRemove: 'ta-user-group-simple[formcontrolname="myDelegatesUsers"] .ta-user-tag-simple__remove', searchDelgateResult: '.ta-user-search-simple-popover__item', // Selectors for Assistant info section searchAssistantInput: '.ta-profile-assistant-info__search-wrapper > ta-user-search > .ta-user-search', searchAssistantResult: '.ta-user-search-popover__item', removeAssistant: '.ta-profile-assistant-info__cancel', existingAssistantButtonNo: 'input[value="no"]', existingAssistantButtonYes: 'input[value="yes"]', newAssistantNameInput: '.ta-profile-assistant-info__form input[formcontrolname="name"]', newAssistantEmailInput: '.ta-profile-assistant-info__form input[formcontrolname="email"]', newAssistantPhoneInput: '.ta-profile-assistant-info__form ta-form-wrap [type="tel"]', addSecondAssistantButton: '.ta-profile-contact-info__second-info > .ta-button > .ta-button__content', // Selectors for Emergency Contact info section emergencyNameInput: 'div[formgroupname="emergencyContact"] input[formcontrolname="name"]', emergencyRelationshipDropdown: 'div[formgroupname="emergencyContact"] .ta-select', emergencyRelationshipFriend: 'div[aria-label="Friend"]', emergencyRelationshipValue: 'ta-select[formcontrolname="relation"] button', emergencyEmailInput: 'div[formgroupname="emergencyContact"] input[formcontrolname="email"]', emergencyPhoneInput: 'div[formgroupname="emergencyContact"] .ta-phone-input [type="tel"]' }; type gender = 'MALE' | 'FEMALE'; type age = number; export class ContactModal { static visitPage(): void { cy.allure().logStep('Visit profile page on contact info tab'); cy.visit('app/user2/profile?tab=contact'); } static interceptApis(numRetries: number): void { if (numRetries === 0) { throw new Error( `Could not find property '${'given_name'}' after multiple attempts` ); } SharedIntercepts.intercepts(); cy.allure().logStep('Visit profile page on contact info tab'); ContactModal.visitPage(); cy.wait('@waitForUserInfo').then((interception) => { const response = interception.response; if (response && Object.prototype.hasOwnProperty.call(response.body, 'given_name')) { // Response has the expected property, proceed with the test cy.wrap(response.body['given_name']).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); this.interceptApis(numRetries - 1); } }); } static getContactInfo(): void { cy.wait('@waitForUserInfo').then((interception) => { // Gets current contact information and saves them as aliases const response = interception.response; if (response) { const properties = ['given_name', 'family_name', 'phone_number', 'email']; properties.forEach((property) => { cy.wrap(response.body) .should('have.property', property) .as(`org${property.charAt(0).toUpperCase()}${property.slice(1)}`); }); } }); } static compareContactInfo(): void { // Proper handling of the latest request needs unique alias each time const userInfoInterceptAlias = 'waitForUserInfo_' + Random.randomString(); cy.intercept('GET', '/api/uaa/userinfo').as(userInfoInterceptAlias); cy.reload(); cy.wait(`@${userInfoInterceptAlias}`).then((interception) => { // Gets new contact 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('given_name'); setAliasForProperty('family_name'); setAliasForProperty('phone_number'); setAliasForProperty('email'); } }); // Confirms on the API level that the contact info has been updated const properties = { orgGiven_name: 'newGiven_name', orgFamily_name: 'newFamily_name', orgPhone_number: 'newPhone_number' }; for (const [orgProp, newProp] of Object.entries(properties)) { TravelerModal.compareAPIProperties(orgProp, newProp); } // Confirms that the UI is also displaying the updated contact info TravelerModal.compareUIProperties(selectors.givenNameInput, properties.orgGiven_name); TravelerModal.compareUIProperties( selectors.familyNameInput, properties.orgFamily_name ); // Phone numbers requires unique comparisons cy.get(selectors.phoneValue) .first() // Checks mobile number field .invoke('val') .then((displayedPhoneNumber) => { const phoneStr = displayedPhoneNumber?.toString().replace(/\s/g, ''); cy.get('@newPhone_number').then((value) => { expect(phoneStr).to.equal(value); }); }); cy.get(selectors.phoneValue) .eq(1) // Checks work phone field .invoke('val') .then((displayedWorkNumber) => { const phoneStr = displayedWorkNumber?.toString().replace(/\s/g, ''); cy.get('@newPhone_number').then((value) => { expect(phoneStr).to.equal(value); }); }); // Confirm personal email field is not blank (since there was none added before) cy.get(selectors.personalEmailValue).invoke('val').should('not.be.empty'); // Confirms the work email address field is displaying (field cannot be edited; checks existing email is displaying) cy.get(selectors.workEmailValue) .invoke('val') .then((displayedEmail) => { cy.get('@newEmail').then((value) => { expect(displayedEmail).to.equal(value); }); }); // Confirms marketing email checkbox is now enabled (previously unchecked) cy.get(selectors.loyaltyButtonStatus).should('have.attr', 'aria-checked', 'true'); } static createNewContactInfo = ( age: age, gender: gender, travelerType: TripTileType ) => { const { givenName = '', familyName = '', phoneNumber = '', email = '' } = createGuestDetails(age, gender, travelerType); // Trim the generated phone number 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 contact information UserModal.fillTravelerName(givenName, familyName); UserModal.fillMobilePhoneNumber(trimNumber); UserModal.fillWorkPhoneNumber(trimNumber); UserModal.fillAltEmail(email); cy.get(selectors.loyaltyButton).click(); // Checks marketing email box, which was previously not checked cy.get(selectors.saveFooterButton).click(); cy.wait('@userInfoSave'); }); }; } export class DelegateModal { static interceptApis(numRetries: number): void { if (numRetries === 0) { throw new Error( `Could not find property '${'delegatedUsers'}' after multiple attempts` ); } ProfileInterceptApis.interceptProfileApis(); cy.allure().logStep('Visit profile page on contact info tab'); ContactModal.visitPage(); cy.wait('@waitForDelegatesInfo').then((interception) => { const response = interception.response; if ( response && Object.prototype.hasOwnProperty.call(response.body, 'delegatedUsers') ) { // Response has the expected property, proceed with the test cy.wrap(response.body['delegatedUsers']).as('delegates'); } 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); this.interceptApis(numRetries - 1); } }); } static addAsDelegate(delegate: string): void { // Proper handling of the latest request needs unique alias each time const delegatesInterceptAlias = 'waitForDelegatesInfoSave_' + Random.randomString(); cy.intercept('PUT', 'api/user/profile/delegates').as(delegatesInterceptAlias); cy.get(selectors.asDelegateCheckbox).click(); cy.get(selectors.asDelegateInput).type(delegate); cy.get(selectors.searchDelgateResult).click(); cy.get(selectors.saveFooterButton).click(); cy.wait(`@${delegatesInterceptAlias}`).then((interception) => { // Confirms user has a saved delegate const response = interception.response; if (response) { const properties = ['givenName', 'familyName']; properties.forEach((property) => { cy.wrap(response.body.delegatedUsers[0].user).should('have.property', property); }); } }); } static verifyAsDelegate(delegate: string) { cy.get(selectors.asDelegateEntry).should('contain.text', delegate); } static deleteAsDelegate() { // Proper handling of the latest request needs unique alias each time const delegatesInterceptAlias = 'waitForDelegatesInfoSave_' + Random.randomString(); cy.intercept('PUT', 'api/user/profile/delegates').as(delegatesInterceptAlias); cy.get(selectors.asDelegateRemove).click(); cy.get(selectors.saveFooterButton).click(); cy.wait(`@${delegatesInterceptAlias}`).then((interception) => { // Confirms user has no saved delegates const response = interception.response; if (response) { const properties = ['user']; properties.forEach((property) => { cy.wrap(response.body.delegatedUsers).should('not.have.property', property); }); } }); cy.get(selectors.asDelegateEntry).should('not.exist'); } static addSetDelegate(delegate: string) { // Proper handling of the latest request needs unique alias each time const delegatesInterceptAlias = 'waitForDelegatesInfoSave_' + Random.randomString(); cy.intercept('PUT', 'api/user/profile/delegates').as(delegatesInterceptAlias); cy.get(selectors.setDelegateCheckbox).click(); cy.get(selectors.setDelegateInput).type(delegate); cy.get(selectors.searchDelgateResult).click(); cy.get(selectors.saveFooterButton).click(); cy.wait(`@${delegatesInterceptAlias}`).then((interception) => { // Confirms user has a set delegate const response = interception.response; console.log(response); if (response) { const properties = ['givenName']; properties.forEach((property) => { cy.wrap(response.body.delegates[0].user).should('have.property', property); }); } }); } static verifySetDelegate(delegate: string): void { cy.get(selectors.setDelegateEntry).should('contain.text', delegate); } } export class AssistantModal { static addExistingAssistant(assistant: string): void { cy.allure().logStep('Adding existing assistant on contact info tab'); cy.get(selectors.searchAssistantInput).as('assistantInput'); cy.get('@assistantInput').scrollIntoView(); cy.get('@assistantInput').should('be.visible').click(); cy.get('@assistantInput').should('be.visible').type(assistant); cy.get(selectors.searchAssistantResult).should('be.visible').click(); cy.get(selectors.saveFooterButton).click(); } static removeAssistant(): void { cy.allure().logStep('Removing assistant on contact info tab'); cy.get(selectors.removeAssistant).click(); cy.get(selectors.saveFooterButton).click(); } static validateAssistant( assistantName: string, assistantEmail: string, assistantPhone: string ): void { cy.allure().logStep('Validating assistant on contact info tab'); cy.get(selectors.newAssistantNameInput).should('have.value', assistantName); cy.get(selectors.newAssistantEmailInput).should('have.value', assistantEmail); cy.get(selectors.newAssistantPhoneInput) .invoke('val') .then((phoneNumber) => { const actualPhoneNumber = Cypress._.trim( phoneNumber?.toString().replace(/\D/g, '').substring(1) ); // removes all non-numeric characters expect(actualPhoneNumber).to.eq(assistantPhone); }); } static addNewAssistant( assistantName: string, assistantEmail: string, assistantPhone: string ): void { cy.allure().logStep('Adding new assistant on contact info tab'); cy.get(selectors.existingAssistantButtonNo).click(); cy.get(selectors.newAssistantNameInput).type(assistantName); cy.get(selectors.newAssistantEmailInput).type(assistantEmail); cy.get(selectors.newAssistantPhoneInput).type(assistantPhone); cy.get(selectors.saveFooterButton).click(); } static addSecondAssistant(assistant: string): void { cy.allure().logStep('Adding second assistant on contact info tab'); cy.get(selectors.addSecondAssistantButton).click(); cy.get(selectors.searchAssistantInput).type(assistant); cy.get(selectors.searchAssistantResult).click(); cy.get(selectors.saveFooterButton).click(); } } export class EmergencyContactModal { static addEmergencyContact( emergencyName: string, emergencyEmail: string, emergencyNumber: string ): void { cy.allure().logStep('Adding emergency contact info on contact info tab'); cy.get(selectors.emergencyNameInput).type(emergencyName); cy.get(selectors.emergencyRelationshipDropdown).click(); // Defaults to relationship type "Friend" cy.get(selectors.emergencyRelationshipFriend).click(); cy.get(selectors.emergencyEmailInput).type(emergencyEmail); cy.get(selectors.emergencyPhoneInput).type(emergencyNumber); cy.get(selectors.saveFooterButton).click(); } static verifyEmergencyContact( emergencyName: string, emergencyEmail: string, emergencyNumber: string ) { cy.allure().logStep('Verifying emergency contact info on contact info tab'); cy.get(selectors.emergencyNameInput).should('have.value', emergencyName); cy.get(selectors.emergencyEmailInput).should('have.value', emergencyEmail); cy.get(selectors.emergencyPhoneInput) .invoke('val') .then((displayedPhoneNumber) => { const phoneStr = displayedPhoneNumber ?.toString() .replace(/\s/g, '') .replace(/^\+1/, ''); expect(phoneStr).to.equal(emergencyNumber); }); // Verifies the default relationship type, friend cy.get(selectors.emergencyRelationshipValue).should('have.value', 'FRIEND'); } static clearEmergencyContact(): void { cy.allure().logStep('Removing emergency contact info on contact info tab'); cy.get(selectors.emergencyNameInput).clear(); // Relationship dropdown cannot be cleared cy.get(selectors.emergencyEmailInput).clear(); cy.get(selectors.emergencyPhoneInput).clear(); cy.get(selectors.saveFooterButton).click(); } }