From d5bc4a9bd1454ff676c80c4b791be98f359a108e Mon Sep 17 00:00:00 2001 From: Gareth Lancaster <90632240+Gareth40343@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:49:32 +0100 Subject: [PATCH] CIV-15169 Hearing Notice API Tests (#4821) * Added spec and unspec hearing notice scheduler tests * Updated spec hearing notice tests * Unskip 1v2 diff transfer case offline test --------- Co-authored-by: GarethLancaster <31533575+Gareth40342@users.noreply.github.com> Co-authored-by: vasudevganesanhmcts <100689363+vasudevganesanhmcts@users.noreply.github.com> --- codecept.conf.js | 1 + e2e/api/dataHelper.js | 20 +- e2e/api/serviceAuthorisationHelper.js | 24 ++ e2e/api/steps_hearings.js | 53 ++- e2e/api/testingSupport.js | 181 +++++----- e2e/api/wiremock.js | 52 --- e2e/api/wiremock/data/hearings.js | 322 ++++++++++++++++++ e2e/api/wiremock/requests/hearings.js | 76 +++++ e2e/api/wiremock/wiremock.js | 94 +++++ e2e/config.js | 4 +- e2e/fixtures/camundaProcesses.js | 5 + e2e/helpers/activeOrganisationUsers.js | 2 +- .../hearing_notice_scheduler_test.js | 63 ++++ .../1v2CreateClaim_DiffSol_fast_track_test.js | 2 +- package.json | 1 + 15 files changed, 742 insertions(+), 158 deletions(-) create mode 100644 e2e/api/serviceAuthorisationHelper.js delete mode 100644 e2e/api/wiremock.js create mode 100644 e2e/api/wiremock/data/hearings.js create mode 100644 e2e/api/wiremock/requests/hearings.js create mode 100644 e2e/api/wiremock/wiremock.js create mode 100644 e2e/fixtures/camundaProcesses.js create mode 100644 e2e/tests/api_tests/automated_hearing_notice/hearing_notice_scheduler_test.js diff --git a/codecept.conf.js b/codecept.conf.js index 11d337ee6f..eef1b977cd 100644 --- a/codecept.conf.js +++ b/codecept.conf.js @@ -27,6 +27,7 @@ exports.config = { './e2e/tests/api_tests/lrspec_cui/*_test.js', './e2e/tests/api_tests/multiIntermediateTrack/*_test.js', './e2e/tests/api_tests/settle-discontinue/*_test.js', + './e2e/tests/api_tests/automated_hearing_notice/*_test.js' ], output: process.env.REPORT_DIR || 'test-results/functional', helpers: { diff --git a/e2e/api/dataHelper.js b/e2e/api/dataHelper.js index fac6c8113a..ed5e29e99f 100644 --- a/e2e/api/dataHelper.js +++ b/e2e/api/dataHelper.js @@ -67,7 +67,25 @@ module.exports = { dateTime: (days = 0) => { return getDateTimeISOString(days); }, - + incrementDate: (date = new Date(), dayIncrement, monthIncrement, yearIncrement) => { + const newDate = new Date(date); + if(dayIncrement) { + newDate.setDate(newDate.getDate() + dayIncrement); + } + if(monthIncrement) { + newDate.setMonth(newDate.getMonth() + monthIncrement); + } + if(yearIncrement) { + newDate.setYear(newDate.getFullYear() + yearIncrement); + } + return newDate; + }, + appendTime: (date = new Date(), hours, minutes) => { + const newDate = new Date(date); + newDate.setHours(hours ? hours : date.getHours()); + newDate.setMinutes(minutes ? minutes : date.getMinutes()); + return newDate; + }, document: filename => { const documentId = uuid.v1(); return { diff --git a/e2e/api/serviceAuthorisationHelper.js b/e2e/api/serviceAuthorisationHelper.js new file mode 100644 index 0000000000..2420c7b7dd --- /dev/null +++ b/e2e/api/serviceAuthorisationHelper.js @@ -0,0 +1,24 @@ +const restHelper = require('./restHelper'); +const config = require('../config'); +const totp = require('totp-generator'); +const {s2sForXUI, s2s} = require('../config'); + +const getS2sToken = async ({microservice, secret}) => { + return restHelper.retriedRequest( + `${config.url.authProviderApi}/lease`, + {'Content-Type': 'application/json'}, + { + microservice: microservice, + oneTimePassword: totp(secret) + }) + .then(response => response.text()); +}; + +module.exports = { + civilServiceAuth: () => { + return getS2sToken(s2s); + }, + xuiAuth: () => { + return getS2sToken(s2sForXUI); + }, +}; diff --git a/e2e/api/steps_hearings.js b/e2e/api/steps_hearings.js index f951ebf180..c2cbe5bbf0 100644 --- a/e2e/api/steps_hearings.js +++ b/e2e/api/steps_hearings.js @@ -1,4 +1,4 @@ -const {checkCaseFlagsEnabled, checkCaseFlagsAndHmcEnabled} = require('./testingSupport'); +const {checkCaseFlagsEnabled, checkCaseFlagsAndHmcEnabled, triggerCamundaProcess, waitForCompletedCamundaProcess} = require('./testingSupport'); const apiRequest = require('./apiRequest.js'); const {addAndAssertCaseFlag} = require('./caseFlagsHelper'); const {getHearingsPayload} = require('./apiRequest'); @@ -6,6 +6,16 @@ const chai = require('chai'); const {expect} = chai; const {date} = require('../api/dataHelper'); const config = require('../config'); +const {listedHearing} = require('./wiremock/data/hearings'); +const {createUpdateStub} = require('./wiremock/wiremock'); +const {hearingStubRequestBody, unnotifiedHearingStubRequestBody, getpartiesNotifiedStubRequestBody, + putPartiesNotifiedStubRequestBody +} = require('./wiremock/requests/hearings'); +const { + AUTOMATED_HEARING_NOTICE, + UNSPEC_AUTOMATED_HEARING_NOTICE_SCHEDULER, + SPEC_AUTOMATED_HEARING_NOTICE_SCHEDULER +} = require('../fixtures/camundaProcesses'); const specServiceId = 'AAA6'; const unspecServiceId = 'AAA7'; @@ -13,6 +23,9 @@ const unspecServiceId = 'AAA7'; const runningOnLocal = () => !['aat', 'demo', 'preview'].includes(config.runningEnv); const locationId = () => runningOnLocal() ? '000000' : '424213'; +const createHearingId = () => `${Math.floor(1000000000 + Math.random() * 9000000000)}`; +const getUILink = (process)=> `${process.links[0].href.replace('engine-rest', 'app/cockpit/default/#')}`; + const getExpectedPayload = (serviceId) => { if (serviceId === specServiceId) { return { @@ -840,6 +853,28 @@ const getExpectedPayload = (serviceId) => { } ; +const createHearing = async (caseId, hearingType, serviceCode) => { + const hearingId = createHearingId(); + const hearing = listedHearing(caseId, hearingId, hearingType, serviceCode); + await createUpdateStub(hearingStubRequestBody(hearing, hearingId)); + console.log(`Created new hearing mock: [${hearingId} - ${hearingType}]`); + return hearingId; +}; + +const triggerHearingNoticeScheduler = async (expectedHearingId, definitionKey) => { + //Update unnotified hearings stub + await createUpdateStub(unnotifiedHearingStubRequestBody([expectedHearingId])); + + const process = await triggerCamundaProcess(definitionKey); + console.log(`Started hearing notice scheduler process: ${getUILink(process)}`); + + // Wait for the hearing notice scheduler process + await waitForCompletedCamundaProcess(null, process.id, null); + + // Wait for hearing notice process + await waitForCompletedCamundaProcess(AUTOMATED_HEARING_NOTICE, null, `hearingId_eq_${expectedHearingId}`); +}; + module.exports = { createCaseFlags: async (user, caseId, flagLocation, flag) => { if (!(await checkCaseFlagsEnabled())) { @@ -882,5 +917,21 @@ module.exports = { expect(actualPayload).deep.equal(expectedPayload); expect(caseDeepLink).deep.contain(`/cases/case-details/${caseId}`); }, + setupStaticMocks: async () => { + await createUpdateStub(getpartiesNotifiedStubRequestBody()); + await createUpdateStub(putPartiesNotifiedStubRequestBody()); + }, + createUnspecTrialHearing: async (caseId) => createHearing(caseId, 'TRI', 'AAA7'), + createUnspecDisposalHearing: async (caseId) => createHearing(caseId, 'DIS', 'AAA7'), + createUnspecDisputeResolutionHearing: async (caseId) => createHearing(caseId, 'DRH', 'AAA7'), + createSpecTrialHearing: async (caseId) => createHearing(caseId, 'TRI', 'AAA6'), + createSpecDisposalHearing: async (caseId) => createHearing(caseId, 'DIS', 'AAA6'), + createSpecDisputeResolutionHearing: async (caseId) => createHearing(caseId, 'DRH', 'AAA6'), + triggerUnspecAutomatedHearingNoticeScheduler: async (expectedHearingId) => { + return await triggerHearingNoticeScheduler(expectedHearingId, UNSPEC_AUTOMATED_HEARING_NOTICE_SCHEDULER); + }, + triggerSpecAutomatedHearingNoticeScheduler: async (expectedHearingId) => { + return await triggerHearingNoticeScheduler(expectedHearingId, SPEC_AUTOMATED_HEARING_NOTICE_SCHEDULER); + } }; diff --git a/e2e/api/testingSupport.js b/e2e/api/testingSupport.js index 13979cc58a..85c1199104 100644 --- a/e2e/api/testingSupport.js +++ b/e2e/api/testingSupport.js @@ -1,8 +1,8 @@ const config = require('../config.js'); const idamHelper = require('./idamHelper'); +const serviceAuthHelper = require('./serviceAuthorisationHelper'); const restHelper = require('./restHelper'); const {retry} = require('./retryHelper'); -const totp = require('totp-generator'); let incidentMessage; @@ -12,14 +12,7 @@ const RETRY_TIMEOUT_MS = 5000; const checkFlagEnabled = async (flag) => { const authToken = await idamHelper.accessToken(config.applicantSolicitorUser); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); return await restHelper.request( `${config.url.civilService}/testing-support/feature-toggle/${flag}`, @@ -66,14 +59,7 @@ const checkMintiToggleEnabled = async () => { module.exports = { waitForFinishedBusinessProcess: async caseId => { const authToken = await idamHelper.accessToken(config.applicantSolicitorUser); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); await retry(() => { return restHelper.request( @@ -96,17 +82,39 @@ module.exports = { if (incidentMessage) throw new Error(`Business process failed for case: ${caseId}, incident message: ${incidentMessage}`); }, + waitForCompletedCamundaProcess: async (definitionKey, processInstanceId, variables) => { + const authToken = await idamHelper.accessToken(config.systemUpdate2); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); + + await retry(() => { + const params = {definitionKey, processInstanceId, variables}; + const url = new URL(`${config.url.civilService}/testing-support/camunda-processes`); + Object.keys(params).forEach(key => { + if (params[key]) { + url.searchParams.append(key, params[key]); + } + }); + return restHelper.request( + url.toString(), + { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${authToken}`, + 'ServiceAuthorization': s2sAuth + }, null, 'GET') + .then(async response => await response.json()).then(response => { + // console.log(JSON.stringify(response)); + if (response && response.length > 0 && response[0].state === 'COMPLETED') { + console.log(`${response[0].processDefinitionKey} process has completed!!`); + } else { + throw new Error('Waiting for camunda process to complete'); + } + }); + }, 10, RETRY_TIMEOUT_MS); + }, assignCaseToDefendant: async (caseId, caseRole = 'RESPONDENTSOLICITORONE', user = config.defendantSolicitorUser) => { const authToken = await idamHelper.accessToken(user); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); await retry(() => { return restHelper.request( @@ -132,49 +140,34 @@ module.exports = { }, assignCaseToLRSpecDefendant: async (caseId, caseRole = 'RESPONDENTSOLICITORONE', user = config.defendantSolicitorUser) => { - const authToken = await idamHelper.accessToken(user); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); - - await retry(() => { - return restHelper.request( - `${config.url.civilService}/testing-support/assign-case/${caseId}/${caseRole}`, - { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${authToken}`, - 'ServiceAuthorization': s2sAuth - }, - {}, - 'POST') - .then(response => { - if (response.status === 200) { - console.log( 'Role created successfully'); - } else if (response.status === 409) { - console.log('Role already exists!'); - } else { - throw new Error(`Error occurred with status : ${response.status}`); - } - }); - }); - }, + const authToken = await idamHelper.accessToken(user); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); + + await retry(() => { + return restHelper.request( + `${config.url.civilService}/testing-support/assign-case/${caseId}/${caseRole}`, + { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${authToken}`, + 'ServiceAuthorization': s2sAuth + }, + {}, + 'POST') + .then(response => { + if (response.status === 200) { + console.log('Role created successfully'); + } else if (response.status === 409) { + console.log('Role already exists!'); + } else { + throw new Error(`Error occurred with status : ${response.status}`); + } + }); + }); + }, unAssignUserFromCases: async (caseIds, user) => { const authToken = await idamHelper.accessToken(user); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); - + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); await retry(() => { return restHelper.request( @@ -202,15 +195,7 @@ module.exports = { checkToggleEnabled: async (toggle) => { const authToken = await idamHelper.accessToken(config.applicantSolicitorUser); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); - + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); return await restHelper.request( `${config.url.civilService}/testing-support/feature-toggle/${toggle}`, @@ -232,15 +217,7 @@ module.exports = { checkPBAv3IsEnabled: async () => { const authToken = await idamHelper.accessToken(config.applicantSolicitorUser); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); - + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); return await restHelper.request( `${config.url.civilService}/testing-support/feature-toggle/pba-version-3-ways-to-pay`, @@ -262,15 +239,7 @@ module.exports = { updateCaseData: async (caseId, caseData, user = config.applicantSolicitorUser) => { const authToken = await idamHelper.accessToken(user); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); - + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); await restHelper.retriedRequest( `${config.url.civilService}/testing-support/case/${caseId}`, @@ -283,14 +252,7 @@ module.exports = { uploadDocument: async () => { const authToken = await idamHelper.accessToken(config.applicantSolicitorUser); - const s2sAuth = await restHelper.retriedRequest( - `${config.url.authProviderApi}/lease`, - {'Content-Type': 'application/json'}, - { - microservice: config.s2s.microservice, - oneTimePassword: totp(config.s2s.secret) - }) - .then(response => response.text()); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); let response = await restHelper.request( `${config.url.civilService}/testing-support/upload/test-document`, @@ -304,6 +266,25 @@ module.exports = { return await response.json(); }, + triggerCamundaProcess: async (processName, variables = {}) => { + const authToken = await idamHelper.accessToken(config.systemUpdate2); + const s2sAuth = await serviceAuthHelper.civilServiceAuth(); + + let response = await restHelper.request( + `${config.url.civilService}/testing-support/trigger-camunda-process`, + { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${authToken}`, + 'ServiceAuthorization': s2sAuth + }, + { + name: processName, + variables + }, + 'POST'); + + return await response.json(); + }, checkCaseFlagsAndHmcEnabled: async () => { const caseFlagsEnabled = await checkCaseFlagsEnabled(); console.log(`caseFlagsEnabled: ${caseFlagsEnabled}`); diff --git a/e2e/api/wiremock.js b/e2e/api/wiremock.js deleted file mode 100644 index 46cdbb5edc..0000000000 --- a/e2e/api/wiremock.js +++ /dev/null @@ -1,52 +0,0 @@ -const restHelper = require('./restHelper'); -const {url} = require('../config'); - -const wireMockUrl = `${url.wiremockService}/__admin/mappings`; -const headers = { - 'Content-Type': 'application/json' -}; - -const getStubs = async () => { - return restHelper.request( - wireMockUrl, null, null, 'GET', 200) - .then(async response => { - const content = await response.json(); - return content.mappings; - }); -}; - -const getStubByRequestUrl = async (stubRequestUrl) => { - const allStubs = await getStubs(); - const targetStub = allStubs.find(stub => stub.request.urlPath == stubRequestUrl); - if (targetStub == null) { - throw new Error(`Could not locate stub for: ${stubRequestUrl} request url`); - } - return targetStub; -}; - -const updateStubById = async (stubId, mappingContent) => { - return restHelper.request( - `${wireMockUrl}/${stubId}`, headers, mappingContent, 'PUT', 200) - .then(response => { - response.json(); - }); -}; - -const updateStubResponseFileByRequestUrl = async (stubRequestUrl, bodyFileName) => { - return getStubByRequestUrl(stubRequestUrl) - .then(stub => updateStubById(stub.id, { - ...stub, - response: { - ...stub.response, - bodyFileName - } - }) - ); -}; - -module.exports = { - getStubs, - getStubByRequestUrl, - updateStubById, - updateStubResponseFileByRequestUrl -}; diff --git a/e2e/api/wiremock/data/hearings.js b/e2e/api/wiremock/data/hearings.js new file mode 100644 index 0000000000..5f2c8570b7 --- /dev/null +++ b/e2e/api/wiremock/data/hearings.js @@ -0,0 +1,322 @@ +const {incrementDate, appendTime} = require('../../dataHelper'); + +const listedHearing = (caseId, hearingId, hearingType, serviceCode) => { + const today = new Date(); + const hearingDate = incrementDate(today, 5, null, null); + + return { + 'requestDetails': { + 'status': 'LISTED', + 'timestamp': `${today.toISOString()}`, + 'versionNumber': 1, + 'hearingRequestID': `${hearingId}` + }, + 'hearingDetails': { + 'hearingType': `${serviceCode}-${hearingType}`, + 'hearingWindow': {}, + 'duration': 60, + 'hearingPriorityType': 'Standard', + 'numberOfPhysicalAttendees': 5, + 'hearingInWelshFlag': false, + 'hearingLocations': [ + { + 'locationType': 'court', + 'locationId': '424213' + } + ], + 'privateHearingRequiredFlag': false, + 'panelRequirements': { + 'roleType': [ + '45' + ], + 'authorisationTypes': [], + 'authorisationSubType': [], + 'panelPreferences': [], + 'panelSpecialisms': [] + }, + 'hearingIsLinkedFlag': false, + 'hearingChannels': [ + 'INTER' + ], + 'autolistFlag': false + }, + 'caseDetails': { + 'hmctsServiceCode': `${serviceCode}`, + 'caseRef': `${caseId}`, + 'caseDeepLink': `https://manage-case.demo.platform.hmcts.net/cases/case-details/${caseId}`, + 'hmctsInternalCaseName': '\'New name\' represented by \'Gareth Lancaster\' (litigation friend) v \'John Doe\'', + 'publicCaseName': '\'New name\' represented by \'Gareth Lancaster\' (litigation friend) v \'John Doe\'', + 'caseAdditionalSecurityFlag': false, + 'caseInterpreterRequiredFlag': false, + 'caseCategories': [ + { + 'categoryType': 'caseType', + 'categoryValue': `${serviceCode}-FAST_CLAIM` + }, + { + 'categoryType': 'caseSubType', + 'categoryValue': `${serviceCode}-FAST_CLAIM`, + 'categoryParent': `${serviceCode}-FAST_CLAIM` + } + ], + 'caseManagementLocationCode': '424213', + 'caserestrictedFlag': false, + 'caseSLAStartDate': '2024-02-08' + }, + 'partyDetails': [ + { + 'partyID': '70e0aa2c-0c2a-41', + 'partyType': 'ORG', + 'partyRole': 'CLAI', + 'organisationDetails': { + 'name': 'New name', + 'organisationType': 'ORG', + 'cftOrganisationID': null + }, + 'unavailabilityRanges': [ + { + 'unavailableFromDate': '2024-02-18', + 'unavailableToDate': '2024-02-18', + 'unavailabilityType': 'All Day' + }, + { + 'unavailableFromDate': '2024-03-09', + 'unavailableToDate': '2024-03-14', + 'unavailabilityType': 'All Day' + } + ] + }, + { + 'partyID': 'B04IXE4', + 'partyType': 'ORG', + 'partyRole': 'LGRP', + 'organisationDetails': { + 'name': 'Civil - Organisation 1', + 'organisationType': 'ORG', + 'cftOrganisationID': 'B04IXE4' + } + }, + { + 'partyID': 'DAWY9LJ', + 'partyType': 'ORG', + 'partyRole': 'LGRP', + 'organisationDetails': { + 'name': 'Civil - Organisation 2', + 'organisationType': 'ORG', + 'cftOrganisationID': 'DAWY9LJ' + } + }, + { + 'partyID': '03dd0269-a4b1-48', + 'partyType': 'IND', + 'partyRole': 'LGRP', + 'individualDetails': { + 'title': null, + 'firstName': 'claimant1', + 'lastName': 'lrindividual', + 'preferredHearingChannel': 'INTER', + 'interpreterLanguage': null, + 'reasonableAdjustments': [], + 'vulnerableFlag': false, + 'vulnerabilityDetails': null, + 'hearingChannelEmail': [ + 'hjfkhkjdsfhsdf@gmail.com' + ], + 'hearingChannelPhone': [ + '07898767676' + ], + 'relatedParties': [], + 'custodyStatus': null, + 'otherReasonableAdjustmentDetails': null + } + }, + { + 'partyID': 'c6864175-2314-45', + 'partyType': 'IND', + 'partyRole': 'LIFR', + 'individualDetails': { + 'title': null, + 'firstName': 'Gareth', + 'lastName': 'Lancaster', + 'preferredHearingChannel': 'INTER', + 'interpreterLanguage': null, + 'reasonableAdjustments': [], + 'vulnerableFlag': false, + 'vulnerabilityDetails': null, + 'hearingChannelEmail': [ + 'Gareththelitigant@litigants.com' + ], + 'hearingChannelPhone': [ + '07123456789' + ], + 'relatedParties': [], + 'custodyStatus': null, + 'otherReasonableAdjustmentDetails': null + } + }, + { + 'partyID': '0bf456e0-c680-11', + 'partyType': 'IND', + 'partyRole': 'DEFE', + 'individualDetails': { + 'title': null, + 'firstName': 'John', + 'lastName': 'Doe', + 'preferredHearingChannel': 'TEL', + 'interpreterLanguage': null, + 'reasonableAdjustments': [], + 'vulnerableFlag': false, + 'vulnerabilityDetails': null, + 'hearingChannelEmail': [], + 'hearingChannelPhone': [], + 'relatedParties': [], + 'custodyStatus': null, + 'otherReasonableAdjustmentDetails': null + }, + 'unavailabilityRanges': [ + { + 'unavailableFromDate': '2024-02-18', + 'unavailableToDate': '2024-02-18', + 'unavailabilityType': 'All Day' + }, + { + 'unavailableFromDate': '2024-03-09', + 'unavailableToDate': '2024-03-14', + 'unavailabilityType': 'All Day' + } + ] + }, + { + 'partyID': 'f4aca95a-dc91-41', + 'partyType': 'IND', + 'partyRole': 'WITN', + 'individualDetails': { + 'title': null, + 'firstName': 'John', + 'lastName': 'Smith', + 'preferredHearingChannel': 'VID', + 'interpreterLanguage': null, + 'reasonableAdjustments': [], + 'vulnerableFlag': false, + 'vulnerabilityDetails': null, + 'hearingChannelEmail': [ + 'johnsmith@email.com' + ], + 'hearingChannelPhone': [ + '07012345678' + ], + 'relatedParties': [], + 'custodyStatus': null, + 'otherReasonableAdjustmentDetails': null + } + }, + { + 'partyID': 'd5577b58-c753-43', + 'partyType': 'IND', + 'partyRole': 'EXPR', + 'individualDetails': { + 'title': null, + 'firstName': 'John', + 'lastName': 'Doe', + 'preferredHearingChannel': 'INTER', + 'interpreterLanguage': null, + 'reasonableAdjustments': [], + 'vulnerableFlag': false, + 'vulnerabilityDetails': null, + 'hearingChannelEmail': [ + 'john@doemail.com' + ], + 'hearingChannelPhone': [ + '07111111111' + ], + 'relatedParties': [], + 'custodyStatus': null, + 'otherReasonableAdjustmentDetails': null + } + }, + { + 'partyID': '63247839-59e2-44', + 'partyType': 'IND', + 'partyRole': 'EXPR', + 'individualDetails': { + 'title': null, + 'firstName': 'John', + 'lastName': 'Doe', + 'preferredHearingChannel': 'INTER', + 'interpreterLanguage': null, + 'reasonableAdjustments': [], + 'vulnerableFlag': false, + 'vulnerabilityDetails': null, + 'hearingChannelEmail': [ + 'test@email.com' + ], + 'hearingChannelPhone': [ + '07000111000' + ], + 'relatedParties': [], + 'custodyStatus': null, + 'otherReasonableAdjustmentDetails': null + } + } + ], + 'hearingResponse': { + 'hearingDaySchedule': [ + { + 'hearingStartDateTime': `${appendTime(hearingDate, 9, 0).toISOString()}`, + 'hearingEndDateTime': `${appendTime(hearingDate, 16, 0).toISOString()}`, + 'hearingVenueId': '739514', + 'hearingRoomId': 'Clerkenwell and Shoreditch Floating List', + 'hearingJudgeId': null, + 'panelMemberIds': null, + 'attendees': [ + { + 'hearingSubChannel': 'INTER', + 'partyID': '63247839-59e2-44' + }, + { + 'hearingSubChannel': 'INTER', + 'partyID': 'c6864175-2314-45' + }, + { + 'hearingSubChannel': 'TELCVP', + 'partyID': '0bf456e0-c680-11' + }, + { + 'hearingSubChannel': 'INTER', + 'partyID': 'd5577b58-c753-43' + }, + { + 'hearingSubChannel': 'VIDCVP', + 'partyID': 'f4aca95a-dc91-41' + }, + { + 'hearingSubChannel': null, + 'partyID': '70e0aa2c-0c2a-41' + }, + { + 'hearingSubChannel': 'INTER', + 'partyID': '03dd0269-a4b1-48' + }, + { + 'hearingSubChannel': null, + 'partyID': 'B04IXE4' + }, + { + 'hearingSubChannel': null, + 'partyID': 'DAWY9LJ' + } + ], + 'listAssistSessionID': null + } + ], + 'laCaseStatus': 'LISTED', + 'listingStatus': 'FIXED', + 'receivedDateTime': `${today.toISOString()}`, + 'requestVersion': 1 + } + }; +}; + +module.exports = { + listedHearing +}; diff --git a/e2e/api/wiremock/requests/hearings.js b/e2e/api/wiremock/requests/hearings.js new file mode 100644 index 0000000000..81e38ac3ce --- /dev/null +++ b/e2e/api/wiremock/requests/hearings.js @@ -0,0 +1,76 @@ +const hearingStubRequestBody = (hearing, hearingId) => ({ + request: { + method: 'GET', + url: `/hearing/${hearingId}` + }, + response: { + status: 200, + body: `${JSON.stringify(hearing)}`, + headers: { + 'Content-Type': 'application/json' + } + } +}); + +const unnotifiedHearingStubRequestBody = (hearingIds) => ( + { + request: { + method: 'GET', + urlPathPattern: '/unNotifiedHearings/.*' + }, + response: { + status: 200, + headers: { + 'Content-Type': 'application/json' + }, + body: `${JSON.stringify( + { + totalFound: hearingIds.length, + hearingIds: hearingIds + } + )}`, + } + } + +); + +const getpartiesNotifiedStubRequestBody = () => { + return { + request: { + method: 'GET', + urlPathPattern: '/partiesNotified/.*' + }, + response: { + status: 200, + headers: { + 'Content-Type': 'application/json' + }, + body: `${JSON.stringify({ + hearingID: '', + responses: [] + })}` + } + }; +}; + +const putPartiesNotifiedStubRequestBody = () => { + return { + 'request': { + 'method': 'PUT', + 'urlPathPattern': '/partiesNotified/.*' + }, + 'response': { + 'status': 200, + 'headers': { + 'Content-Type': 'application/json' + } + } + }; +}; + +module.exports = { + hearingStubRequestBody, + unnotifiedHearingStubRequestBody, + getpartiesNotifiedStubRequestBody, + putPartiesNotifiedStubRequestBody +}; diff --git a/e2e/api/wiremock/wiremock.js b/e2e/api/wiremock/wiremock.js new file mode 100644 index 0000000000..2593ac21c7 --- /dev/null +++ b/e2e/api/wiremock/wiremock.js @@ -0,0 +1,94 @@ +const restHelper = require('../restHelper'); +const {url} = require('../../config'); + +const wireMockUrl = `${url.wiremockService}/__admin/mappings`; +const headers = { + 'Content-Type': 'application/json' +}; + +const getStubs = async () => { + return restHelper.request( + wireMockUrl, null, null, 'GET', 200) + .then(async response => { + const content = await response.json(); + return content.mappings; + }); +}; + +const getStubUrl = ({request}) => request.url || request.urlPath || request.urlPathPattern; + +const getStub = async (stubUrl) => { + const allStubs = await getStubs(); + return allStubs.find(stub => getStubUrl(stub) == stubUrl); +}; + +const sameStub = (stub1, stub2) => { + return stub1.request.method === stub2.request.method && getStubUrl(stub1) === getStubUrl(stub2); +}; + +const getStubByRequest = async (request) => { + const allStubs = await getStubs(); + return allStubs.find(stub => sameStub(stub, {request})); +}; + +const getStubByRequestUrl = async (stubRequestUrl) => { + const targetStub = await getStub(stubRequestUrl); + if (targetStub == null) { + console.log(`Could not locate stub for: ${stubRequestUrl} request url`); + } + return targetStub; +}; + +const updateStubById = async (stubId, mappingContent) => { + return restHelper.request( + `${wireMockUrl}/${stubId}`, headers, mappingContent, 'PUT', 200) + .then(response => { + response.json(); + }); +}; +const createStub = async (mappingContent) => { + return restHelper.request( + `${wireMockUrl}`, {}, mappingContent, 'POST'); +}; + +const createUpdateStub = async (mappingContent) => { + const existingStub = await getStubByRequest(mappingContent.request); + return existingStub ? + await updateStubById(existingStub.id, mappingContent) + : await createStub(mappingContent); +}; + +const updateStubResponseFileByRequestUrl = async (stubRequestUrl, bodyFileName) => { + return getStubByRequestUrl(stubRequestUrl) + .then(stub => updateStubById(stub.id, { + ...stub, + response: { + ...stub.response, + bodyFileName + } + }) + ); +}; + +const updateStubResponseByRequestUrl = async (stubRequestUrl, responseContent) => { + return getStubByRequestUrl(stubRequestUrl) + .then(stub => updateStubById(stub.id, { + ...stub, + response: { + ...stub.response, + bodyFileName: null, + body: responseContent + } + }) + ); +}; + +module.exports = { + getStubs, + createStub, + createUpdateStub, + getStubByRequestUrl, + updateStubById, + updateStubResponseFileByRequestUrl, + updateStubResponseByRequestUrl +}; diff --git a/e2e/config.js b/e2e/config.js index 1c542fc740..5a5e561b23 100644 --- a/e2e/config.js +++ b/e2e/config.js @@ -47,8 +47,8 @@ module.exports = { caseAssignmentService: process.env.AAC_API_URL || 'http://localhost:4454', orchestratorService: process.env.CIVIL_ORCHESTRATOR_SERVICE_URL || 'https://localhost:9090', paymentApi: process.env.PAYMENT_API_URL || 'http://payment-api-aat.service.core-compute-aat.internal', - wiremockService: 'http://localhost:8765' - }, + wiremockService: process.env.WIREMOCK_URL || 'http://localhost:8765' + }, s2s: { microservice: 'civil_service', secret: process.env.S2S_SECRET || 'AABBCCDDEEFFGGHH' diff --git a/e2e/fixtures/camundaProcesses.js b/e2e/fixtures/camundaProcesses.js new file mode 100644 index 0000000000..a2ba0a0221 --- /dev/null +++ b/e2e/fixtures/camundaProcesses.js @@ -0,0 +1,5 @@ +module.exports = { + AUTOMATED_HEARING_NOTICE: 'NOTIFY_HEARING_PARTIES', + UNSPEC_AUTOMATED_HEARING_NOTICE_SCHEDULER: 'UnspecAutomatedHearingNoticeScheduler', + SPEC_AUTOMATED_HEARING_NOTICE_SCHEDULER: 'SpecAutomatedHearingNoticeScheduler' +}; diff --git a/e2e/helpers/activeOrganisationUsers.js b/e2e/helpers/activeOrganisationUsers.js index 545cdad70f..b92d695bf1 100644 --- a/e2e/helpers/activeOrganisationUsers.js +++ b/e2e/helpers/activeOrganisationUsers.js @@ -1,4 +1,4 @@ -const {updateStubResponseFileByRequestUrl} = require('../api/wiremock'); +const {updateStubResponseFileByRequestUrl} = require('../api/wiremock/wiremock'); const activeOrganisationUsersRequestUrl = '/refdata/external/v1/organisations/users'; diff --git a/e2e/tests/api_tests/automated_hearing_notice/hearing_notice_scheduler_test.js b/e2e/tests/api_tests/automated_hearing_notice/hearing_notice_scheduler_test.js new file mode 100644 index 0000000000..f47ce9f295 --- /dev/null +++ b/e2e/tests/api_tests/automated_hearing_notice/hearing_notice_scheduler_test.js @@ -0,0 +1,63 @@ +const config = require('../../../config'); + +Feature('Automated hearing notice schedulers @api-nonprod @AHN'); + +const judgeUser = config.testEarlyAdopterCourts ? config.judgeUser2WithRegionId2 : config.judgeUserWithRegionId1; + +let caseId; + +BeforeSuite(async ({hearings}) => { + await hearings.setupStaticMocks(); +}); + +Scenario('Create Unspec claim with sdo', async ({api}) => { + await api.createClaimWithRepresentedRespondent(config.applicantSolicitorUser, 'ONE_V_ONE', '11000'); + caseId = await api.getCaseId(); + await api.amendClaimDocuments(config.applicantSolicitorUser); + await api.notifyClaim(config.applicantSolicitorUser); + await api.notifyClaimDetails(config.applicantSolicitorUser); + await api.defendantResponse(config.defendantSolicitorUser, 'ONE_V_ONE', null, 'FAST_CLAIM'); + await api.claimantResponse(config.applicantSolicitorUser, 'ONE_V_ONE', 'AWAITING_APPLICANT_INTENTION', 'FOR_SDO', 'FAST_CLAIM'); + await api.createSDO(judgeUser, 'CREATE_FAST'); +}).retry(3); + +Scenario('Generate Unspec Disposal hearing notice', async ({hearings}) => { + const hearingId = await hearings.createUnspecDisposalHearing(caseId); + await hearings.triggerUnspecAutomatedHearingNoticeScheduler(hearingId); +}).retry(3); + +Scenario('Generate Unspec Trial hearing notice', async ({hearings}) => { + const hearingId = await hearings.createUnspecTrialHearing(caseId); + await hearings.triggerUnspecAutomatedHearingNoticeScheduler(hearingId); +}).retry(3); + +Scenario('Generate Unspec Dispute Resolution hearing notice', async ({hearings}) => { + const hearingId = await hearings.createUnspecDisputeResolutionHearing(caseId); + await hearings.triggerUnspecAutomatedHearingNoticeScheduler(hearingId); +}).retry(3); + +Scenario('Create Spec claim with SDO', async ({api_spec_small}) => { + await api_spec_small.createClaimWithRepresentedRespondent(config.applicantSolicitorUser, 'ONE_V_ONE', false, false); + await api_spec_small.defendantResponse(config.defendantSolicitorUser, 'FULL_DEFENCE'); + await api_spec_small.claimantResponse(config.applicantSolicitorUser, true, 'No', false); + await api_spec_small.createSDO(config.judgeUser2WithRegionId4, 'CREATE_SMALL', true); +}).retry(3); + +Scenario('Generate Spec Disposal hearing notice', async ({hearings}) => { + const hearingId = await hearings.createSpecDisposalHearing(caseId); + await hearings.triggerSpecAutomatedHearingNoticeScheduler(hearingId); +}).retry(3); + +Scenario('Generate Spec Trial hearing notice', async ({hearings}) => { + const hearingId = await hearings.createSpecTrialHearing(caseId); + await hearings.triggerSpecAutomatedHearingNoticeScheduler(hearingId); +}).retry(3); + +Scenario('Generate Spec Dispute Resolution hearing notice', async ({hearings}) => { + const hearingId = await hearings.createSpecDisputeResolutionHearing(caseId); + await hearings.triggerSpecAutomatedHearingNoticeScheduler(hearingId); +}).retry(3); + +AfterSuite(async ({api}) => { + await api.cleanUp(); +}); diff --git a/e2e/tests/ui_tests/damages/1v2CreateClaim_DiffSol_fast_track_test.js b/e2e/tests/ui_tests/damages/1v2CreateClaim_DiffSol_fast_track_test.js index 7fa2fe2fed..121432de28 100644 --- a/e2e/tests/ui_tests/damages/1v2CreateClaim_DiffSol_fast_track_test.js +++ b/e2e/tests/ui_tests/damages/1v2CreateClaim_DiffSol_fast_track_test.js @@ -143,7 +143,7 @@ Scenario('Create a Hearing Request', async ({I}) => { } }).retry(3); -Scenario.skip('Transfer online case', async ({I}) => { +Scenario('Transfer online case', async ({I}) => { await I.login(config.hearingCenterAdminWithRegionId2); await I.transferOnlineCase(); }).retry(3); diff --git a/package.json b/package.json index eca53b9fd5..63c7e000f6 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "test:api-mediation": "MOCHAWESOME_REPORTFILENAME=api-mediation npx codeceptjs run-workers --suites 4 --grep @api-spec-mediation --reporter mocha-multi --verbose", "test:api-multi-intermediate-spec": "MOCHAWESOME_REPORTFILENAME=api-multi-intermediate-spec npx codeceptjs run-workers --suites 4 --grep @api-spec-multi-intermediate --reporter mocha-multi --verbose", "test:api-multi-intermediate-unspec": "MOCHAWESOME_REPORTFILENAME=api-multi-intermediate-unspec npx codeceptjs run-workers --suites 4 --grep @api-unspec-multi-intermediate --reporter mocha-multi --verbose", + "test:AHN": "MOCHAWESOME_REPORTFILENAME=automated-hearing-notice-scheduler npx codeceptjs run --grep '@AHN' --reporter mocha-multi --verbose", "prepare": "husky install" }, "license": "MIT",