Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(),
};
Expand All @@ -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<Letter, "ttl" | "supplierStatus" | "supplierStatusSk"> = {
id: letterId,
supplierId,
specificationId,
groupId,
url: url,
status: status,
url,
status,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response body of the POST /letters is empty - it only returns a 202 (accepted).See https://digital.nhs.uk/developer/api-catalogue/nhs-notify-supplier#post-/letters

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export type PostMessageResponseBody = {
export type PostLettersMessageResponseBody = {

data: {
type: string;
id: string;
attributes: {
reasonCode?: string;
reasonText?: string;
status: string;
specificationId: string;
groupId?: string;
};
};
};

export function postRequestHeaders(): RequestHeaders {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export function postRequestHeaders(): RequestHeaders {
export function postLettersRequestHeaders(): RequestHeaders {

let requestHeaders: RequestHeaders;
requestHeaders = {
"NHSD-Supplier-ID": SUPPLIERID,
"NHSD-Correlation-ID": "12344",
"X-Request-ID": "requestId1",
};
return requestHeaders;
}

export function postInvalidRequestHeaders(): RequestHeaders {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export function postInvalidRequestHeaders(): RequestHeaders {
export function postLettersInvalidRequestHeaders(): 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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth including the reasonText and reasonCode in at least one of these?

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;
}
Original file line number Diff line number Diff line change
@@ -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());
});
});
13 changes: 13 additions & 0 deletions tests/helpers/common-types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
export type PostMessageRequestBody = {
data: PostRequest[];
};

type PostRequest = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type PostRequest = {
type PostLettersRequest = {

type: string;
id: string;
attributes: {
reasonCode?: string;
reasonText?: string;
status: string;
};
};

export type ErrorLink = {
about: string;
Expand Down
Loading
Loading