diff --git a/src/test/ui/config/axe-exclusions.config.ts b/src/test/ui/config/axe-exclusions.config.ts index f253c8bff..6b595fe63 100644 --- a/src/test/ui/config/axe-exclusions.config.ts +++ b/src/test/ui/config/axe-exclusions.config.ts @@ -4,6 +4,7 @@ export const axe_exclusions = [ '#contactByTelephone', //page: contactByTelephone, element: 'Yes', element_type: radioOption, reason_for_exclusion: 'aria-expanded' attribute is expected for this radio button '#nameConfirmation-2', //page: DefendantNameConfirmation, element: 'No', element_type: radioOption, reason_for_exclusion: 'aria-expanded' attribute is expected for this radio button '#confirmTenancyDate-2', //page: tenancyStartDateKnown, element: 'No', element_type: radioOption, reason_for_exclusion: 'aria-expanded' attribute is expected for this radio button + '#disputeOtherParts', //page: nonRentArrearsDispute, element: 'Yes', element_type: radioOption, reason_for_exclusion: 'aria-expanded' attribute is expected for this radio button '#tenancyTypeConfirm-2', //page: tenancyOccupationContractLicenseAgreement, element: 'No', element_type: radioOption, reason_for_exclusion: 'aria-expanded' attribute is expected for this radio button '#contactByEmailOrPost', //page: contactPreferenceEmailOrPost, element: 'Yes', element_type: radioOption, reason_for_exclusion: 'aria-expanded' attribute is expected for this radio button ]; diff --git a/src/test/ui/data/page-data/nonRentArrearsDispute.page.data.ts b/src/test/ui/data/page-data/nonRentArrearsDispute.page.data.ts index 6866f1ab4..2595a5a84 100644 --- a/src/test/ui/data/page-data/nonRentArrearsDispute.page.data.ts +++ b/src/test/ui/data/page-data/nonRentArrearsDispute.page.data.ts @@ -1,4 +1,27 @@ +import { generateRandomString } from '../../utils/common/string.utils'; + export const nonRentArrearsDispute = { - mainHeader: `Non-Rent Arrears Dispute(Placeholder)`, - continueButton: `Continue`, + mainHeader: `Disputing other parts of the claim`, + partOfClaimParagraph: `You should`, + toSeeIfParagraph: `to see if there’s any other parts of the claim that are incorrect or you disagree with.`, + viewTheClaimLink: `view the claim (opens in new tab)`, + mainHeaderGovServiceHiddenNewTab: `Welcome to GOV.UK`, + thisIncludesParagraph: `This includes:`, + groundsForPossessionList: `${process.env.CLAIMANT_NAME}’s grounds for possession (their reasons for making the claim)`, + anyDocumentsList: `any documents they’ve uploaded to support their claim`, + anyOtherList: `any other information they’ve given as part of their claim`, + doYouWantToDisputeQuestion: `Do you want to dispute any other parts of the claim?`, + explainPartOfClaimHiddenTextLabel: `Explain which parts of the claim you do not agree with`, + explainClaimTextInput: `Example - Do not agree with claim 1,2 and 3`, + yesRadioOption: `Yes`, + noRadioOption: `No`, + saveForLaterButton: `Save for later`, + saveAndContinueButton: `Save and continue`, + backLink: `Back`, + detailsCharLimitInputText: generateRandomString(6501), + tooManyCharacterHiddenHintText: `You have 1 character too many`, + youHave6500CharactersHiddenHintText: `You have 6,500 characters remaining`, + thereIsAProblemErrorMessageHeader: `There is a problem`, + selectIfYouWantToDisputeErrorMessage: `Select if you want to dispute any other parts of the claim`, + partsOfClaimDoNotAgreeErrorMessage: `Enter the parts of the claim you do not agree with`, }; diff --git a/src/test/ui/data/page-data/rentArrearsDispute.page.data.ts b/src/test/ui/data/page-data/rentArrearsDispute.page.data.ts index 1ce132dcf..e65f79010 100644 --- a/src/test/ui/data/page-data/rentArrearsDispute.page.data.ts +++ b/src/test/ui/data/page-data/rentArrearsDispute.page.data.ts @@ -1,4 +1,4 @@ export const rentArrearsDispute = { - mainHeader: `Rent Arrears Dispute(Placeholder)`, + mainHeader: `Rent arrears`, continueButton: `Continue`, }; diff --git a/src/test/ui/e2eTest/respondToAClaim.spec.ts b/src/test/ui/e2eTest/respondToAClaim.spec.ts index f3a5adfe9..491aa6e5d 100644 --- a/src/test/ui/e2eTest/respondToAClaim.spec.ts +++ b/src/test/ui/e2eTest/respondToAClaim.spec.ts @@ -34,6 +34,13 @@ test.beforeEach(async ({ page }, testInfo) => { process.env.NOTICE_SERVED = 'YES'; } + // Notice date provided + if (testInfo.title.includes('NoticeDateProvided - No')) { + process.env.NOTICE_DATE_PROVIDED = 'NO'; + } else if (testInfo.title.includes('NoticeDateProvided - Yes')) { + process.env.NOTICE_DATE_PROVIDED = 'YES'; + } + const tenancyKey = ['Introductory', 'Demoted', 'Assured', 'Secure', 'Flexible'].find(type => testInfo.title.includes(type) ); @@ -62,10 +69,23 @@ test.beforeEach(async ({ page }, testInfo) => { break; } + //Check if No or Im not sure is selected on NoticeDetails page - for back link navigation + if (testInfo.title.includes('NoticeDetails - No') || testInfo.title.includes('NoticeDetails - Im not sure')) { + process.env.NOTICE_DETAILS_NO_NOTSURE = 'YES'; + } + + // Tenancy start date logic for noDefendantTest and rentNonRent test + if (testInfo.title.includes('NoticeServed - No') && !testInfo.title.includes('@rentNonRent')) { + process.env.TENANCY_START_DATE_KNOWN = testInfo.title.includes('noDefendants') ? 'NO' : 'YES'; + process.env.RENT_NON_RENT = 'NO'; + } else { + process.env.RENT_NON_RENT = 'YES'; + } + if (testInfo.title.includes('@noDefendants')) { + process.env.CLAIMANT_NAME = submitCaseApiData.submitCasePayloadNoDefendants.overriddenClaimantName; process.env.CLAIMANT_NAME_OVERRIDDEN = 'YES'; process.env.CORRESPONDENCE_ADDRESS = 'UNKNOWN'; - process.env.CLAIMANT_NAME = submitCaseApiData.submitCasePayloadNoDefendants.overriddenClaimantName; await performAction('createCaseAPI', { data: createCaseApiData.createCasePayload }); await performAction('submitCaseAPI', { data: submitCaseApiData.submitCasePayloadNoDefendants }); } else if (testInfo.title.includes('@assured')) { @@ -77,7 +97,7 @@ test.beforeEach(async ({ page }, testInfo) => { } else if (testInfo.title.includes('@other')) { await performAction('createCaseAPI', { data: createCaseApiData.createCasePayload }); await performAction('submitCaseAPI', { data: submitCaseApiData.submitCasePayloadOtherTenancy }); - } else if (testInfo.title.includes('@rentAndNonRent')) { + } else if (testInfo.title.includes('@rentNonRent')) { await performAction('createCaseAPI', { data: createCaseApiData.createCasePayload }); await performAction('submitCaseAPI', { data: submitCaseApiData.submitCasePayloadRentNonRent }); } else { @@ -189,7 +209,9 @@ test.describe('Respond to a claim - e2e Journey @nightly', async () => { option: confirmationOfNoticeGiven.yesRadioOption, }); await performAction('enterNoticeDateUnknown'); - await performValidation('mainHeader', nonRentArrearsDispute.mainHeader); + await performAction('disputingOtherPartsOfTheClaim', { + disputeOption: nonRentArrearsDispute.noRadioOption, + }); }); test('Non-RentArrears - Secure - NoticeServed - Yes and NoticeDateProvided - Yes - NoticeDetails- Yes - Notice date known @secureFlexible @regression', async () => { @@ -232,8 +254,9 @@ test.describe('Respond to a claim - e2e Journey @nightly', async () => { option: confirmationOfNoticeGiven.yesRadioOption, }); await performAction('enterNoticeDateKnown'); - await performValidation('mainHeader', nonRentArrearsDispute.mainHeader); - await performAction('clickButton', nonRentArrearsDispute.continueButton); + await performAction('disputingOtherPartsOfTheClaim', { + disputeOption: nonRentArrearsDispute.noRadioOption, + }); // placeholder page, so need to be replaced with custom action when actual page is implemented await performValidation('mainHeader', counterClaim.mainHeader); await performAction('clickButton', counterClaim.saveAndContinueButton); @@ -280,8 +303,10 @@ test.describe('Respond to a claim - e2e Journey @nightly', async () => { await performAction('selectNoticeDetails', { option: confirmationOfNoticeGiven.imNotSureRadioOption, }); - await performValidation('mainHeader', nonRentArrearsDispute.mainHeader); - await performAction('clickButton', nonRentArrearsDispute.continueButton); + await performAction('disputingOtherPartsOfTheClaim', { + disputeOption: nonRentArrearsDispute.yesRadioOption, + disputeInfo: nonRentArrearsDispute.explainClaimTextInput, + }); // placeholder page, so need to be replaced with custom action when actual page is implemented await performValidation('mainHeader', counterClaim.mainHeader); await performAction('clickButton', counterClaim.saveAndContinueButton); @@ -326,8 +351,9 @@ test.describe('Respond to a claim - e2e Journey @nightly', async () => { tenancyTypeInfo: tenancyTypeDetails.giveCorrectTenancyTypeTextInput, }); await performAction('enterTenancyStartDetailsUnKnown'); - await performValidation('mainHeader', nonRentArrearsDispute.mainHeader); - await performAction('clickButton', nonRentArrearsDispute.continueButton); + await performAction('disputingOtherPartsOfTheClaim', { + disputeOption: nonRentArrearsDispute.noRadioOption, + }); }); test('RentArrears - Introductory - NoticeServed - Yes and NoticeDateProvided - No - NoticeDetails- Yes - Notice date unknown @regression', async () => { diff --git a/src/test/ui/functional/nonRentArrearsDispute.pft.ts b/src/test/ui/functional/nonRentArrearsDispute.pft.ts new file mode 100644 index 000000000..19fe26255 --- /dev/null +++ b/src/test/ui/functional/nonRentArrearsDispute.pft.ts @@ -0,0 +1,104 @@ +import { + confirmationOfNoticeGiven, + dashboard, + nonRentArrearsDispute, + noticeDateWhenNotProvided, + noticeDateWhenProvided, + tenancyDateDetails, + tenancyDateUnknown, +} from '../data/page-data'; +import { performAction, performValidation } from '../utils/controller'; + +export async function nonRentArrearsDisputeErrorValidation(): Promise { + //mandatory radio button selection + await performAction('clickButton', nonRentArrearsDispute.saveAndContinueButton); + await performValidation('errorMessage', { + header: nonRentArrearsDispute.thereIsAProblemErrorMessageHeader, + message: nonRentArrearsDispute.selectIfYouWantToDisputeErrorMessage, + }); + await performAction('clickRadioButton', nonRentArrearsDispute.yesRadioOption); + //hidden hint text for input field validation + await performValidation('elementToBeVisible', nonRentArrearsDispute.youHave6500CharactersHiddenHintText); + //mandatory input field validation for 'Yes' radio button selection + await performAction('clickButton', nonRentArrearsDispute.saveAndContinueButton); + await performValidation('errorMessage', { + header: nonRentArrearsDispute.thereIsAProblemErrorMessageHeader, + message: nonRentArrearsDispute.partsOfClaimDoNotAgreeErrorMessage, + }); + //character limit error validation + await performAction( + 'inputText', + nonRentArrearsDispute.explainPartOfClaimHiddenTextLabel, + nonRentArrearsDispute.detailsCharLimitInputText + ); + await performValidation('elementToBeVisible', nonRentArrearsDispute.tooManyCharacterHiddenHintText); + //link opening in new tab validation + await performAction( + 'clickLinkAndVerifyNewTabTitle', + nonRentArrearsDispute.viewTheClaimLink, + nonRentArrearsDispute.mainHeaderGovServiceHiddenNewTab + ); + await performAction( + 'inputText', + nonRentArrearsDispute.explainPartOfClaimHiddenTextLabel, + nonRentArrearsDispute.explainClaimTextInput + ); +} + +export async function noRentArrearsNavigationTests(): Promise { + if (process.env.NOTICE_SERVED === 'YES' && process.env.NOTICE_DATE_PROVIDED === 'YES') { + if (process.env.NOTICE_DETAILS_NO_NOTSURE === 'YES') { + await performValidation('pageNavigation', nonRentArrearsDispute.backLink, confirmationOfNoticeGiven.mainHeader); + } else { + await performValidation('pageNavigation', nonRentArrearsDispute.backLink, noticeDateWhenProvided.mainHeader); + } + } else if (process.env.NOTICE_SERVED === 'YES' && process.env.NOTICE_DATE_PROVIDED === 'NO') { + if (process.env.NOTICE_DETAILS_NO_NOTSURE === 'YES') { + await performValidation('pageNavigation', nonRentArrearsDispute.backLink, confirmationOfNoticeGiven.mainHeader); + } else { + await performValidation('pageNavigation', nonRentArrearsDispute.backLink, noticeDateWhenNotProvided.mainHeader); + } + } + + if ( + process.env.NOTICE_SERVED === 'NO' && + process.env.TENANCY_START_DATE_KNOWN === 'NO' && + process.env.RENT_NON_RENT === 'NO' + ) { + await performValidation('pageNavigation', nonRentArrearsDispute.backLink, tenancyDateUnknown.mainHeader); + } else if ( + process.env.NOTICE_SERVED === 'NO' && + process.env.TENANCY_START_DATE_KNOWN === 'YES' && + process.env.RENT_NON_RENT === 'NO' + ) { + await performValidation('pageNavigation', nonRentArrearsDispute.backLink, tenancyDateDetails.mainHeader); + } + //enable after 3495 is merged + + // else if ( + // process.env.NOTICE_SERVED === 'NO' && + // process.env.TENANCY_START_DATE_KNOWN === 'YES' && + // process.env.RENT_NON_RENT === 'YES' + // ) { + // await performValidation('pageNavigation', nonRentArrearsDispute.backLink, rentArrearsDispute.mainHeader); + // } + await performAction('clickRadioButton', nonRentArrearsDispute.yesRadioOption); + await performValidation('pageNavigation', nonRentArrearsDispute.saveForLaterButton, dashboard.mainHeader); +} + +//old implementation +// if (process.env.NOTICE_DATE_PROVIDED === 'NO') { +// await performValidation('pageNavigation', nonRentArrearsDispute.backLink, noticeDateWhenNotProvided.mainHeader); +// } else if (process.env.NOTICE_DATE_PROVIDED === 'YES') { +// await performValidation('pageNavigation', nonRentArrearsDispute.backLink, noticeDateWhenProvided.mainHeader); +// } else if (process.env.TENANCY_START_DATE_KNOWN === 'NO') { +// await performValidation('pageNavigation', nonRentArrearsDispute.backLink, tenancyDateUnknown.mainHeader); +// } else if (process.env.TENANCY_START_DATE_KNOWN === 'YES') { +// await performValidation('pageNavigation', nonRentArrearsDispute.backLink, tenancyDateDetails.mainHeader); +// } else if (process.env.RENT_NON_RENT === 'YES') { +// await performValidation('pageNavigation', nonRentArrearsDispute.backLink, rentArrearsDispute.mainHeader); +// } else if (process.env.NOTICE_DETAILS_NO_NOTSURE === 'YES') { +// await performValidation('pageNavigation', nonRentArrearsDispute.backLink, confirmationOfNoticeGiven.mainHeader); +// } +// await performValidation('pageNavigation', nonRentArrearsDispute.saveForLaterButton, dashboard.mainHeader); +// } diff --git a/src/test/ui/utils/actions/custom-actions/respondToClaim.action.ts b/src/test/ui/utils/actions/custom-actions/respondToClaim.action.ts index d327a0a10..59a2b9898 100644 --- a/src/test/ui/utils/actions/custom-actions/respondToClaim.action.ts +++ b/src/test/ui/utils/actions/custom-actions/respondToClaim.action.ts @@ -14,6 +14,7 @@ import { freeLegalAdvice, landlordLicensed, landlordRegistered, + nonRentArrearsDispute, noticeDateWhenNotProvided, noticeDateWhenProvided, paymentInterstitial, @@ -50,6 +51,7 @@ export class RespondToClaimAction implements IAction { ['selectLandlordRegistered', () => this.selectLandlordRegistered(fieldName as actionData)], ['selectWrittenTerms', () => this.selectWrittenTerms(fieldName as actionRecord)], ['enterTenancyStartDetailsUnKnown', () => this.enterTenancyStartDetailsUnKnown(fieldName as actionRecord)], + ['disputingOtherPartsOfTheClaim', () => this.disputingOtherPartsOfTheClaim(fieldName as actionRecord)], ['tenancyOrContractTypeDetails', () => this.tenancyOrContractTypeDetails(fieldName as actionRecord)], ['selectLandlordLicensed', () => this.selectLandlordLicensed(fieldName as actionRecord)], ]); @@ -286,6 +288,22 @@ export class RespondToClaimAction implements IAction { await performAction('clickButton', tenancyDateUnknown.saveAndContinueButton); } + private async disputingOtherPartsOfTheClaim(doYouWantToDisputeOption: actionRecord): Promise { + await performAction('clickRadioButton', { + question: nonRentArrearsDispute.doYouWantToDisputeQuestion, + option: doYouWantToDisputeOption.disputeOption, + }); + + if (doYouWantToDisputeOption.disputeOption === 'Yes') { + await performAction( + 'inputText', + nonRentArrearsDispute.explainPartOfClaimHiddenTextLabel, + doYouWantToDisputeOption.disputeInfo + ); + } + await performAction('clickButton', nonRentArrearsDispute.saveAndContinueButton); + } + private async tenancyOrContractTypeDetails(tenancyTypeDetailsInfo: actionRecord) { const tenancyType = formatTextToLowercaseSeparatedBySpace(tenancyTypeDetailsInfo.tenancyType as string); const article = /^[aeiou]/i.test(tenancyType) ? 'an' : 'a'; diff --git a/src/test/ui/utils/common/string.utils.ts b/src/test/ui/utils/common/string.utils.ts index 82061ac85..81845a29a 100644 --- a/src/test/ui/utils/common/string.utils.ts +++ b/src/test/ui/utils/common/string.utils.ts @@ -6,6 +6,18 @@ export function exactTextWithOptionalWhitespaceRegex(text: string): RegExp { return new RegExp(`^\\s*${escapeForRegex(text)}\\s*$`); } +export function generateRandomString(length: number): string { + const chars = `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`; + let result = ``; + + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * chars.length); + result += chars[randomIndex]; + } + + return result; +} + export function formatTextToLowercaseSeparatedBySpace(value: string): string { return value.toLowerCase().replace(/_/g, ' ').trim(); } diff --git a/src/test/ui/utils/registry/action.registry.ts b/src/test/ui/utils/registry/action.registry.ts index 89aaac697..41edbe95d 100644 --- a/src/test/ui/utils/registry/action.registry.ts +++ b/src/test/ui/utils/registry/action.registry.ts @@ -60,6 +60,7 @@ export class ActionRegistry { ['enterTenancyStartDetailsUnKnown', new RespondToClaimAction()], ['triggerFunctionalTests', new TriggerPageFunctionalTestsAction()], ['selectTenancyStartDateKnown', new RespondToClaimAction()], + ['disputingOtherPartsOfTheClaim', new RespondToClaimAction()], ['tenancyOrContractTypeDetails', new RespondToClaimAction()], ['selectLandlordLicensed', new RespondToClaimAction()], ['selectContactPreferenceEmailOrPost', new RespondToClaimAction()],