diff --git a/application/CohortManager/.env.example b/application/CohortManager/.env.example index bcb23ac58d..a0b061c6b1 100644 --- a/application/CohortManager/.env.example +++ b/application/CohortManager/.env.example @@ -18,6 +18,7 @@ CAASFOLDER_STORAGE_CONNECTION_STRING="" # Enter the connection string for azurit CONTAINER_NAME="" # Name of the container to be used in the test. Example: "inbound". E2E_TEST_FILES_PATH="" # Path to the end-to-end test files directory. Example: "e2e/testFiles". API_TEST_FILES_PATH="" # Path to the api test files directory. Example: "api/testFiles". +WIREMOCK_URL=http://localhost:8080/__admin/requests # Data Service Endpoints to access the APIs built on top of the Entity Framework # For Local Development & testing, make sure these are mapped using ports option in compose.data-services.yaml diff --git a/application/CohortManager/Set-up/wiremock/mappings/servicenow_authentication.json b/application/CohortManager/Set-up/wiremock/mappings/servicenow_authentication.json new file mode 100644 index 0000000000..07757e28e7 --- /dev/null +++ b/application/CohortManager/Set-up/wiremock/mappings/servicenow_authentication.json @@ -0,0 +1,30 @@ +{ + "request": { + "urlPath": "/oauth_token.do", + "method": "POST", + "formParameters": { + "grant_type": { + "equalTo": "refresh_token" + }, + "client_id": { + "equalTo": "MockClientId-123" + }, + "client_secret": { + "equalTo": "MockClientSecret-123" + }, + "refresh_token": { + "equalTo": "MockRefreshToken-123" + } + } + }, + "response": { + "jsonBody": { + "access_token": "MockAccessToken-123", + "refresh_token": "MockRefreshToken-123", + "scope": "IntegrationStationAll", + "token_type": "Bearer", + "expires_in": 1800 + }, + "status": 200 + } +} diff --git a/application/CohortManager/Set-up/wiremock/mappings/servicenow_resolution.json b/application/CohortManager/Set-up/wiremock/mappings/servicenow_resolution.json new file mode 100644 index 0000000000..de72b07041 --- /dev/null +++ b/application/CohortManager/Set-up/wiremock/mappings/servicenow_resolution.json @@ -0,0 +1,25 @@ +{ + "request": { + "urlPathPattern": "^/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseResolution/.+$", + "method": "PUT", + "headers": { + "Authorization": { + "equalTo": "Bearer MockAccessToken-123" + } + }, + "bodyPatterns": [ + { + "matchesJsonPath": "$[?(@.state == 6)]" + }, + { + "matchesJsonPath": "$[?(@.resolution_code == '28')]" + }, + { + "matchesJsonPath": "$.close_notes" + } + ] + }, + "response": { + "status": 200 + } +} diff --git a/application/CohortManager/Set-up/wiremock/mappings/servicenow_update.json b/application/CohortManager/Set-up/wiremock/mappings/servicenow_update.json new file mode 100644 index 0000000000..81478f7761 --- /dev/null +++ b/application/CohortManager/Set-up/wiremock/mappings/servicenow_update.json @@ -0,0 +1,22 @@ +{ + "request": { + "urlPathPattern": "^/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseUpdate/.+$", + "method": "PUT", + "headers": { + "Authorization": { + "equalTo": "Bearer MockAccessToken-123" + } + }, + "bodyPatterns": [ + { + "matchesJsonPath": "$[?(@.state == 10)]" + }, + { + "matchesJsonPath": "$.work_notes" + } + ] + }, + "response": { + "status": 200 + } +} diff --git a/application/CohortManager/compose.core.yaml b/application/CohortManager/compose.core.yaml index 600ca5bc31..3b317604c6 100644 --- a/application/CohortManager/compose.core.yaml +++ b/application/CohortManager/compose.core.yaml @@ -320,13 +320,13 @@ services: profiles: [service-now] environment: - ASPNETCORE_URLS=http://*:9092 - - ServiceNowRefreshAccessTokenUrl=https://nhsdigitaldev.service-now.com/oauth_token.do - - ServiceNowUpdateUrl=https://nhsdigitaldev.service-now.com/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseUpdate - - ServiceNowResolutionUrl=https://nhsdigitaldev.service-now.com/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseResolution + - ServiceNowRefreshAccessTokenUrl=http://wiremock:8080/oauth_token.do + - ServiceNowUpdateUrl=http://wiremock:8080/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseUpdate + - ServiceNowResolutionUrl=http://wiremock:8080/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseResolution - ServiceNowGrantType=refresh_token - - ServiceNowClientId=${SERVICENOW_CLIENT_ID} - - ServiceNowClientSecret=${SERVICENOW_CLIENT_SECRET} - - ServiceNowRefreshToken=${SERVICENOW_REFRESH_TOKEN} + - ServiceNowClientId=MockClientId-123 + - ServiceNowClientSecret=MockClientSecret-123 + - ServiceNowRefreshToken=MockRefreshToken-123 - ServiceNowParticipantManagementTopic=servicenow-participant-management-topic - ServiceBusConnectionString_client_internal=Endpoint=sb://service-bus;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true; ports: diff --git a/application/CohortManager/compose.deps.yaml b/application/CohortManager/compose.deps.yaml index a13b913eac..5fef32c4c9 100644 --- a/application/CohortManager/compose.deps.yaml +++ b/application/CohortManager/compose.deps.yaml @@ -72,6 +72,16 @@ services: - SYS_PTRACE restart: "no" + wiremock: + container_name: wiremock + networks: [cohman-network] + image: wiremock/wiremock + ports: + - "8080:8080" + volumes: + - ./Set-up/wiremock/mappings:/home/wiremock/mappings + command: --verbose --root-dir /home/wiremock + networks: cohman-network: name: cohman-network diff --git a/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9998106524.json b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9998106524.json new file mode 100644 index 0000000000..5a2fc002ef --- /dev/null +++ b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9998106524.json @@ -0,0 +1,390 @@ +{ + "resourceType": "Patient", + "id": "9998106524", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9998106524", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSNumberVerificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-NHSNumberVerificationStatus", + "version": "1.0.0", + "code": "01", + "display": "Number present and verified" + } + ] + } + } + ] + } + ], + "meta": { + "versionId": "2", + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality", + "code": "U", + "display": "unrestricted" + } + ] + }, + "name": [ + { + "id": "123", + "use": "usual", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "given": [ + "Jane" + ], + "family": "Smith", + "prefix": [ + "Mrs" + ] + } + ], + "gender": "female", + "birthDate": "1980-10-22", + "multipleBirthInteger": 1, + "deceasedDateTime": "2010-10-22T00:00:00+00:00", + "generalPractitioner": [ + { + "id": "254406A3", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + } + ], + "managingOrganization": { + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + }, + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NominatedPharmacy", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-PreferredDispenserOrganization", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y23456" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-MedicalApplianceSupplier", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y34567" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-DeathNotificationStatus", + "extension": [ + { + "url": "deathNotificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-DeathNotificationStatus", + "version": "1.0.0", + "code": "2", + "display": "Formal - death notice received from Registrar of Deaths" + } + ] + } + }, + { + "url": "systemEffectiveDate", + "valueDateTime": "2010-10-22T00:00:00+00:00" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSCommunication", + "extension": [ + { + "url": "language", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-HumanLanguage", + "version": "1.0.0", + "code": "fr", + "display": "French" + } + ] + } + }, + { + "url": "interpreterRequired", + "valueBoolean": true + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-ContactPreference", + "extension": [ + { + "url": "PreferredWrittenCommunicationFormat", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredWrittenCommunicationFormat", + "code": "12", + "display": "Braille" + } + ] + } + }, + { + "url": "PreferredContactMethod", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredContactMethod", + "code": "1", + "display": "Letter" + } + ] + } + }, + { + "url": "PreferredContactTimes", + "valueString": "Not after 7pm" + } + ] + }, + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace", + "valueAddress": { + "city": "Manchester", + "district": "Greater Manchester", + "country": "GBR" + } + }, + { + "url": "https://fhir.nhs.uk/StructureDefinition/Extension-PDS-RemovalFromRegistration", + "extension": [ + { + "url": "removalFromRegistrationCode", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/PDS-RemovalReasonExitCode", + "code": "SCT", + "display": "Transferred to Scotland" + } + ] + } + }, + { + "url": "effectiveTime", + "valuePeriod": { + "start": "2020-01-01T00:00:00+00:00", + "end": "2021-12-31T00:00:00+00:00" + } + } + ] + } + ], + "telecom": [ + { + "id": "789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "phone", + "value": "01632960587", + "use": "home" + }, + { + "id": "790", + "period": { + "start": "2019-01-01", + "end": "2022-12-31" + }, + "system": "email", + "value": "jane.smith@example.com", + "use": "home" + }, + { + "id": "OC789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "other", + "value": "01632960587", + "use": "home", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-OtherContactSystem", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-OtherContactSystem", + "code": "textphone", + "display": "Minicom (Textphone)" + } + } + ] + } + ], + "contact": [ + { + "id": "C123", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "C", + "display": "Emergency Contact" + } + ] + } + ], + "telecom": [ + { + "system": "phone", + "value": "01632960587" + } + ] + } + ], + "address": [ + { + "id": "456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "home", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + }, + { + "id": "T456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "temp", + "text": "Student Accommodation", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + } + ] +} diff --git a/tests/playwright-tests/src/config/env.ts b/tests/playwright-tests/src/config/env.ts index c3a48d239d..ad27977c41 100644 --- a/tests/playwright-tests/src/config/env.ts +++ b/tests/playwright-tests/src/config/env.ts @@ -22,7 +22,8 @@ const endpointSerNowReceiveParticipant = process.env.ENDPOINT_SERVICE_NOW_MESSAG const invalidEndpointSerNow = process.env.INVALID_ENDPOINT_SERVICE_NOW_MESSAGE_HANDLER ?? ''; const participantPayloadPath = process.env.PARTICIPANT_PAYLOAD_PATH ?? ''; const createPDSDemographicEnv = process.env.ENDPOINT_PDS_DEMOGRAPHIC ?? ''; -const subToNemsEndPoint = process.env.ENDPOINT_SUB_TO_NEMS ?? '' +const subToNemsEndPoint = process.env.ENDPOINT_SUB_TO_NEMS ?? ''; +const wireMockUrl = process.env.WIREMOCK_URL ?? ''; export const config = { baseURL, @@ -41,6 +42,7 @@ export const config = { createPDSDemographic: createPDSDemographicEnv, invalidEndpointSerNow: invalidEndpointSerNow, SubToNems: subToNemsEndPoint, + wireMockUrl: wireMockUrl, SubToNemsPath: 'api/Subscribe', routeBsSelectRetrieveCohortDistributionData: 'api/RetrieveCohortDistributionData', routeBsSelectRetrieveCohortRequestAudit: 'api/RetrieveCohortRequestAudit', diff --git a/tests/playwright-tests/src/interface/InputData.ts b/tests/playwright-tests/src/interface/InputData.ts index d919bfc4ac..464356902a 100644 --- a/tests/playwright-tests/src/interface/InputData.ts +++ b/tests/playwright-tests/src/interface/InputData.ts @@ -7,7 +7,6 @@ interface Validation { RuleId: number; RuleDescription: string; ExceptionFlag: number; - } interface Validations { @@ -20,8 +19,18 @@ interface QueryParams { exceptionCategory: number; } +interface ServiceNowRequestValidation { + caseNumber: string; + messageType: 1|2|3; +} + +export interface ServiceNowRequestValidations { + validation: ServiceNowRequestValidation +} + export interface InputData { validations: Validations[]; + serviceNowRequestValidations: ServiceNowRequestValidations[]; inputParticipantRecord: Record; nhsNumbers: string[]; queryParams: QueryParams; diff --git a/tests/playwright-tests/src/interface/wiremock.ts b/tests/playwright-tests/src/interface/wiremock.ts new file mode 100644 index 0000000000..d8fcebcafb --- /dev/null +++ b/tests/playwright-tests/src/interface/wiremock.ts @@ -0,0 +1,12 @@ +interface WireMockRequestDetails { + url: string; + body: string; +} + +interface WireMockRequest { + request: WireMockRequestDetails; +} + +export interface WireMockResponse { + requests: WireMockRequest[]; +} diff --git a/tests/playwright-tests/src/tests/e2e/epic4c-add-participant-tests/epic4c-testsuite-migrated.ts b/tests/playwright-tests/src/tests/e2e/epic4c-add-participant-tests/epic4c-testsuite-migrated.ts index bb9d1b191f..80de5f9b0d 100644 --- a/tests/playwright-tests/src/tests/e2e/epic4c-add-participant-tests/epic4c-testsuite-migrated.ts +++ b/tests/playwright-tests/src/tests/e2e/epic4c-add-participant-tests/epic4c-testsuite-migrated.ts @@ -30,6 +30,6 @@ export const runnerBasedEpic4cTestScenariosAdd = "@DTOSS-9337-01"; export const runnerBasedEpic4cTestScenariosAmend = "@DTOSS-9337-01"; // export const runnerBasedEpic4cTestScenariosManualAdd = ""; -export const runnerBasedEpic4cTestScenariosManualAdd = "@DTOSS-3883-01|@DTOSS-8484-01|@DTOSS-9614-01|@DTOSS-8375-01"; +export const runnerBasedEpic4cTestScenariosManualAdd = "@DTOSS-3883-01|@DTOSS-8484-01|@DTOSS-9614-01|@DTOSS-8375-01|@DTOSS-3884-01"; export const runnerBasedEpic4cTestScenariosManualAmend = "@DTOSS-8483-01|@DTOSS-9614-01"; //export const runnerBasedEpic4cTestScenariosManualAmend = ""; diff --git a/tests/playwright-tests/src/tests/e2e/testFiles/@DTOSS-3884-01/ADDMANUAL1_BREAST_SCREENING_COHORT.json b/tests/playwright-tests/src/tests/e2e/testFiles/@DTOSS-3884-01/ADDMANUAL1_BREAST_SCREENING_COHORT.json new file mode 100644 index 0000000000..b8cc483bfe --- /dev/null +++ b/tests/playwright-tests/src/tests/e2e/testFiles/@DTOSS-3884-01/ADDMANUAL1_BREAST_SCREENING_COHORT.json @@ -0,0 +1,53 @@ +{ + "serviceNowRequestValidations": [ + { + "validation": { + "caseNumber": "CS388402", + "messageType": 1 + }, + "meta": { + "testJiraId": "@DTOSS-3884-02", + "requirementJiraId": "@DTOSS-3884-02", + "additionalTags": "@DTOSS-3884-02 @e2e @epic4c- NHS Number not found in PDS, message type 1 is sent to ServiceNow" + } + }, + { + "validation": { + "caseNumber": "CS388403", + "messageType": 1 + }, + "meta": { + "testJiraId": "@DTOSS-3884-03", + "requirementJiraId": "@DTOSS-3884-03", + "additionalTags": "@DTOSS-3884-03 @e2e @epic4c- NHS Number from PDS does not match, message type 1 is sent to ServiceNow" + } + } + ], + "inputParticipantRecord": [ + { + "number": "CS388402", + "u_case_variable_data": { + "nhs_number": "9990048622", + "forename_": "Jane", + "surname_family_name": "Doe", + "date_of_birth": "2010-10-22", + "enter_dummy_gp_code": "ZZZDKL", + "BSO_code": "NORTH NOTTINGHAMSHIRE BREAST SCREENING OFFICE", + "reason_for_adding": "requires_ceasing_following_surgery_bilateral_mastectomy" + } + }, + { + "number": "CS388403", + "u_case_variable_data": { + "nhs_number": "9998106524", + "forename_": "Jane", + "surname_family_name": "Doe", + "date_of_birth": "2010-10-22", + "enter_dummy_gp_code": "ZZZDKL", + "BSO_code": "NORTH NOTTINGHAMSHIRE BREAST SCREENING OFFICE", + "reason_for_adding": "requires_ceasing_following_surgery_bilateral_mastectomy" + } + } + ], + "nhsNumbers": [] +} diff --git a/tests/playwright-tests/src/tests/runner/runner-workflow-manual-add.spec.ts b/tests/playwright-tests/src/tests/runner/runner-workflow-manual-add.spec.ts index 426e9280d9..e8af5c4137 100644 --- a/tests/playwright-tests/src/tests/runner/runner-workflow-manual-add.spec.ts +++ b/tests/playwright-tests/src/tests/runner/runner-workflow-manual-add.spec.ts @@ -1,9 +1,8 @@ import { test, request as playwrightRequest, APIRequestContext } from '@playwright/test' -import { cleanupDatabaseFromAPI, getConsolidatedAllTestData, processFileViaStorage, sendParticipantViaSnowAPI, validateSqlDatabaseFromAPI } from '../steps/steps'; +import { cleanupDatabaseFromAPI, cleanupWireMock, getConsolidatedAllTestData, processFileViaStorage, sendParticipantViaSnowAPI, validateServiceNowRequestWithMockServer, validateSqlDatabaseFromAPI } from '../steps/steps'; import { generateDynamicDateMap, replaceDynamicDatesInJson } from '../../../src/json/json-updater'; import { createParquetFromJson } from '../../parquet/parquet-multiplier'; import { receiveParticipantViaServiceNow, invalidServiceNowEndpoint } from '../../api/distributionService/bsSelectService'; - import { runnerBasedEpic4cTestScenariosManualAdd } from '../e2e/epic4c-add-participant-tests/epic4c-testsuite-migrated'; import { ParticipantRecord } from '../../interface/InputData'; @@ -27,7 +26,6 @@ test.beforeAll(async () => { console.log(`Running ${TEST_TYPE} tests with scenario tags: ${scopedTestScenario}`); await cleanupDatabaseFromAPI(apiContext, addData.nhsNumbers); - const dateMap = generateDynamicDateMap(); const updatedParticipantRecords = replaceDynamicDatesInJson(addData.inputParticipantRecords, dateMap); await Promise.all( @@ -38,6 +36,7 @@ test.beforeAll(async () => { }); test.afterAll(async () => { + await cleanupWireMock(apiContext); await apiContext.dispose(); }); @@ -53,3 +52,16 @@ addData.validations.forEach((validations) => { await validateSqlDatabaseFromAPI(request, [validations]); }); }); + +console.log('Number of ServiceNow request validations:', addData.serviceNowRequestValidations?.length) + +addData.serviceNowRequestValidations.forEach((validations) => { + test(`${validations.meta?.testJiraId} ${validations.meta?.additionalTags}`, { + annotation: [ + { type: 'TestId', description: validations.meta?.testJiraId ?? '' }, + { type: 'RequirementId', description: validations.meta?.requirementJiraId ?? '' } + ], + }, async ({ request }) => { + await validateServiceNowRequestWithMockServer(request, [validations]); + }); +}); diff --git a/tests/playwright-tests/src/tests/runner/runner-workflow-manual-amend.spec.ts b/tests/playwright-tests/src/tests/runner/runner-workflow-manual-amend.spec.ts index 941ccddbca..18f6c4ceb7 100644 --- a/tests/playwright-tests/src/tests/runner/runner-workflow-manual-amend.spec.ts +++ b/tests/playwright-tests/src/tests/runner/runner-workflow-manual-amend.spec.ts @@ -1,5 +1,5 @@ import { test, request as playwrightRequest, APIRequestContext } from '@playwright/test' -import { cleanupDatabaseFromAPI, getConsolidatedAllTestData, processFileViaStorage, sendParticipantViaSnowAPI, validateSqlDatabaseFromAPI } from '../steps/steps'; +import { cleanupDatabaseFromAPI, cleanupWireMock, getConsolidatedAllTestData, processFileViaStorage, sendParticipantViaSnowAPI, validateServiceNowRequestWithMockServer, validateSqlDatabaseFromAPI } from '../steps/steps'; import { generateDynamicDateMap, replaceDynamicDatesInJson } from '../../json/json-updater'; import { createParquetFromJson } from '../../parquet/parquet-multiplier'; import { runnerBasedEpic4cTestScenariosManualAmend } from '../e2e/epic4c-add-participant-tests/epic4c-testsuite-migrated'; @@ -46,6 +46,7 @@ test.beforeAll(async () => { }); test.afterAll(async () => { + await cleanupWireMock(apiContext); await apiContext.dispose(); }); @@ -61,3 +62,16 @@ amendData.validations.forEach((validations) => { await validateSqlDatabaseFromAPI(request, [validations]); }); }); + +console.log('Number of ServiceNow request validations:', amendData.serviceNowRequestValidations?.length) + +amendData.serviceNowRequestValidations.forEach((validations) => { + test(`${validations.meta?.testJiraId} ${validations.meta?.additionalTags}`, { + annotation: [ + { type: 'TestId', description: validations.meta?.testJiraId ?? '' }, + { type: 'RequirementId', description: validations.meta?.requirementJiraId ?? '' } + ], + }, async ({ request }) => { + await validateServiceNowRequestWithMockServer(request, [validations]); + }); +}); diff --git a/tests/playwright-tests/src/tests/steps/steps.ts b/tests/playwright-tests/src/tests/steps/steps.ts index fca08b0372..cf623b5ca1 100644 --- a/tests/playwright-tests/src/tests/steps/steps.ts +++ b/tests/playwright-tests/src/tests/steps/steps.ts @@ -1,6 +1,6 @@ import { test, APIRequestContext, expect } from "@playwright/test"; import { checkBlobExists, uploadToLocalStorage } from "../../storage/azureStorage"; -import { InputData, ParticipantRecord } from "../../interface/InputData"; +import { InputData, ParticipantRecord, ServiceNowRequestValidations } from "../../interface/InputData"; import { config } from "../../config/env"; import * as fs from 'fs'; import path from "path"; @@ -8,6 +8,7 @@ import { validateApiResponse } from "../../api/apiHelper"; import { cleanDataBaseUsingServices } from "../../api/dataService/dataServiceCleaner"; import { ensureNhsNumbersStartWith999 } from "../fixtures/testDataHelper"; import { receiveParticipantViaServiceNow } from "../../api/distributionService/bsSelectService"; +import { WireMockResponse } from "../../interface/wiremock"; export async function cleanupDatabaseFromAPI(request: APIRequestContext, numbers: string[]) { @@ -16,6 +17,30 @@ export async function cleanupDatabaseFromAPI(request: APIRequestContext, numbers }); } +function getWireMockUrl(): string { + const wireMockUrl = config.wireMockUrl; + + if (wireMockUrl.length === 0) + { + throw new Error(`❌ WIREMOCK_URL environment variable is empty`); + } + + return wireMockUrl; +} + +export async function cleanupWireMock(request: APIRequestContext) { + const wireMockUrl = getWireMockUrl(); + + return test.step(`Cleaning up WireMock`, async () => { + try { + await request.delete(wireMockUrl); + } + catch { + console.warn(`Failed to clean up WireMock requests. Is the WireMock server running? URL: ${wireMockUrl}`); + } + }); +} + export async function validateSqlDatabaseFromAPI(request: APIRequestContext, validations: any) { return test.step(`Validate database for assertions`, async () => { const { status, errorTrace } = await validateApiResponse(validations, request); @@ -25,6 +50,46 @@ export async function validateSqlDatabaseFromAPI(request: APIRequestContext, val }); } +export async function validateServiceNowRequestWithMockServer(request: APIRequestContext, validations: ServiceNowRequestValidations[]) { + const wireMockUrl = getWireMockUrl(); + + var response = await request.get(wireMockUrl); + var body = await response.json() as WireMockResponse; + + return test.step(`Validate ServiceNow Requests with WireMock`, async () => { + validations.forEach(validation => { + const { caseNumber, messageType } = validation.validation; + + var request = body.requests.find(request => request.request.url.endsWith(caseNumber)); + + if (!request) + { + throw new Error(`❌ Validation failed, request not found for: ${caseNumber}`); + } + + console.info(`🚧 Validating ServiceNow Message Type ${messageType} was sent for ${caseNumber}`); + + switch (messageType) { + case 1: + expect(request.request.url == `/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseUpdate/${caseNumber}`).toBeTruthy(); + expect(JSON.parse(request.request.body)['needs_attention'] == true).toBeTruthy(); + break; + case 2: + expect(request.request.url == `/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseUpdate/${caseNumber}`).toBeTruthy(); + expect(JSON.parse(request.request.body)['needs_attention'] == false).toBeTruthy(); + break; + case 3: + expect(request.request.url == `/api/x_nhsd_intstation/nhs_integration/9c78f87c97912e10dd80f2df9153aff5/CohortCaseResolution/${caseNumber}`).toBeTruthy(); + break; + default: + throw new Error(`❌ Validation failed, unexpected message type: ${messageType}`); + } + + console.info(`✅ Validation Complete - ServiceNow Message Type ${messageType} request was sent for ${caseNumber}`); + }); + }); +} + export async function processFileViaStorage(parquetFilePath: string) { return test.step(`Process file via Storage`, async () => { await uploadToLocalStorage(parquetFilePath); @@ -37,8 +102,6 @@ export async function sendParticipantViaSnowAPI(request: APIRequestContext, return test.step(`Process file via SnowAPI`, async () => { await receiveParticipantViaServiceNow(request,payload); }); - - } export async function getTestData(scenarioFolderName: string @@ -97,6 +160,7 @@ export function getConsolidatedAllTestData( let allValidations: any[] = []; let allInputParticipantRecords: any[] = []; let allNhsNumbers: any[] = []; + let allServiceNowRequestValidations: any[] = []; scenarioFolders.forEach(folder => { try { @@ -106,7 +170,8 @@ export function getConsolidatedAllTestData( const srcPath = path.join(testFilesPath, jsonFile); try { const parsedData: InputData = JSON.parse(fs.readFileSync(srcPath, 'utf-8')); - allValidations = allValidations.concat(parsedData.validations); + allValidations = allValidations.concat(parsedData.validations).filter(element => element !== undefined); + allServiceNowRequestValidations = allServiceNowRequestValidations.concat(parsedData.serviceNowRequestValidations).filter(element => element !== undefined); allNhsNumbers = allNhsNumbers.concat(parsedData.nhsNumbers); if (Array.isArray(parsedData.inputParticipantRecord)) { allInputParticipantRecords = allInputParticipantRecords.concat(parsedData.inputParticipantRecord); @@ -126,6 +191,7 @@ export function getConsolidatedAllTestData( validations: allValidations, inputParticipantRecords: allInputParticipantRecords, nhsNumbers: allNhsNumbers, + serviceNowRequestValidations: allServiceNowRequestValidations, testFilesPath }; }