From 4b1a88356a2db339711231dc0089944f996bcb7d Mon Sep 17 00:00:00 2001 From: varsha-vanbatte-nhs Date: Wed, 24 Dec 2025 17:16:52 +0000 Subject: [PATCH 1/2] comments for merge --- .../src/helpers/create_letter_helpers.ts | 26 +-- test-results/.last-run.json | 4 + .../update-multiple-letter-status.ts | 197 ++++++++++++++++++ .../update-multiple-letter-status.spec.ts | 122 +++++++++++ tests/helpers/common-types.ts | 13 ++ .../update-multiple-status-test-cases.ts | 15 +- 6 files changed, 347 insertions(+), 30 deletions(-) create mode 100644 test-results/.last-run.json create mode 100644 tests/component-tests/apiGateway-tests/testCases/update-multiple-letter-status.ts create mode 100644 tests/component-tests/apiGateway-tests/update-multiple-letter-status.spec.ts diff --git a/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts b/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts index 062154ec..691171c0 100644 --- a/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts +++ b/scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts @@ -16,14 +16,14 @@ export async function createLetter(params: { letterRepository: LetterRepository; }) { const { - letterId, bucketName, - supplierId, - targetFilename, - specificationId, groupId, - status, + letterId, letterRepository, + specificationId, + status, + supplierId, + targetFilename, } = params; await uploadFile( @@ -39,7 +39,7 @@ export async function createLetter(params: { specificationId, groupId, url: `s3://${bucketName}/${supplierId}/${targetFilename}`, - status: status, + status, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; @@ -56,22 +56,16 @@ export function createLetterDto(params: { status: LetterStatusType; url: string; }) { - const { - letterId, - supplierId, - specificationId, - groupId, - status, - url, - } = params; + const { groupId, letterId, specificationId, status, supplierId, url } = + params; const letter: Omit = { id: letterId, supplierId, specificationId, groupId, - url: url, - status: status, + url, + status, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; diff --git a/test-results/.last-run.json b/test-results/.last-run.json new file mode 100644 index 00000000..6da63411 --- /dev/null +++ b/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "failedTests": [], + "status": "passed" +} diff --git a/tests/component-tests/apiGateway-tests/testCases/update-multiple-letter-status.ts b/tests/component-tests/apiGateway-tests/testCases/update-multiple-letter-status.ts new file mode 100644 index 00000000..f2f05b12 --- /dev/null +++ b/tests/component-tests/apiGateway-tests/testCases/update-multiple-letter-status.ts @@ -0,0 +1,197 @@ +import { RequestHeaders } from "../../../constants/request-headers"; +import { SUPPLIERID } from "../../../constants/api-constants"; +import { + ErrorMessageBody, + PostMessageRequestBody, +} from "../../../helpers/common-types"; +import { SupplierApiLetters } from "../../../helpers/generate-fetch-test-data"; + +export type PostMessageResponseBody = { + data: { + type: string; + id: string; + attributes: { + reasonCode?: string; + reasonText?: string; + status: string; + specificationId: string; + groupId?: string; + }; + }; +}; + +export function postRequestHeaders(): RequestHeaders { + let requestHeaders: RequestHeaders; + requestHeaders = { + "NHSD-Supplier-ID": SUPPLIERID, + "NHSD-Correlation-ID": "12344", + "X-Request-ID": "requestId1", + }; + return requestHeaders; +} + +export function postInvalidRequestHeaders(): RequestHeaders { + let requestHeaders: RequestHeaders; + requestHeaders = { + "NHSD-Supplier-ID": SUPPLIERID, + "NHSD-Correlation-ID": "12344", + // Request Id is missing + }; + return requestHeaders; +} + +export function postValidRequestBody( + letters: SupplierApiLetters[], +): PostMessageRequestBody { + let requestBody: PostMessageRequestBody; + + requestBody = { + data: [ + { + type: "Letter", + id: letters[0].id, + attributes: { + status: "ACCEPTED", + }, + }, + { + type: "Letter", + id: letters[1].id, + attributes: { + status: "REJECTED", + }, + }, + { + type: "Letter", + id: letters[2].id, + attributes: { + status: "PRINTED", + }, + }, + { + type: "Letter", + id: letters[3].id, + attributes: { + status: "CANCELLED", + }, + }, + ], + }; + return requestBody; +} + +export function postInvalidStatusRequestBody( + letters: SupplierApiLetters[], +): PostMessageRequestBody { + let requestBody: PostMessageRequestBody; + + requestBody = { + data: [ + { + type: "Letter", + id: letters[0].id, + attributes: { + status: "ACCEPTED", + }, + }, + { + type: "Letter", + id: letters[1].id, + attributes: { + status: "SENDING", // Invalid letter status + }, + }, + ], + }; + return requestBody; +} + +export function postDuplicateIDRequestBody( + letters: SupplierApiLetters[], +): PostMessageRequestBody { + let requestBody: PostMessageRequestBody; + + requestBody = { + data: [ + { + type: "Letter", + id: letters[0].id, + attributes: { + status: "ACCEPTED", + }, + }, + { + type: "Letter", + id: letters[0].id, // Duplicate id + attributes: { + status: "REJECTED", + }, + }, + ], + }; + return requestBody; +} + +export function postInvalidStatusResponseBody(): ErrorMessageBody { + let responseBody: ErrorMessageBody; + + responseBody = { + errors: [ + { + id: "12344", + code: "NOTIFY_INVALID_REQUEST", + links: { + about: + "https://digital.nhs.uk/developer/api-catalogue/nhs-notify-supplier", + }, + status: "400", + title: "Invalid request", + detail: "The request body is invalid", + }, + ], + }; + return responseBody; +} + +export function postDuplicateIDResponseBody(): ErrorMessageBody { + let responseBody: ErrorMessageBody; + + responseBody = { + errors: [ + { + id: "12344", + code: "NOTIFY_INVALID_REQUEST", + links: { + about: + "https://digital.nhs.uk/developer/api-catalogue/nhs-notify-supplier", + }, + status: "400", + title: "Invalid request", + detail: + "The request cannot include multiple letter objects with the same id", + }, + ], + }; + return responseBody; +} + +export function post500ErrorResponseBody(): ErrorMessageBody { + let responseBody: ErrorMessageBody; + + responseBody = { + errors: [ + { + id: "12344", + code: "NOTIFY_INTERNAL_SERVER_ERROR", + links: { + about: + "https://digital.nhs.uk/developer/api-catalogue/nhs-notify-supplier", + }, + status: "500", + title: "Internal server error", + detail: "Unexpected error", + }, + ], + }; + return responseBody; +} diff --git a/tests/component-tests/apiGateway-tests/update-multiple-letter-status.spec.ts b/tests/component-tests/apiGateway-tests/update-multiple-letter-status.spec.ts new file mode 100644 index 00000000..3ce4c277 --- /dev/null +++ b/tests/component-tests/apiGateway-tests/update-multiple-letter-status.spec.ts @@ -0,0 +1,122 @@ +import { expect, test } from "@playwright/test"; +import { SUPPLIERID, SUPPLIER_LETTERS } from "../../constants/api-constants"; +import getRestApiGatewayBaseUrl from "../../helpers/aws-gateway-helper"; +import { + post500ErrorResponseBody, + postDuplicateIDRequestBody, + postDuplicateIDResponseBody, + postInvalidRequestHeaders, + postInvalidStatusRequestBody, + postInvalidStatusResponseBody, + postRequestHeaders, + postValidRequestBody, +} from "./testCases/update-multiple-letter-status"; +import { + createTestData, + getLettersBySupplier, +} from "../../helpers/generate-fetch-test-data"; + +let baseUrl: string; + +test.beforeAll(async () => { + baseUrl = await getRestApiGatewayBaseUrl(); +}); + +test.describe("API Gateway Tests to Verify post Status Endpoint", () => { + test(`post /letters returns 202 and status is updated for multiple letters`, async ({ + request, + }) => { + await createTestData(SUPPLIERID, 4); + const letters = await getLettersBySupplier(SUPPLIERID, "PENDING", 4); + + if (!letters?.length) { + test.fail(true, `No PENDING letters found for supplier ${SUPPLIERID}`); + return; + } + + const headers = postRequestHeaders(); + const body = postValidRequestBody(letters); + + const response = await request.post(`${baseUrl}/${SUPPLIER_LETTERS}`, { + headers, + data: body, + }); + + expect(response.status()).toBe(202); + }); + + test(`Post /letters returns 400 if request has invalid status`, async ({ + request, + }) => { + await createTestData(SUPPLIERID, 2); + const letters = await getLettersBySupplier(SUPPLIERID, "PENDING", 2); + + if (!letters?.length) { + test.fail(true, `No PENDING letters found for supplier ${SUPPLIERID}`); + return; + } + + const headers = postRequestHeaders(); + const body = postInvalidStatusRequestBody(letters); + + const response = await request.post(`${baseUrl}/${SUPPLIER_LETTERS}`, { + headers, + data: body, + }); + + const responseBody = await response.json(); + + expect(response.status()).toBe(400); + expect(responseBody).toMatchObject(postInvalidStatusResponseBody()); + }); + + test(`Post /letters returns 400 if request has duplicate id`, async ({ + request, + }) => { + await createTestData(SUPPLIERID, 2); + const letters = await getLettersBySupplier(SUPPLIERID, "PENDING", 2); + + if (!letters?.length) { + test.fail(true, `No PENDING letters found for supplier ${SUPPLIERID}`); + return; + } + + const headers = postRequestHeaders(); + const body = postDuplicateIDRequestBody(letters); + + const response = await request.post(`${baseUrl}/${SUPPLIER_LETTERS}`, { + headers, + data: body, + }); + + const responseBody = await response.json(); + + expect(response.status()).toBe(400); + expect(responseBody).toMatchObject(postDuplicateIDResponseBody()); + }); + + test(`Post /letters returns 500 if request has invalid header`, async ({ + request, + }) => { + await createTestData(SUPPLIERID, 4); + const letters = await getLettersBySupplier(SUPPLIERID, "PENDING", 4); + + if (!letters?.length) { + test.fail(true, `No PENDING letters found for supplier ${SUPPLIERID}`); + return; + } + + const headers = postInvalidRequestHeaders(); + const body = postValidRequestBody(letters); + + const response = await request.post(`${baseUrl}/${SUPPLIER_LETTERS}`, { + headers, + data: body, + }); + + const responseBody = await response.json(); + + expect(response.status()).toBe(500); + expect(responseBody).toMatchObject(post500ErrorResponseBody()); + }); +}); diff --git a/tests/helpers/common-types.ts b/tests/helpers/common-types.ts index e831f151..df699504 100644 --- a/tests/helpers/common-types.ts +++ b/tests/helpers/common-types.ts @@ -1,3 +1,16 @@ +export type PostMessageRequestBody = { + data: PostRequest[]; +}; + +type PostRequest = { + type: string; + id: string; + attributes: { + reasonCode?: string; + reasonText?: string; + status: string; + }; +}; export type ErrorLink = { about: string; diff --git a/tests/sandbox/testCases/update-multiple-status-test-cases.ts b/tests/sandbox/testCases/update-multiple-status-test-cases.ts index 06b8716f..843193ee 100644 --- a/tests/sandbox/testCases/update-multiple-status-test-cases.ts +++ b/tests/sandbox/testCases/update-multiple-status-test-cases.ts @@ -2,6 +2,7 @@ import { RequestSandBoxHeaders, sandBoxHeader, } from "../../constants/request-headers"; +import { PostMessageRequestBody } from "../../helpers/common-types"; export type ApiSandboxUpdateLetterStatusTestData = { testCase: string; @@ -10,20 +11,6 @@ export type ApiSandboxUpdateLetterStatusTestData = { expectedStatus: number; }; -type PostMessageRequestBody = { - data: postRequest[]; -}; - -type postRequest = { - type: string; - id: string; - attributes: { - reasonCode?: string; - reasonText?: string; - status: string; - }; -}; - export const apiSandboxMultipleLetterStatusTestData: ApiSandboxUpdateLetterStatusTestData[] = [ { From 49a25e82ad520edc748fb6b4efe2f16494610a23 Mon Sep 17 00:00:00 2001 From: Varsha Vanbatte Date: Tue, 30 Dec 2025 12:53:34 +0000 Subject: [PATCH 2/2] Ok --- test-results/.last-run.json | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 test-results/.last-run.json diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index 6da63411..00000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "failedTests": [], - "status": "passed" -}