diff --git a/.github/workflows/stage-1-commit.yaml b/.github/workflows/stage-1-commit.yaml index 4d9d5b14..80ad8c8f 100644 --- a/.github/workflows/stage-1-commit.yaml +++ b/.github/workflows/stage-1-commit.yaml @@ -1,5 +1,8 @@ name: "Commit stage" +permissions: + contents: read + on: workflow_call: inputs: diff --git a/docs/package.json b/docs/package.json index 2f2d699b..c694856e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,6 +14,7 @@ "build": "JEKYLL_ENV=production bundle exec jekyll build --trace --config _config.yml,_config.version.yml", "debug": "JEKYLL_ENV=development BUNDLE_GEMFILE=Gemfile bundle exec jekyll serve --config _config.yml,_config.dev.yml,_config.version.yml --limit_posts 100 --trace", "generate-includes": "./generate-includes.sh", + "lint": "echo \"Documentation module has no code to lint\"", "test:unit": "echo \"Documentation module has no unit tests\"", "typecheck": "echo \"Documentation module has no typescript to typecheck\"" }, diff --git a/internal/datastore/.eslintignore b/internal/datastore/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/internal/datastore/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/internal/events/package.json b/internal/events/package.json index 09e72bde..395859af 100644 --- a/internal/events/package.json +++ b/internal/events/package.json @@ -50,5 +50,5 @@ "typecheck": "tsc --noEmit" }, "types": "dist/index.d.ts", - "version": "1.0.6" + "version": "1.0.7" } diff --git a/internal/events/tsconfig.json b/internal/events/tsconfig.json index fa5c2949..167e805a 100644 --- a/internal/events/tsconfig.json +++ b/internal/events/tsconfig.json @@ -4,8 +4,7 @@ "isolatedModules": true, "module": "commonjs", "outDir": "dist", - "resolveJsonModule": true, - "rootDir": "src" + "resolveJsonModule": true }, "exclude": [ "node_modules", @@ -14,6 +13,7 @@ "extends": "../../tsconfig.base.json", "include": [ "src/**/*", - "package.json" + "package.json", + "jest.config.ts" ] } diff --git a/lambdas/api-handler/.eslintignore b/lambdas/api-handler/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/lambdas/api-handler/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/lambdas/api-handler/package.json b/lambdas/api-handler/package.json index 5a436473..d68c90ec 100644 --- a/lambdas/api-handler/package.json +++ b/lambdas/api-handler/package.json @@ -7,6 +7,7 @@ "@aws-sdk/s3-request-presigner": "^3.925.0", "@internal/datastore": "*", "@internal/helpers": "*", + "aws-lambda": "^1.0.7", "esbuild": "^0.25.11", "pino": "^9.7.0", "zod": "^4.1.11" diff --git a/lambdas/authorizer/.eslintignore b/lambdas/authorizer/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/lambdas/authorizer/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/lambdas/authorizer/package.json b/lambdas/authorizer/package.json index 76c674c5..55e7586c 100644 --- a/lambdas/authorizer/package.json +++ b/lambdas/authorizer/package.json @@ -3,6 +3,8 @@ "@aws-sdk/client-dynamodb": "^3.858.0", "@aws-sdk/lib-dynamodb": "^3.858.0", "@internal/datastore": "*", + "@types/aws-lambda": "^8.10.148", + "aws-lambda": "^1.0.7", "esbuild": "^0.25.11", "pino": "^9.7.0", "zod": "^4.1.11" diff --git a/lambdas/letter-updates-transformer/.eslintignore b/lambdas/letter-updates-transformer/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/lambdas/letter-updates-transformer/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts b/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts index 93429c90..6fc36ff0 100644 --- a/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts +++ b/lambdas/letter-updates-transformer/src/mappers/__tests__/letter-mapper.test.ts @@ -20,9 +20,9 @@ describe("letter-mapper", () => { $LetterEvent.parse(event); expect(event.type).toBe("uk.nhs.notify.supplier-api.letter.PRINTED.v1"); expect(event.dataschema).toBe( - `https://notify.nhs.uk/cloudevents/schemas/supplier-api/letter.PRINTED.${event.dataschemaversion}.schema.json` + `https://notify.nhs.uk/cloudevents/schemas/supplier-api/letter.PRINTED.${event.dataschemaversion}.schema.json`, ); - expect(event.dataschemaversion).toBe("1.0.6"); + expect(event.dataschemaversion).toBe("1.0.7"); expect(event.subject).toBe("letter-origin/supplier-api/letter/id1"); expect(event.time).toBe("2025-11-24T15:55:18.000Z"); expect(event.recordedtime).toBe("2025-11-24T15:55:18.000Z"); diff --git a/lambdas/upsert-letter/.eslintignore b/lambdas/upsert-letter/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/lambdas/upsert-letter/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/lambdas/upsert-letter/package.json b/lambdas/upsert-letter/package.json index 9444e714..3770b763 100644 --- a/lambdas/upsert-letter/package.json +++ b/lambdas/upsert-letter/package.json @@ -1,5 +1,7 @@ { "dependencies": { + "@types/aws-lambda": "^8.10.148", + "aws-lambda": "^1.0.7", "esbuild": "^0.24.0" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 7a29e4d7..c0ca0687 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,7 +125,7 @@ }, "internal/events": { "name": "@nhsdigital/nhs-notify-event-schemas-supplier-api", - "version": "1.0.6", + "version": "1.0.7", "license": "MIT", "dependencies": { "@asyncapi/bundler": "^0.6.4", @@ -178,6 +178,7 @@ "@aws-sdk/s3-request-presigner": "^3.925.0", "@internal/datastore": "*", "@internal/helpers": "*", + "aws-lambda": "^1.0.7", "esbuild": "^0.25.11", "pino": "^9.7.0", "zod": "^4.1.11" @@ -221,6 +222,8 @@ "@aws-sdk/client-dynamodb": "^3.858.0", "@aws-sdk/lib-dynamodb": "^3.858.0", "@internal/datastore": "*", + "@types/aws-lambda": "^8.10.148", + "aws-lambda": "^1.0.7", "esbuild": "^0.25.11", "pino": "^9.7.0", "zod": "^4.1.11" @@ -1181,6 +1184,8 @@ "name": "nhs-notify-supplier-api-upsert-letter", "version": "0.0.1", "dependencies": { + "@types/aws-lambda": "^8.10.148", + "aws-lambda": "^1.0.7", "esbuild": "^0.24.0" }, "devDependencies": { @@ -6580,9 +6585,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.0.tgz", - "integrity": "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.1.tgz", + "integrity": "sha512-wOboSEdQ85dbKAJ0zL+wQ6b0HTSBRhtGa0PYKysQXkRg+vK0tdCRRVruiFM2QMprkOQwSYOnwF4og96PAaEGag==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-serde": "^4.2.8", @@ -6800,12 +6805,12 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.1.tgz", - "integrity": "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.2.tgz", + "integrity": "sha512-mqpAdux0BNmZu/SqkFhQEnod4fX23xxTvU2LUpmKp0JpSI+kPYCiHJMmzREr8yxbNxKL2/DU1UZm9i++ayU+2g==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.20.0", + "@smithy/core": "^3.20.1", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -6819,15 +6824,15 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.17", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.17.tgz", - "integrity": "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg==", + "version": "4.4.18", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.18.tgz", + "integrity": "sha512-E5hulijA59nBk/zvcwVMaS7FG7Y4l6hWA9vrW018r+8kiZef4/ETQaPI4oY+3zsy9f6KqDv3c4VKtO4DwwgpCg==", "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", @@ -6994,13 +6999,13 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.2.tgz", - "integrity": "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==", + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.3.tgz", + "integrity": "sha512-EfECiO/0fAfb590LBnUe7rI5ux7XfquQ8LBzTe7gxw0j9QW/q8UT/EHWHlxV/+jhQ3+Ssga9uUYXCQgImGMbNg==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.20.0", - "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/core": "^3.20.1", + "@smithy/middleware-endpoint": "^4.4.2", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", @@ -7101,13 +7106,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.16.tgz", - "integrity": "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ==", + "version": "4.3.17", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.17.tgz", + "integrity": "sha512-dwN4GmivYF1QphnP3xJESXKtHvkkvKHSZI8GrSKMVoENVSKW2cFPRYC4ZgstYjUHdR3zwaDkIaTDIp26JuY7Cw==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.2.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, @@ -7116,16 +7121,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.19.tgz", - "integrity": "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA==", + "version": "4.2.20", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.20.tgz", + "integrity": "sha512-VD/I4AEhF1lpB3B//pmOIMBNLMrtdMXwy9yCOfa2QkJGDr63vH3RqPbSAKzoGMov3iryCxTXCxSsyGmEB8PDpg==", "license": "Apache-2.0", "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, @@ -21776,13 +21781,6 @@ "node": ">=18.17" } }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "extraneous": true, - "license": "MIT" - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -22665,9 +22663,9 @@ "name": "nhs-notify-supplier-api-letter-test-data-utility", "version": "0.0.1", "dependencies": { - "@aws-sdk/client-dynamodb": "^3.858.0", + "@aws-sdk/client-dynamodb": "^3.954.0", "@aws-sdk/client-s3": "^3.858.0", - "@aws-sdk/lib-dynamodb": "^3.858.0", + "@aws-sdk/lib-dynamodb": "^3.954.0", "@internal/datastore": "*", "esbuild": "^0.25.11", "pino": "^9.7.0", @@ -22681,6 +22679,16 @@ "typescript": "^5.9.3" } }, + "scripts/utilities/letter-test-data/node_modules/ansi-styles": { + "version": "6.2.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "scripts/utilities/letter-test-data/node_modules/cliui": { "version": "8.0.1", "license": "ISC", @@ -22750,8 +22758,8 @@ "name": "nhs-notify-supplier-api-suppliers-data-utility", "version": "0.0.1", "dependencies": { - "@aws-sdk/client-dynamodb": "^3.858.0", - "@aws-sdk/lib-dynamodb": "^3.858.0", + "@aws-sdk/client-dynamodb": "^3.954.0", + "@aws-sdk/lib-dynamodb": "^3.954.0", "@internal/datastore": "*", "esbuild": "^0.25.11", "pino": "^9.7.0", diff --git a/scripts/tests/lint.sh b/scripts/tests/lint.sh new file mode 100755 index 00000000..2ace8310 --- /dev/null +++ b/scripts/tests/lint.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +# This file is for you! Edit it to call your unit test suite. Note that the same +# file will be called if you run it locally as if you run it on CI. + +# Replace the following line with something like: +# +# rails test:unit +# python manage.py test +# npm run test +# +# or whatever is appropriate to your project. You should *only* run your fast +# tests from here. If you want to run other test suites, see the predefined +# tasks in scripts/test.mk. + +# run tests +npm ci +npm run lint --workspaces diff --git a/scripts/tests/typecheck.sh b/scripts/tests/typecheck.sh new file mode 100755 index 00000000..2ed6c2e0 --- /dev/null +++ b/scripts/tests/typecheck.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +# This file is for you! Edit it to call your unit test suite. Note that the same +# file will be called if you run it locally as if you run it on CI. + +# Replace the following line with something like: +# +# rails test:unit +# python manage.py test +# npm run test +# +# or whatever is appropriate to your project. You should *only* run your fast +# tests from here. If you want to run other test suites, see the predefined +# tasks in scripts/test.mk. + +# run tests +npm ci +npm run typecheck --workspaces diff --git a/scripts/utilities/letter-test-data/.eslintignore b/scripts/utilities/letter-test-data/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/scripts/utilities/letter-test-data/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/scripts/utilities/letter-test-data/jest.config.ts b/scripts/utilities/letter-test-data/jest.config.ts index cc9a39c9..445325b8 100644 --- a/scripts/utilities/letter-test-data/jest.config.ts +++ b/scripts/utilities/letter-test-data/jest.config.ts @@ -1,7 +1,7 @@ -import type { Config } from 'jest'; +import type { Config } from "jest"; export const baseJestConfig: Config = { - preset: 'ts-jest', + preset: "ts-jest", // Automatically clear mock calls, instances, contexts and results before every test clearMocks: true, @@ -10,10 +10,10 @@ export const baseJestConfig: Config = { collectCoverage: true, // The directory where Jest should output its coverage files - coverageDirectory: './.reports/unit/coverage', + coverageDirectory: "./.reports/unit/coverage", // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'babel', + coverageProvider: "babel", coverageThreshold: { global: { @@ -24,38 +24,38 @@ export const baseJestConfig: Config = { }, }, - coveragePathIgnorePatterns: ['/__tests__/'], - transform: { '^.+\\.ts$': 'ts-jest' }, - testPathIgnorePatterns: ['.build'], - testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + coveragePathIgnorePatterns: ["/__tests__/"], + transform: { "^.+\\.ts$": "ts-jest" }, + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], // Use this configuration option to add custom reporters to Jest reporters: [ - 'default', + "default", [ - 'jest-html-reporter', + "jest-html-reporter", { - pageTitle: 'Test Report', - outputPath: './.reports/unit/test-report.html', + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", includeFailureMsg: true, }, ], ], // The test environment that will be used for testing - testEnvironment: 'jsdom', + testEnvironment: "jsdom", }; const utilsJestConfig = { ...baseJestConfig, - testEnvironment: 'node', + testEnvironment: "node", coveragePathIgnorePatterns: [ ...(baseJestConfig.coveragePathIgnorePatterns ?? []), - 'cli/index.ts', - 'helpers/s3_helpers.ts', - 'letter-repo-factory.ts', + "cli/index.ts", + "helpers/s3_helpers.ts", + "letter-repo-factory.ts", ], }; diff --git a/scripts/utilities/letter-test-data/package.json b/scripts/utilities/letter-test-data/package.json index 58be5cd6..ed4e0d9a 100644 --- a/scripts/utilities/letter-test-data/package.json +++ b/scripts/utilities/letter-test-data/package.json @@ -1,8 +1,8 @@ { "dependencies": { - "@aws-sdk/client-dynamodb": "^3.858.0", + "@aws-sdk/client-dynamodb": "^3.954.0", "@aws-sdk/client-s3": "^3.858.0", - "@aws-sdk/lib-dynamodb": "^3.858.0", + "@aws-sdk/lib-dynamodb": "^3.954.0", "@internal/datastore": "*", "esbuild": "^0.25.11", "pino": "^9.7.0", diff --git a/scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts b/scripts/utilities/letter-test-data/src/__test__/helpers/create-letter-helpers.test.ts similarity index 92% rename from scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts rename to scripts/utilities/letter-test-data/src/__test__/helpers/create-letter-helpers.test.ts index a8b2a0db..36217a5c 100644 --- a/scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts +++ b/scripts/utilities/letter-test-data/src/__test__/helpers/create-letter-helpers.test.ts @@ -1,9 +1,12 @@ import { LetterRepository } from "@internal/datastore/src/letter-repository"; import { LetterStatusType } from "@internal/datastore"; -import { createLetter, createLetterDto } from "../../helpers/create_letter_helpers"; -import { uploadFile } from "../../helpers/s3_helpers"; +import { + createLetter, + createLetterDto, +} from "../../helpers/create-letter-helpers"; +import uploadFile from "../../helpers/s3-helpers"; -jest.mock("../../helpers/s3_helpers"); +jest.mock("../../helpers/s3-helpers"); describe("Create letter helpers", () => { beforeEach(() => { diff --git a/scripts/utilities/letter-test-data/src/__test__/helpers/s3-helpers.test.ts b/scripts/utilities/letter-test-data/src/__test__/helpers/s3-helpers.test.ts new file mode 100644 index 00000000..22e56cd5 --- /dev/null +++ b/scripts/utilities/letter-test-data/src/__test__/helpers/s3-helpers.test.ts @@ -0,0 +1,87 @@ +/** + * Unit tests for s3-helpers.ts + * + * Mocks: + * - @aws-sdk/client-s3: S3Client (with send) and PutObjectCommand + * - node:fs.readFileSync to avoid touching the filesystem + */ + +import * as s3Module from "@aws-sdk/client-s3"; +import uploadFile from "../../helpers/s3-helpers"; + +jest.mock("@aws-sdk/client-s3", () => { + const sendMock = jest.fn(); + class PutObjectCommand { + input: any; + + constructor(input: any) { + this.input = input; + } + } + const S3Client = jest.fn().mockImplementation(() => ({ send: sendMock })); + return { + S3Client, + PutObjectCommand, + __sendMock: sendMock, + __esModule: true, + }; +}); + +jest.mock("node:fs", () => ({ + readFileSync: jest.fn().mockReturnValue(Buffer.from("fake-pdf-bytes")), +})); + +describe("uploadFile", () => { + const bucket = "my-bucket"; + const supplierId = "supplier-1"; + const sourceFilename = "some.pdf"; + const targetFilename = "target.pdf"; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("calls S3Client.send with a PutObjectCommand containing correct params", async () => { + const sendMock = (s3Module as any).__sendMock as jest.Mock; + sendMock.mockResolvedValue({ ETag: '"etag-value"' }); + + await expect( + uploadFile(bucket, supplierId, sourceFilename, targetFilename), + ).resolves.toBeDefined(); + + // S3Client is a mocked constructor — grab the instance that was created + const S3ClientMock = (s3Module as any).S3Client as jest.Mock; + expect(S3ClientMock).toHaveBeenCalled(); + + const instance = S3ClientMock.mock.results[0].value; + expect(instance.send).toHaveBeenCalledTimes(1); + + const calledWith = instance.send.mock.calls[0][0]; + // The mocked PutObjectCommand stores input as `input` property + expect(calledWith).toHaveProperty("input"); + expect(calledWith.input).toEqual({ + Bucket: bucket, + Key: `${supplierId}/${targetFilename}`, + Body: Buffer.from("fake-pdf-bytes"), + ContentType: "application/pdf", + }); + }); + + it("logs and rethrows when S3Client.send rejects", async () => { + const sendMock = (s3Module as any).__sendMock as jest.Mock; + const err = new Error("upload-failed"); + sendMock.mockRejectedValueOnce(err); + + const consoleSpy = jest + .spyOn(console, "error") + .mockImplementation(() => {}); + + await expect( + uploadFile(bucket, supplierId, sourceFilename, targetFilename), + ).rejects.toThrow("upload-failed"); + + expect(consoleSpy).toHaveBeenCalledWith("Error uploading file:", err); + + consoleSpy.mockRestore(); + }); +}); diff --git a/scripts/utilities/letter-test-data/src/cli/index.ts b/scripts/utilities/letter-test-data/src/cli/index.ts index 915c392b..0d2ec0f1 100644 --- a/scripts/utilities/letter-test-data/src/cli/index.ts +++ b/scripts/utilities/letter-test-data/src/cli/index.ts @@ -1,10 +1,13 @@ import { hideBin } from "yargs/helpers"; -import yargs from 'yargs'; +import yargs from "yargs"; import { LetterStatusType } from "@internal/datastore/src/types"; -import { randomUUID } from "crypto"; -import { createLetter, createLetterDto } from "../helpers/create_letter_helpers"; -import { createLetterRepository } from "../infrastructure/letter-repo-factory"; -import { uploadFile } from "../helpers/s3_helpers"; +import { randomUUID } from "node:crypto"; +import { + createLetter, + createLetterDto, +} from "../helpers/create-letter-helpers"; +import createLetterRepository from "../infrastructure/letter-repo-factory"; +import uploadFile from "../helpers/s3-helpers"; async function main() { await yargs(hideBin(process.argv)) @@ -60,17 +63,15 @@ async function main() { }, }, async (argv) => { - const supplierId = argv.supplierId; - const letterId = argv.letterId ? argv.letterId : randomUUID(); + const { supplierId } = argv; + const letterId = argv.letterId ?? randomUUID(); const bucketName = `nhs-${argv.awsAccountId}-eu-west-2-${argv.environment}-supapi-test-letters`; const targetFilename = `${letterId}.pdf`; - const groupId = argv.groupId ? argv.groupId : randomUUID(); - const specificationId = argv.specificationId - ? argv.specificationId - : randomUUID(); - const status = argv.status; - const environment = argv.environment; - const ttlHours = argv.ttlHours; + const groupId = argv.groupId ?? randomUUID(); + const specificationId = argv.specificationId ?? randomUUID(); + const { status } = argv; + const { environment } = argv; + const { ttlHours } = argv; const letterRepository = createLetterRepository(environment, ttlHours); createLetter({ @@ -114,7 +115,7 @@ async function main() { demandOption: false, default: 336, }, - "count": { + count: { type: "number", demandOption: true, }, @@ -137,41 +138,44 @@ async function main() { }, }, async (argv) => { - // set batch ID const batchId = randomUUID(); // parse args - const supplierId = argv.supplierId; - const groupId = argv.groupId ? argv.groupId : randomUUID(); - const specificationId = argv.specificationId - ? argv.specificationId - : randomUUID(); - const status = argv.status; - const environment = argv.environment; - const ttlHours = argv.ttlHours; + const { supplierId } = argv; + const groupId = argv.groupId ?? randomUUID(); + const specificationId = argv.specificationId ?? randomUUID(); + const { status } = argv; + const { environment } = argv; + const { ttlHours } = argv; const letterRepository = createLetterRepository(environment, ttlHours); - const count = argv.count; - + const { count } = argv; // Upload a test file for this batch const bucketName = `nhs-${argv.awsAccountId}-eu-west-2-${argv.environment}-supapi-test-letters`; const targetFilename = `${batchId}-${status}.pdf`; const url = `s3://${bucketName}/${batchId}/${targetFilename}`; - await uploadFile(bucketName, batchId, "../../test_letter.pdf", targetFilename); + await uploadFile( + bucketName, + batchId, + "../../test_letter.pdf", + targetFilename, + ); // Create letter DTOs - let letterDtos = []; + const letterDtos = []; for (let i = 0; i < count; i++) { - letterDtos.push(createLetterDto({ - letterId: randomUUID(), - supplierId, - groupId, - specificationId, - status: status as LetterStatusType, - url, - })); - }; + letterDtos.push( + createLetterDto({ + letterId: randomUUID(), + supplierId, + groupId, + specificationId, + status: status as LetterStatusType, + url, + }), + ); + } // Upload Letters await letterRepository.putLetterBatch(letterDtos); @@ -184,8 +188,8 @@ async function main() { } if (require.main === module) { - main().catch((err) => { - console.error(err); + main().catch((error) => { + console.error(error); process.exitCode = 1; }); } 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 similarity index 97% rename from scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts rename to scripts/utilities/letter-test-data/src/helpers/create-letter-helpers.ts index 691171c0..827c6801 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 @@ -1,9 +1,9 @@ import { - LetterRepository, Letter, + LetterRepository, LetterStatusType, } from "@internal/datastore"; -import { uploadFile } from "./s3_helpers"; +import uploadFile from "./s3-helpers"; export async function createLetter(params: { letterId: string; diff --git a/scripts/utilities/letter-test-data/src/helpers/s3_helpers.ts b/scripts/utilities/letter-test-data/src/helpers/s3-helpers.ts similarity index 53% rename from scripts/utilities/letter-test-data/src/helpers/s3_helpers.ts rename to scripts/utilities/letter-test-data/src/helpers/s3-helpers.ts index 89ef72a4..b88bbf74 100644 --- a/scripts/utilities/letter-test-data/src/helpers/s3_helpers.ts +++ b/scripts/utilities/letter-test-data/src/helpers/s3-helpers.ts @@ -1,9 +1,13 @@ -import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; -import { readFileSync } from "fs"; -import path from "path"; +import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { readFileSync } from "node:fs"; +import path from "node:path"; - -export async function uploadFile(bucketName: string, supplierId: string, sourceFilename: string, targetFilename: string) { +export default async function uploadFile( + bucketName: string, + supplierId: string, + sourceFilename: string, + targetFilename: string, +) { try { const s3 = new S3Client(); const filePath = path.join(__dirname, sourceFilename); @@ -18,7 +22,8 @@ export async function uploadFile(bucketName: string, supplierId: string, sourceF const command = new PutObjectCommand(uploadParams); return await s3.send(command); - } catch (err) { - console.error("Error uploading file:", err); + } catch (error) { + console.error("Error uploading file:", error); + throw error; } } diff --git a/scripts/utilities/letter-test-data/src/infrastructure/letter-repo-factory.ts b/scripts/utilities/letter-test-data/src/infrastructure/letter-repo-factory.ts index e0060337..c6440bf1 100644 --- a/scripts/utilities/letter-test-data/src/infrastructure/letter-repo-factory.ts +++ b/scripts/utilities/letter-test-data/src/infrastructure/letter-repo-factory.ts @@ -1,9 +1,12 @@ -import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; -import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'; -import { pino } from 'pino'; -import { LetterRepository } from '@internal/datastore'; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; +import { pino } from "pino"; +import { LetterRepository } from "@internal/datastore"; -export function createLetterRepository(environment: string, ttlHours:number): LetterRepository { +export default function createLetterRepository( + environment: string, + ttlHours: number, +): LetterRepository { const ddbClient = new DynamoDBClient({}); const docClient = DynamoDBDocumentClient.from(ddbClient); const log = pino(); diff --git a/scripts/utilities/supplier-data/.eslintignore b/scripts/utilities/supplier-data/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/scripts/utilities/supplier-data/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/scripts/utilities/supplier-data/jest.config.ts b/scripts/utilities/supplier-data/jest.config.ts index f2972c27..4bb3369a 100644 --- a/scripts/utilities/supplier-data/jest.config.ts +++ b/scripts/utilities/supplier-data/jest.config.ts @@ -1,7 +1,7 @@ -import type { Config } from 'jest'; +import type { Config } from "jest"; export const baseJestConfig: Config = { - preset: 'ts-jest', + preset: "ts-jest", // Automatically clear mock calls, instances, contexts and results before every test clearMocks: true, @@ -10,10 +10,10 @@ export const baseJestConfig: Config = { collectCoverage: true, // The directory where Jest should output its coverage files - coverageDirectory: './.reports/unit/coverage', + coverageDirectory: "./.reports/unit/coverage", // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'babel', + coverageProvider: "babel", coverageThreshold: { global: { @@ -24,37 +24,37 @@ export const baseJestConfig: Config = { }, }, - coveragePathIgnorePatterns: ['/__tests__/'], - transform: { '^.+\\.ts$': 'ts-jest' }, - testPathIgnorePatterns: ['.build'], - testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + coveragePathIgnorePatterns: ["/__tests__/"], + transform: { "^.+\\.ts$": "ts-jest" }, + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], // Use this configuration option to add custom reporters to Jest reporters: [ - 'default', + "default", [ - 'jest-html-reporter', + "jest-html-reporter", { - pageTitle: 'Test Report', - outputPath: './.reports/unit/test-report.html', + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", includeFailureMsg: true, }, ], ], // The test environment that will be used for testing - testEnvironment: 'jsdom', + testEnvironment: "jsdom", }; const utilsJestConfig = { ...baseJestConfig, - testEnvironment: 'node', + testEnvironment: "node", coveragePathIgnorePatterns: [ ...(baseJestConfig.coveragePathIgnorePatterns ?? []), - 'cli/index.ts', - 'suppliers-repo-factory.ts', + "cli/index.ts", + "suppliers-repo-factory.ts", ], }; diff --git a/scripts/utilities/supplier-data/package.json b/scripts/utilities/supplier-data/package.json index 0d3b48e9..ebeb6a55 100644 --- a/scripts/utilities/supplier-data/package.json +++ b/scripts/utilities/supplier-data/package.json @@ -1,7 +1,7 @@ { "dependencies": { - "@aws-sdk/client-dynamodb": "^3.858.0", - "@aws-sdk/lib-dynamodb": "^3.858.0", + "@aws-sdk/client-dynamodb": "^3.954.0", + "@aws-sdk/lib-dynamodb": "^3.954.0", "@internal/datastore": "*", "esbuild": "^0.25.11", "pino": "^9.7.0", diff --git a/scripts/utilities/supplier-data/src/cli/index.ts b/scripts/utilities/supplier-data/src/cli/index.ts index 3efab279..bda349ed 100644 --- a/scripts/utilities/supplier-data/src/cli/index.ts +++ b/scripts/utilities/supplier-data/src/cli/index.ts @@ -1,10 +1,6 @@ import { hideBin } from "yargs/helpers"; -import yargs from 'yargs'; -import { LetterStatusType } from "@internal/datastore/src/types"; -import { randomUUID } from "crypto"; -import { createSupplierRepository } from "../infrastructure/suppliers-repo-factory"; - - +import yargs from "yargs"; +import createSupplierRepository from "../infrastructure/suppliers-repo-factory"; async function main() { await yargs(hideBin(process.argv)) @@ -16,35 +12,32 @@ async function main() { type: "string", demandOption: true, }, - "id": { + id: { type: "string", demandOption: true, }, - "name": { + name: { type: "string", demandOption: true, }, - "apimId": { + apimId: { type: "string", demandOption: true, }, status: { type: "string", demandOption: true, - choices: [ - "ENABLED", - "DISABLED" - ], + choices: ["ENABLED", "DISABLED"], }, }, async (argv) => { // parse args - const id = argv.id; - const name = argv.name; - const apimId = argv.apimId; + const { id } = argv; + const { name } = argv; + const { apimId } = argv; const status = argv.status as "ENABLED" | "DISABLED"; - const environment = argv.environment; + const { environment } = argv; const supplierRepository = createSupplierRepository(environment); @@ -56,13 +49,13 @@ async function main() { }); console.log(`PUT successful ${JSON.stringify(putResult)}`); - } + }, ) .command( "get-supplier-by-id", "Get a supplier by their Supplier ID", { - "id": { + id: { type: "string", demandOption: true, }, @@ -72,9 +65,8 @@ async function main() { }, }, async (argv) => { - - const id = argv.id; - const environment = argv.environment; + const { id } = argv; + const { environment } = argv; const supplierRepository = createSupplierRepository(environment); @@ -87,7 +79,7 @@ async function main() { "get-supplier-by-apim-id", "Get a supplier by their APIM ID", { - "apimId": { + apimId: { type: "string", demandOption: true, }, @@ -97,9 +89,8 @@ async function main() { }, }, async (argv) => { - - const apimId = argv.apimId; - const environment = argv.environment; + const { apimId } = argv; + const { environment } = argv; const supplierRepository = createSupplierRepository(environment); @@ -113,8 +104,8 @@ async function main() { } if (require.main === module) { - main().catch((err) => { - console.error(err); + main().catch((error) => { + console.error(error); process.exitCode = 1; }); } diff --git a/scripts/utilities/supplier-data/src/infrastructure/suppliers-repo-factory.ts b/scripts/utilities/supplier-data/src/infrastructure/suppliers-repo-factory.ts index 3bddc616..59ce4c3a 100644 --- a/scripts/utilities/supplier-data/src/infrastructure/suppliers-repo-factory.ts +++ b/scripts/utilities/supplier-data/src/infrastructure/suppliers-repo-factory.ts @@ -1,9 +1,11 @@ -import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; -import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb'; -import { pino } from 'pino'; -import { SupplierRepository } from '@internal/datastore'; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; +import { pino } from "pino"; +import { SupplierRepository } from "@internal/datastore"; -export function createSupplierRepository(environment: string): SupplierRepository { +export default function createSupplierRepository( + environment: string, +): SupplierRepository { const ddbClient = new DynamoDBClient({}); const docClient = DynamoDBDocumentClient.from(ddbClient); const log = pino(); diff --git a/tests/component-tests/apiGateway-tests/get-letter-status.spec.ts b/tests/component-tests/apiGateway-tests/get-letter-status.spec.ts index c2a12bf9..aa5d475c 100644 --- a/tests/component-tests/apiGateway-tests/get-letter-status.spec.ts +++ b/tests/component-tests/apiGateway-tests/get-letter-status.spec.ts @@ -30,7 +30,7 @@ test.describe("API Gateway Tests to Verify Get Letter Status Endpoint", () => { `${baseUrl}/${SUPPLIER_LETTERS}/${letter.id}`, { headers, - } + }, ); const responseBody = await response.json(); diff --git a/tests/component-tests/apiGateway-tests/testCases/create-mi.ts b/tests/component-tests/apiGateway-tests/testCases/create-mi.ts index f7f0b222..e3f60db9 100644 --- a/tests/component-tests/apiGateway-tests/testCases/create-mi.ts +++ b/tests/component-tests/apiGateway-tests/testCases/create-mi.ts @@ -1,70 +1,61 @@ - - - export type MiRequestBody = { data: { type: string; attributes: { - groupId: string; - lineItem: string; - quantity: number; - specificationId: string; - stockRemaining: number; - timestamp: string; + groupId: string; + lineItem: string; + quantity: number; + specificationId: string; + stockRemaining: number; + timestamp: string; }; }; }; -export function miValidRequest() : MiRequestBody{ - let requestBody: MiRequestBody; - - requestBody = { +export function miValidRequest(): MiRequestBody { + return { data: { -  attributes: { - groupId: 'group123', - lineItem: 'envelope-business-standard', + attributes: { + groupId: "group123", + lineItem: "envelope-business-standard", quantity: 10, - specificationId: 'Test-Spec-Id', + specificationId: "Test-Spec-Id", stockRemaining: 100, timestamp: new Date().toISOString(), }, - type: 'ManagementInformation', - }}; - return requestBody; + type: "ManagementInformation", + }, + }; } -export function miInvalidRequest() : MiRequestBody{ - let requestBody: MiRequestBody; - - requestBody = { +export function miInvalidRequest(): MiRequestBody { + return { data: { -  attributes: { - groupId: 'group123', - lineItem: 'envelope-business-standard', + attributes: { + groupId: "group123", + lineItem: "envelope-business-standard", quantity: 10, - specificationId: 'Test-Spec-Id', + specificationId: "Test-Spec-Id", stockRemaining: 100, timestamp: new Date().toISOString(), }, - type: '?', - }}; - return requestBody; + type: "?", + }, + }; } -export function miInvalidDateRequest() : MiRequestBody{ - let requestBody: MiRequestBody; - - requestBody = { +export function miInvalidDateRequest(): MiRequestBody { + return { data: { -  attributes: { - groupId: 'group123', - lineItem: 'envelope-business-standard', + attributes: { + groupId: "group123", + lineItem: "envelope-business-standard", quantity: 10, - specificationId: 'Test-Spec-Id', + specificationId: "Test-Spec-Id", stockRemaining: 100, - timestamp: '2021-10-28T', + timestamp: "2021-10-28T", }, - type: 'ManagementInformation', - }}; - return requestBody; + type: "ManagementInformation", + }, + }; } diff --git a/tests/component-tests/apiGateway-tests/testCases/update-letter-status.ts b/tests/component-tests/apiGateway-tests/testCases/update-letter-status.ts index 368711a3..10a9184f 100644 --- a/tests/component-tests/apiGateway-tests/testCases/update-letter-status.ts +++ b/tests/component-tests/apiGateway-tests/testCases/update-letter-status.ts @@ -29,23 +29,19 @@ export type PatchMessageResponseBody = { }; export function patchRequestHeaders(): RequestHeaders { - let requestHeaders: RequestHeaders; - requestHeaders = { + return { headerauth1: process.env.HEADERAUTH || "", "NHSD-Supplier-ID": SUPPLIERID, "NHSD-Correlation-ID": "12344", "X-Request-ID": "requestId1", }; - return requestHeaders; } export function patchValidRequestBody( id: string, - status: string + status: string, ): PatchMessageRequestBody { - let requestBody: PatchMessageRequestBody; - - requestBody = { + return { data: { attributes: { status, @@ -54,16 +50,13 @@ export function patchValidRequestBody( id, }, }; - return requestBody; } export function patchFailureRequestBody( id: string, - status: string + status: string, ): PatchMessageRequestBody { - let requestBody: PatchMessageRequestBody; - - requestBody = { + return { data: { attributes: { status, @@ -74,12 +67,10 @@ export function patchFailureRequestBody( id, }, }; - return requestBody; } export function patch400ErrorResponseBody(): ErrorMessageBody { - let responseBody: ErrorMessageBody; - responseBody = { + return { errors: [ { id: "12344", @@ -94,12 +85,10 @@ export function patch400ErrorResponseBody(): ErrorMessageBody { }, ], }; - return responseBody; } export function patch500ErrorResponseBody(id: string): ErrorMessageBody { - let responseBody: ErrorMessageBody; - responseBody = { + return { errors: [ { id: "12344", @@ -114,5 +103,4 @@ export function patch500ErrorResponseBody(id: string): ErrorMessageBody { }, ], }; - return responseBody; } 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 index 117e8838..733cc77b 100644 --- a/tests/component-tests/apiGateway-tests/testCases/update-multiple-letter-status.ts +++ b/tests/component-tests/apiGateway-tests/testCases/update-multiple-letter-status.ts @@ -7,31 +7,25 @@ import { import { SupplierApiLetters } from "../../../helpers/generate-fetch-test-data"; export function postLettersRequestHeaders(): RequestHeaders { - let requestHeaders: RequestHeaders; - requestHeaders = { + return { "NHSD-Supplier-ID": SUPPLIERID, "NHSD-Correlation-ID": "12344", "X-Request-ID": "requestId1", }; - return requestHeaders; } export function postLettersInvalidRequestHeaders(): RequestHeaders { - let requestHeaders: RequestHeaders; - requestHeaders = { + return { "NHSD-Supplier-ID": SUPPLIERID, "NHSD-Correlation-ID": "12344", // Request Id is missing }; - return requestHeaders; } export function postValidRequestBody( letters: SupplierApiLetters[], ): PostMessageRequestBody { - let requestBody: PostMessageRequestBody; - - requestBody = { + return { data: [ { type: "Letter", @@ -65,15 +59,12 @@ export function postValidRequestBody( }, ], }; - return requestBody; } export function postInvalidStatusRequestBody( letters: SupplierApiLetters[], ): PostMessageRequestBody { - let requestBody: PostMessageRequestBody; - - requestBody = { + return { data: [ { type: "Letter", @@ -91,15 +82,12 @@ export function postInvalidStatusRequestBody( }, ], }; - return requestBody; } export function postDuplicateIDRequestBody( letters: SupplierApiLetters[], ): PostMessageRequestBody { - let requestBody: PostMessageRequestBody; - - requestBody = { + return { data: [ { type: "Letter", @@ -117,13 +105,10 @@ export function postDuplicateIDRequestBody( }, ], }; - return requestBody; } export function postInvalidStatusResponseBody(): ErrorMessageBody { - let responseBody: ErrorMessageBody; - - responseBody = { + return { errors: [ { id: "12344", @@ -138,13 +123,10 @@ export function postInvalidStatusResponseBody(): ErrorMessageBody { }, ], }; - return responseBody; } export function postDuplicateIDResponseBody(): ErrorMessageBody { - let responseBody: ErrorMessageBody; - - responseBody = { + return { errors: [ { id: "12344", @@ -160,13 +142,10 @@ export function postDuplicateIDResponseBody(): ErrorMessageBody { }, ], }; - return responseBody; } export function post500ErrorResponseBody(): ErrorMessageBody { - let responseBody: ErrorMessageBody; - - responseBody = { + return { errors: [ { id: "12344", @@ -181,5 +160,4 @@ export function post500ErrorResponseBody(): ErrorMessageBody { }, ], }; - return responseBody; } diff --git a/tests/component-tests/apiGateway-tests/update-letter-status.spec.ts b/tests/component-tests/apiGateway-tests/update-letter-status.spec.ts index 371dbba2..bd90cb26 100644 --- a/tests/component-tests/apiGateway-tests/update-letter-status.spec.ts +++ b/tests/component-tests/apiGateway-tests/update-letter-status.spec.ts @@ -45,7 +45,7 @@ test.describe("API Gateway Tests to Verify Patch Status Endpoint", () => { { headers, data: body, - } + }, ); expect(response.status()).toBe(202); @@ -72,7 +72,7 @@ test.describe("API Gateway Tests to Verify Patch Status Endpoint", () => { { headers, data: body, - } + }, ); expect(response.status()).toBe(202); @@ -92,7 +92,7 @@ test.describe("API Gateway Tests to Verify Patch Status Endpoint", () => { { headers, data: body, - } + }, ); const responseBody = await response.json(); @@ -113,7 +113,7 @@ test.describe("API Gateway Tests to Verify Patch Status Endpoint", () => { { headers, data: body, - } + }, ); const responseBody = await response.json(); @@ -133,7 +133,7 @@ test.describe("API Gateway Tests to Verify Patch Status Endpoint", () => { { headers, data: body, - } + }, ); const responseBody = await response.json(); diff --git a/tests/config/reporters.ts b/tests/config/reporters.ts index 913e09c3..6579d8bd 100644 --- a/tests/config/reporters.ts +++ b/tests/config/reporters.ts @@ -1,8 +1,7 @@ import type { ReporterDescription } from "@playwright/test"; -import path from "path"; +import path from "node:path"; const resultsDir = process.env.RESULTS_DIR || "results"; -const reportsDir = process.env.REPORTS_DIR || "reports"; export function getReporters(allureFolder: string) { return [ diff --git a/tests/config/sandbox.config.ts b/tests/config/sandbox.config.ts index 79fd5c9a..6f63788b 100644 --- a/tests/config/sandbox.config.ts +++ b/tests/config/sandbox.config.ts @@ -1,7 +1,7 @@ import type { PlaywrightTestConfig } from "@playwright/test"; +import path from "node:path"; import { config as baseConfig } from "./playwright.base.config"; import { getReporters } from "./reporters"; -import path from "path"; const localConfig: PlaywrightTestConfig = { /* Reporter to use. See https://playwright.dev/docs/test-reporters */ diff --git a/tests/helpers/generate-fetch-test-data.ts b/tests/helpers/generate-fetch-test-data.ts index 7e7eee77..d0a0486b 100644 --- a/tests/helpers/generate-fetch-test-data.ts +++ b/tests/helpers/generate-fetch-test-data.ts @@ -33,7 +33,7 @@ export interface SupplierApiLetters { export async function createTestData( supplierId: string, - count?: number + count?: number, ): Promise { await runCreateLetter({ filter: "nhs-notify-supplier-api-letter-test-data-utility", @@ -50,7 +50,7 @@ export async function createTestData( export const getLettersBySupplier = async ( supplierId: string, status: string, - limit: number + limit: number, ) => { const supplierStatus = `${supplierId}#${status}`; const params = { @@ -78,13 +78,13 @@ export const deleteLettersBySupplier = async (id: string) => { TableName: LETTERSTABLENAME, Key: { supplierId: SUPPLIERID, id }, ReturnValues: "ALL_OLD", - }) + }), ); return resp.Attributes; }; export async function checkSupplierExists( - supplierId: string + supplierId: string, ): Promise { try { const params = { diff --git a/tests/helpers/pnpm-helpers.ts b/tests/helpers/pnpm-helpers.ts index d71b1d18..5351f92e 100644 --- a/tests/helpers/pnpm-helpers.ts +++ b/tests/helpers/pnpm-helpers.ts @@ -29,7 +29,7 @@ export async function runCreateLetter(options: { const workspaceRoot = path.resolve( __dirname, - "../../scripts/utilities/letter-test-data" + "../../scripts/utilities/letter-test-data", ); const cmd = process.platform === "win32" ? "npm.cmd" : "npm"; const root = path.resolve(workspaceRoot); @@ -60,7 +60,6 @@ export async function runCreateLetter(options: { ]; await new Promise((resolve, reject) => { - let output = ""; const child = spawn(cmd, args, { stdio: "inherit", cwd: root, @@ -68,12 +67,11 @@ export async function runCreateLetter(options: { }); child.stdout?.on("id", (id) => { const text = id.toString(); - output += text; process.stdout.write(text); }); child.on("close", (code) => - code === 0 ? resolve() : reject(new Error(`pnpm exited with ${code}`)) + code === 0 ? resolve() : reject(new Error(`pnpm exited with ${code}`)), ); child.on("error", reject); }); @@ -87,11 +85,11 @@ export async function createSupplierData(options: { environment: string; status: string; }) { - const { apimId, environment, name, status, supplierId, filter } = options; + const { apimId, environment, filter, name, status, supplierId } = options; const workspaceRoot = path.resolve( __dirname, - "../../scripts/utilities/supplier-data" + "../../scripts/utilities/supplier-data", ); const cmd = process.platform === "win32" ? "npm.cmd" : "npm"; const root = path.resolve(workspaceRoot); @@ -118,7 +116,6 @@ export async function createSupplierData(options: { ]; await new Promise((resolve, reject) => { - let output = ""; const child = spawn(cmd, args, { stdio: "inherit", cwd: root, @@ -126,12 +123,11 @@ export async function createSupplierData(options: { }); child.stdout?.on("id", (id) => { const text = id.toString(); - output += text; process.stdout.write(text); }); child.on("close", (code) => - code === 0 ? resolve() : reject(new Error(`pnpm exited with ${code}`)) + code === 0 ? resolve() : reject(new Error(`pnpm exited with ${code}`)), ); child.on("error", reject); }); diff --git a/tests/helpers/validate-json-schema.ts b/tests/helpers/validate-json-schema.ts index 82dd7e80..b3987d99 100644 --- a/tests/helpers/validate-json-schema.ts +++ b/tests/helpers/validate-json-schema.ts @@ -19,7 +19,7 @@ export default async function validateApiResponse( method: string, pathVar: string, status: number, - body: any + body: any, ): Promise { const openapiDoc = await import(paths); @@ -36,7 +36,7 @@ export default async function validateApiResponse( operation.responses[status] || operation.responses.default; if (!responseSchema) { throw new Error( - `No schema defined for status ${status} at ${method.toUpperCase()} ${pathVar}` + `No schema defined for status ${status} at ${method.toUpperCase()} ${pathVar}`, ); } diff --git a/tests/mtls/mtls-test.spec.ts b/tests/mtls/mtls-test.spec.ts index b3fbee6d..256b3c96 100644 --- a/tests/mtls/mtls-test.spec.ts +++ b/tests/mtls/mtls-test.spec.ts @@ -1,7 +1,7 @@ -import { test, expect, request, APIRequestContext } from "@playwright/test"; +import { APIRequestContext, expect, request, test } from "@playwright/test"; // Assume you have your constants in a config file -const PROXY_URL = process.env.PROXY_URL; +const { PROXY_URL } = process.env; test("should fail when connecting without client certificate", async () => { let apiContext: APIRequestContext | null = null; @@ -15,15 +15,15 @@ test("should fail when connecting without client certificate", async () => { // Check if request succeeded or failed if (response.ok()) { throw new Error( - `Expected connection failure, but got success with status ${response.status()}` + `Expected connection failure, but got success with status ${response.status()}`, ); } // Assert on the actual error code returned by the gateway // For mTLS, often 401, 403, or 502 depending on infra config expect(response.ok()).toBeFalsy(); - } catch (err: any) { + } catch (error: any) { // If the request truly fails at the TLS layer, Playwright will throw instead - expect(err.message).toMatch(/SSL|certificate|ECONNRESET|socket/i); + expect(error.message).toMatch(/SSL|certificate|ECONNRESET|socket/i); } finally { if (apiContext) { await apiContext.dispose(); diff --git a/tests/sandbox/get-letter-status.spec.ts b/tests/sandbox/get-letter-status.spec.ts index 173b6a1f..52401f71 100644 --- a/tests/sandbox/get-letter-status.spec.ts +++ b/tests/sandbox/get-letter-status.spec.ts @@ -20,7 +20,7 @@ test.describe("Sandbox Tests To Get Letter Status", () => { `${SUPPLIER_API_URL_SANDBOX}/${SUPPLIER_LETTERS}/${id}`, { headers: header, - } + }, ); expect(response.status()).toBe(expectedStatus); diff --git a/tests/sandbox/get-list-of-letters.spec.ts b/tests/sandbox/get-list-of-letters.spec.ts index 4132b40d..624a2227 100644 --- a/tests/sandbox/get-list-of-letters.spec.ts +++ b/tests/sandbox/get-list-of-letters.spec.ts @@ -21,7 +21,7 @@ test.describe("Sandbox Tests To Get List Of Pending Letters ", () => { params: { limit, }, - } + }, ); const res = await response.json(); diff --git a/tests/sandbox/update-letter-status.spec.ts b/tests/sandbox/update-letter-status.spec.ts index 996683a9..dcd724fd 100644 --- a/tests/sandbox/update-letter-status.spec.ts +++ b/tests/sandbox/update-letter-status.spec.ts @@ -20,7 +20,7 @@ test.describe("Sandbox Tests To Update Letter Status", () => { { headers: header, data: body, - } + }, ); const res = await response.json(); diff --git a/tests/sandbox/update-multiple-letter-status.spec.ts b/tests/sandbox/update-multiple-letter-status.spec.ts index c5ebba51..f7e30198 100644 --- a/tests/sandbox/update-multiple-letter-status.spec.ts +++ b/tests/sandbox/update-multiple-letter-status.spec.ts @@ -18,7 +18,7 @@ test.describe("Sandbox Tests To Update Multiple Letter Status", () => { { headers: header, data: body, - } + }, ); expect(response.status()).toBe(expectedStatus); });