Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
9e2d78f
HDPI-5180: Create gen app skeleton journey
scottstewart-sl Mar 9, 2026
8a94076
Merge remote-tracking branch 'origin/master' into HDPI-5180_gen_app_s…
scottstewart-sl Mar 23, 2026
c3882a0
Merge remote-tracking branch 'origin/master' into HDPI-5180_gen_app_s…
scottstewart-sl Mar 25, 2026
55690ec
HDPI-5180: Update CYA page for gen apps
scottstewart-sl Mar 25, 2026
0b59970
HDPI-5180: Fix lint issues
scottstewart-sl Mar 25, 2026
13fbd73
HDPI-5180: Fix unit test following property name change
scottstewart-sl Mar 25, 2026
378da77
HDPI-5180: Use Continue button for now
scottstewart-sl Mar 25, 2026
1a2adc3
HDPI-5180: Fix accidental space
scottstewart-sl Mar 25, 2026
ee93665
HDPI-5180: Remove Suspend as is no longer in scope
scottstewart-sl Mar 25, 2026
ee0c5d4
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Mar 26, 2026
ff8cbf2
HDPI-5180: Resolve PR comments
scottstewart-sl Mar 26, 2026
5c8d84c
Merge branch 'HDPI-5180_gen_app_skeleton' of github.com:hmcts/pcs-fro…
scottstewart-sl Mar 26, 2026
7868fa8
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Mar 26, 2026
e3f7e04
HDPI-5180: Use entity encoding in another HTML page title
scottstewart-sl Mar 26, 2026
735f105
Merge remote-tracking branch 'origin/master' into HDPI-5180_gen_app_s…
scottstewart-sl Mar 27, 2026
3fdd1b5
HDPI-5180: Adding placeholder banner to pages
scottstewart-sl Mar 27, 2026
8a27cf6
HDPI-5180: Update brace-expansion to resolve CVE
scottstewart-sl Mar 27, 2026
4064415
Merge remote-tracking branch 'origin/master' into HDPI-5180_gen_app_s…
scottstewart-sl Mar 27, 2026
ff80075
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Mar 30, 2026
b929a54
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Mar 30, 2026
ac758c9
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Mar 31, 2026
e7e89b4
HDPI-5180: Fix merge issue
scottstewart-sl Mar 31, 2026
b692503
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Apr 1, 2026
4a991ac
initial commit
srinijg Apr 1, 2026
77b125f
new gen app tests added
srinijg Apr 1, 2026
1736136
Merge remote-tracking branch 'origin/HDPI-5180_gen_app_skeleton' into…
srinijg Apr 1, 2026
ee103ba
Merge branch 'master' into HDPI-5180_gen_app_skeleton
srinijg Apr 1, 2026
0ab77a8
Merge remote-tracking branch 'origin/HDPI-5180_gen_app_skeleton' into…
srinijg Apr 1, 2026
24f8855
lint fix
srinijg Apr 1, 2026
8bd26b6
Merge branch 'master' into HDPI-5180_gen_app_skeleton
scottstewart-sl Apr 2, 2026
aa0a479
Merge branch 'master' into HDPI-5180_gen_app_skeleton
srinijg Apr 7, 2026
93366f8
Merge remote-tracking branch 'origin/HDPI-5180_gen_app_skeleton' into…
srinijg Apr 7, 2026
0593f40
new tests added
srinijg Apr 7, 2026
dd9e8a8
error message update
srinijg Apr 7, 2026
545daca
tags added
srinijg Apr 7, 2026
5230de3
lint fix
srinijg Apr 8, 2026
151a179
Merge branch 'master' into HDPI-5180_gen_app_skeleton
srinijg Apr 8, 2026
a057a07
Merge remote-tracking branch 'origin/HDPI-5180_gen_app_skeleton' into…
srinijg Apr 8, 2026
3226496
test update
srinijg Apr 8, 2026
253c858
Merge branch 'master' into HDPI-5180_gen_app_skeleton
srinijg Apr 8, 2026
589a9da
tests updated
srinijg Apr 8, 2026
47cd7fa
Merge remote-tracking branch 'origin/HDPI-5180_gen_app_skeleton' into…
srinijg Apr 8, 2026
7f55d97
Merge branch 'master' into HDPI-5180_gen_app_skeleton
srinijg Apr 9, 2026
00edff3
separated spec files
srinijg Apr 9, 2026
d4ce7a3
Merge remote-tracking branch 'origin/HDPI-5180_gen_app_skeleton' into…
srinijg Apr 9, 2026
760d585
button updates
srinijg Apr 9, 2026
9ee1ee5
fixes to buttons
srinijg Apr 9, 2026
6abca3c
spec file renamed
srinijg Apr 9, 2026
2b20013
reference to improvements link added
srinijg Apr 10, 2026
409f03b
Merge remote-tracking branch 'origin/master' into HDPI-5180-Automation
srinijg Apr 10, 2026
311321f
separate Gen apps section
srinijg Apr 10, 2026
5b05d23
Merge branch 'master' into HDPI-5180-Automation
PadmaDeenadayalan Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/test/ui/config/urlToFileMapping.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ export default {
'your-household-and-circumstances': 'yourHouseholdAndCircumstances',
'do-you-have-any-dependant-children': 'doYouHaveAnyDependantChildren',
'do-you-have-any-other-dependants': 'doYouHaveAnyOtherDependants',
//Add Gen APPs mapping below this line
'choose-an-application': 'chooseAnApplication',
'check-your-answers': 'checkYourAnswers',
};
86 changes: 86 additions & 0 deletions src/test/ui/data/api-data/submitCase.api.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,5 +598,91 @@ export const submitCaseApiData = {
},
};
},
get submitCasePayloadDefault() {
return {
legislativeCountry: 'England',
claimantType: {
value: {
code: 'PROVIDER_OF_SOCIAL_HOUSING',
label: 'Registered provider of social housing',
},
list_items: [
{
code: 'PRIVATE_LANDLORD',
label: 'Private landlord',
},
{
code: 'PROVIDER_OF_SOCIAL_HOUSING',
label: 'Registered provider of social housing',
},
{
code: 'MORTGAGE_LENDER',
label: 'Mortgage lender',
},
{
code: 'OTHER',
label: 'Other',
},
],
valueCode: 'PROVIDER_OF_SOCIAL_HOUSING',
},
claimAgainstTrespassers: 'NO',
orgNameFound: 'Yes',
claimantName: 'Possession Claims Solicitor Org',
isClaimantNameCorrect: 'YES',
claimantContactEmail: 'pcs-solicitor-automation@test.com',
isCorrectClaimantContactEmail: 'YES',
orgAddressFound: 'Yes',
organisationAddress: {
AddressLine1: 'Ministry Of Justice',
AddressLine2: 'Seventh Floor 102 Petty France',
PostTown: 'London',
PostCode: 'SW1H 9AJ',
Country: 'United Kingdom',
},
formattedClaimantContactAddress: 'Ministry Of Justice<br>Seventh Floor 102 Petty France<br>London<br>SW1H 9AJ',
isCorrectClaimantContactAddress: 'YES',
claimantProvidePhoneNumber: 'NO',
defendant1: {
nameKnown: 'NO',
addressKnown: 'NO',
},
addAnotherDefendant: 'NO',
tenancy_TypeOfTenancyLicence: 'OTHER',
tenancy_DetailsOfOtherTypeOfTenancyLicence: 'Other tenancy - short term',
tenancy_TenancyLicenceDate: null,
tenancy_TenancyLicenceDocuments: [],
showIntroductoryDemotedOtherGroundReasonPage: 'Yes',
introGrounds_HasIntroductoryDemotedOtherGroundsForPossession: 'YES',
introGrounds_IntroductoryDemotedOrOtherGrounds: ['ANTI_SOCIAL'],
antiSocialBehaviourGround: 'Antisocial behaviour',
preActionProtocolCompleted: 'NO',
mediationAttempted: 'NO',
settlementAttempted: 'NO',
noticeServed: 'YES',
claimantNamePossessiveForm: 'Possession Claims Solicitor Org’s',
claimantCircumstancesSelect: 'NO',
hasDefendantCircumstancesInfo: 'NO',
suspensionOfRTB_ShowHousingActsPage: 'No',
demotionOfTenancy_ShowHousingActsPage: 'No',
suspensionToBuyDemotionOfTenancyPages: 'No',
alternativesToPossession: [],
claimingCostsWanted: 'NO',
additionalReasonsForPossession: {
hasReasons: 'NO',
},
hasUnderlesseeOrMortgagee: 'NO',
wantToUploadDocuments: 'NO',
applicationWithClaim: 'YES',
languageUsed: 'ENGLISH',
completionNextStep: 'SUBMIT_AND_PAY_NOW',
statementOfTruth: {
completedBy: 'CLAIMANT',
fullNameClaimant: 'fg',
positionClaimant: 'fg',
agreementClaimant: ['BELIEVE_TRUE'],
},
};
},
submitCaseApiEndPoint: (): string => `/cases/${process.env.CASE_NUMBER}/events`,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const checkYourAnswers = {
mainHeader: `Check your answers`,
submitApplicationButton: `Submit application`,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const chooseAnApplication = {
mainHeader: `Choose an application`,
whatDoYouWantToApplyForQuestion: `What do you want to apply for?`,
delayRadioOption: `Ask to adjourn (delay) the hearing`,
setAsideRadioOption: `Ask the court to change (set aside) their decision to evict you`,
somethingElseRadioOption: `Something else`,
continueButton: `Continue`,
cancelLink: `Cancel`,
thereIsAProblemErrorMessageHeader: `There is a problem`,
// if the below format is deemed complicated it will replaced as part of https://tools.hmcts.net/jira/browse/HDPI-5815
errorValidationType: { one: `radioOptions`, two: `textField`, three: `checkBox` },
Comment thread
srinijg marked this conversation as resolved.
errorValidationField: {
errorRadioOption: { type: `none`, input: ``, errMessage: `You must select an type of application to apply for` },
},
};
2 changes: 2 additions & 0 deletions src/test/ui/data/page-data/genApps-page-data/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './chooseAnApplication.page.data';
export * from './checkYourAnswers.page.data';
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { test } from '@playwright/test';
import config from 'config';

import { createCaseApiData, submitCaseApiData } from '../../data/api-data';
import { checkYourAnswers, chooseAnApplication } from '../../data/page-data/genApps-page-data';
import { finaliseAllValidations, initializeExecutor, performAction, performValidation } from '../../utils/controller';

const home_url = config.get('e2e.testUrl') as string;

test.beforeEach(async ({ page }) => {
initializeExecutor(page);
await performAction('createCaseAPI', { data: createCaseApiData.createCasePayload });
await performAction('submitCaseAPI', { data: submitCaseApiData.submitCasePayloadDefault });
await performAction('fetchPINsAPI');
await performAction('createUser', 'citizen', ['citizen']);
await performAction('validateAccessCodeAPI');
await performAction('navigateToUrl', home_url);
await performAction('login');
await performAction(
'navigateToUrl',
home_url + `/case/${process.env.CASE_NUMBER}/make-an-application/choose-an-application`
);
});

test.afterEach(async () => {
finaliseAllValidations();
});

test.describe('Make an Application - e2e Journey @nightly', async () => {
test('Select an Application - Ask to Adjourn journey @regression', async () => {
await performAction('chooseAnApplication', {
question: chooseAnApplication.whatDoYouWantToApplyForQuestion,
option: chooseAnApplication.delayRadioOption,
});
await performValidation('mainHeader', checkYourAnswers.mainHeader);
await performAction('clickButton', checkYourAnswers.submitApplicationButton);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { test } from '@playwright/test';
import config from 'config';

import { createCaseApiData, submitCaseApiData } from '../../data/api-data';
import { checkYourAnswers, chooseAnApplication } from '../../data/page-data/genApps-page-data';
import { finaliseAllValidations, initializeExecutor, performAction, performValidation } from '../../utils/controller';

const home_url = config.get('e2e.testUrl') as string;

test.beforeEach(async ({ page }) => {
initializeExecutor(page);
await performAction('createCaseAPI', { data: createCaseApiData.createCasePayload });
await performAction('submitCaseAPI', { data: submitCaseApiData.submitCasePayloadDefault });
await performAction('fetchPINsAPI');
await performAction('createUser', 'citizen', ['citizen']);
await performAction('validateAccessCodeAPI');
await performAction('navigateToUrl', home_url);
await performAction('login');
await performAction(
'navigateToUrl',
home_url + `/case/${process.env.CASE_NUMBER}/make-an-application/choose-an-application`
);
});

test.afterEach(async () => {
finaliseAllValidations();
});

test.describe('Make an Application - e2e Journey @nightly', async () => {
test('Select an Application - Ask to Set aside @regression', async () => {
await performAction('chooseAnApplication', {
question: chooseAnApplication.whatDoYouWantToApplyForQuestion,
option: chooseAnApplication.setAsideRadioOption,
});
await performValidation('mainHeader', checkYourAnswers.mainHeader);
await performAction('clickButton', checkYourAnswers.submitApplicationButton);
});
});
Comment thread
Gautham059 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { test } from '@playwright/test';
import config from 'config';

import { createCaseApiData, submitCaseApiData } from '../../data/api-data';
import { checkYourAnswers, chooseAnApplication } from '../../data/page-data/genApps-page-data';
import { finaliseAllValidations, initializeExecutor, performAction, performValidation } from '../../utils/controller';

const home_url = config.get('e2e.testUrl') as string;

test.beforeEach(async ({ page }) => {
initializeExecutor(page);
await performAction('createCaseAPI', { data: createCaseApiData.createCasePayload });
await performAction('submitCaseAPI', { data: submitCaseApiData.submitCasePayloadDefault });
await performAction('fetchPINsAPI');
await performAction('createUser', 'citizen', ['citizen']);
await performAction('validateAccessCodeAPI');
await performAction('navigateToUrl', home_url);
await performAction('login');
await performAction(
'navigateToUrl',
home_url + `/case/${process.env.CASE_NUMBER}/make-an-application/choose-an-application`
);
});

test.afterEach(async () => {
finaliseAllValidations();
});

test.describe('Make an Application - e2e Journey @nightly', async () => {
test('Select an Application - Something else @regression', async () => {
await performAction('chooseAnApplication', {
question: chooseAnApplication.whatDoYouWantToApplyForQuestion,
option: chooseAnApplication.somethingElseRadioOption,
});
await performValidation('mainHeader', checkYourAnswers.mainHeader);
await performAction('clickButton', checkYourAnswers.submitApplicationButton);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { chooseAnApplication } from '../../data/page-data/genApps-page-data';
import { performAction } from '../../utils/controller';

export async function chooseAnApplicationErrorValidation(): Promise<void> {
await performAction('inputErrorValidationGenApp', {
validationType: chooseAnApplication.errorValidationType.one,
inputArray: chooseAnApplication.errorValidationField.errorRadioOption,
header: chooseAnApplication.thereIsAProblemErrorMessageHeader,
question: chooseAnApplication.whatDoYouWantToApplyForQuestion,
option: chooseAnApplication.delayRadioOption,
button: chooseAnApplication.continueButton,
});
}
45 changes: 45 additions & 0 deletions src/test/ui/utils/actions/custom-actions/genApps.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Page } from '@playwright/test';

import { chooseAnApplication } from '../../../data/page-data/genApps-page-data';
import { performAction, performValidation } from '../../controller';
import { IAction, actionData, actionRecord } from '../../interfaces';

export class GenAppsAction implements IAction {
async execute(page: Page, action: string, fieldName: actionData | actionRecord): Promise<void> {
const actionsMap = new Map<string, () => Promise<void>>([
['chooseAnApplication', () => this.chooseAnApplication(fieldName as actionRecord)],
['inputErrorValidationGenApp', () => this.inputErrorValidationGenApp(fieldName as actionRecord)],
]);
const actionToPerform = actionsMap.get(action);
if (!actionToPerform) {
throw new Error(`No action found for '${action}'`);
}
await actionToPerform();
}

private async chooseAnApplication(chooseApp: actionRecord) {
await performAction('clickRadioButton', {
question: chooseApp.question,
option: chooseApp.option,
});
await performAction('clickButton', chooseAnApplication.continueButton);
}

private async inputErrorValidationGenApp(validationArr: actionRecord) {
const inputs = Array.isArray(validationArr.inputArray) ? validationArr.inputArray : [validationArr.inputArray];

for (const item of inputs) {
switch (validationArr.validationType) {
case 'radioOptions':
await performAction('clickButton', validationArr.button);
await performValidation(
'errorMessage',
!validationArr?.header ? (validationArr.header = 'There is a problem') : validationArr.header,
item.errMessage
);
await performAction('clickRadioButton', { question: validationArr.question, option: validationArr.option });
break;
}
}
}
}
1 change: 1 addition & 0 deletions src/test/ui/utils/actions/custom-actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './navigateToUrl.action';
export * from './fetchPINsAndValidateAccessCodeAPI.action';
export * from './respondToClaim.action';
export * from './triggerPageFunctionalTests.action';
export * from './genApps.action';
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,22 @@ export class TriggerPageFunctionalTestsAction implements IAction {

TriggerPageFunctionalTestsAction.pagesTestedInCurrentRun.add(pageName);

const pageDataFilePath = path.join(TriggerPageFunctionalTestsAction.PAGE_DATA_DIR, `${pageName}.page.data.ts`);
const pageDataFileExists = fs.existsSync(pageDataFilePath);
const pageDataFilePath = this.resolveFilePath(
TriggerPageFunctionalTestsAction.PAGE_DATA_DIR,
`${pageName}.page.data.ts`
);

if (enable_content_validation === 'true') {
if (pageDataFileExists) {
if (pageDataFilePath && fs.existsSync(pageDataFilePath)) {
Comment thread
Gautham059 marked this conversation as resolved.
PageContentValidation.trackPageWithData(pageName);
await this.runPageContentValidation(page, pageName);
} else {
PageContentValidation.trackMissingDataFile(pageName);
}
}

const pftFilePath = path.join(TriggerPageFunctionalTestsAction.PFT_DIR, `${pageName}.pft.ts`);
const pftFileExists = fs.existsSync(pftFilePath);

if (!pftFileExists) {
const pftFilePath = this.resolveFilePath(TriggerPageFunctionalTestsAction.PFT_DIR, `${pageName}.pft.ts`);
if (!pftFilePath || !fs.existsSync(pftFilePath)) {
if (enable_error_message_validation === 'true') {
ErrorMessageValidation.trackMissingEMVFile(pageName);
}
Expand Down Expand Up @@ -113,6 +113,28 @@ export class TriggerPageFunctionalTestsAction implements IAction {
}
}

private resolveFilePath(baseDir: string, pageName: string): string | null {
if (!fs.existsSync(baseDir)) {
throw new Error(`Base directory does not exist: ${baseDir}`);
}

const directPath = path.join(baseDir, pageName);
if (fs.existsSync(directPath)) {
return directPath;
}

const subDirs = fs.readdirSync(baseDir, { withFileTypes: true }).filter(d => d.isDirectory());

for (const dir of subDirs) {
const subDirPath = path.join(baseDir, dir.name, pageName);
if (fs.existsSync(subDirPath)) {
return subDirPath;
}
}

return null;
}

private createLockFile(pageName: string): void {
try {
if (!fs.existsSync(TriggerPageFunctionalTestsAction.LOCK_DIR)) {
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/utils/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ function getExecutor(): { page: Page } {
async function detectPageNavigation(): Promise<boolean> {
const executor = getExecutor();
const currentUrl = executor.page.url();
if (!startAxeAudit && executor.page.url().includes('start-now')) {
const testPages = ['start-now', 'choose-an-application'];
if (!startAxeAudit && testPages.some(page => currentUrl.includes(page))) {
startAxeAudit = true;
startFunctionalTests = true;
}
Expand Down
4 changes: 4 additions & 0 deletions src/test/ui/utils/registry/action.registry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
CreateCaseAPIAction,
FetchPINsAndValidateAccessCodeAPIAction,
GenAppsAction,
LoginAction,
NavigateToUrlAction,
RespondToClaimAction,
Expand Down Expand Up @@ -72,6 +73,9 @@ export class ActionRegistry {
['rentArrears', new RespondToClaimAction()],
['yourCircumstances', new RespondToClaimAction()],
['exceptionalHardship', new RespondToClaimAction()],
//ADD GEN APPS details below this line
['chooseAnApplication', new GenAppsAction()],
['inputErrorValidationGenApp', new GenAppsAction()],
]);

static getAction(actionName: string): IAction {
Expand Down
Loading