Skip to content

Commit 5de86bb

Browse files
letter test data utility manual fixes
1 parent 5c2b284 commit 5de86bb

8 files changed

Lines changed: 104 additions & 170 deletions

File tree

package-lock.json

Lines changed: 1 addition & 152 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/utilities/letter-test-data/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"@aws-sdk/client-s3": "^3.858.0",
55
"@aws-sdk/lib-dynamodb": "^3.858.0",
66
"@internal/datastore": "*",
7+
"@jest/globals": "^30.2.0",
78
"esbuild": "^0.25.11",
89
"pino": "^9.7.0",
910
"yargs": "^17.7.2"

scripts/utilities/letter-test-data/src/__test__/helpers/create_letter_helpers.test.ts renamed to scripts/utilities/letter-test-data/src/__test__/helpers/create-letter-helpers.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { LetterStatusType } from "@internal/datastore";
33
import {
44
createLetter,
55
createLetterDto,
6-
} from "../../helpers/create_letter_helpers";
7-
import { uploadFile } from "../../helpers/s3_helpers";
6+
} from "../../helpers/create-letter-helpers";
7+
import uploadFile from "../../helpers/s3-helpers";
88

9-
jest.mock("../../helpers/s3_helpers");
9+
jest.mock("../../helpers/s3-helpers");
1010

1111
describe("Create letter helpers", () => {
1212
beforeEach(() => {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Unit tests for s3-helpers.ts
3+
*
4+
* Mocks:
5+
* - @aws-sdk/client-s3: S3Client (with send) and PutObjectCommand
6+
* - node:fs.readFileSync to avoid touching the filesystem
7+
*/
8+
9+
import * as s3Module from "@aws-sdk/client-s3";
10+
import uploadFile from "../../helpers/s3-helpers";
11+
12+
jest.mock("@aws-sdk/client-s3", () => {
13+
const sendMock = jest.fn();
14+
class PutObjectCommand {
15+
input: any;
16+
17+
constructor(input: any) {
18+
this.input = input;
19+
}
20+
}
21+
const S3Client = jest.fn().mockImplementation(() => ({ send: sendMock }));
22+
return {
23+
S3Client,
24+
PutObjectCommand,
25+
__sendMock: sendMock,
26+
__esModule: true,
27+
};
28+
});
29+
30+
jest.mock("node:fs", () => ({
31+
readFileSync: jest.fn().mockReturnValue(Buffer.from("fake-pdf-bytes")),
32+
}));
33+
34+
describe("uploadFile", () => {
35+
const bucket = "my-bucket";
36+
const supplierId = "supplier-1";
37+
const sourceFilename = "some.pdf";
38+
const targetFilename = "target.pdf";
39+
40+
beforeEach(() => {
41+
jest.clearAllMocks();
42+
});
43+
44+
it("calls S3Client.send with a PutObjectCommand containing correct params", async () => {
45+
const sendMock = (s3Module as any).__sendMock as jest.Mock;
46+
sendMock.mockResolvedValue({ ETag: '"etag-value"' });
47+
48+
await expect(
49+
uploadFile(bucket, supplierId, sourceFilename, targetFilename),
50+
).resolves.toBeDefined();
51+
52+
// S3Client is a mocked constructor — grab the instance that was created
53+
const S3ClientMock = (s3Module as any).S3Client as jest.Mock;
54+
expect(S3ClientMock).toHaveBeenCalled();
55+
56+
const instance = S3ClientMock.mock.results[0].value;
57+
expect(instance.send).toHaveBeenCalledTimes(1);
58+
59+
const calledWith = instance.send.mock.calls[0][0];
60+
// The mocked PutObjectCommand stores input as `input` property
61+
expect(calledWith).toHaveProperty("input");
62+
expect(calledWith.input).toEqual({
63+
Bucket: bucket,
64+
Key: `${supplierId}/${targetFilename}`,
65+
Body: Buffer.from("fake-pdf-bytes"),
66+
ContentType: "application/pdf",
67+
});
68+
});
69+
70+
it("logs and rethrows when S3Client.send rejects", async () => {
71+
const sendMock = (s3Module as any).__sendMock as jest.Mock;
72+
const err = new Error("upload-failed");
73+
sendMock.mockRejectedValueOnce(err);
74+
75+
const consoleSpy = jest
76+
.spyOn(console, "error")
77+
.mockImplementation(() => {});
78+
79+
await expect(
80+
uploadFile(bucket, supplierId, sourceFilename, targetFilename),
81+
).rejects.toThrow("upload-failed");
82+
83+
expect(consoleSpy).toHaveBeenCalledWith("Error uploading file:", err);
84+
85+
consoleSpy.mockRestore();
86+
});
87+
});

scripts/utilities/letter-test-data/src/cli/index.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { randomUUID } from "node:crypto";
55
import {
66
createLetter,
77
createLetterDto,
8-
} from "../helpers/create_letter_helpers";
9-
import { createLetterRepository } from "../infrastructure/letter-repo-factory";
10-
import { uploadFile } from "../helpers/s3_helpers";
8+
} from "../helpers/create-letter-helpers";
9+
import createLetterRepository from "../infrastructure/letter-repo-factory";
10+
import uploadFile from "../helpers/s3-helpers";
1111

1212
async function main() {
1313
await yargs(hideBin(process.argv))
@@ -64,13 +64,11 @@ async function main() {
6464
},
6565
async (argv) => {
6666
const { supplierId } = argv;
67-
const letterId = argv.letterId ? argv.letterId : randomUUID();
67+
const letterId = argv.letterId ?? randomUUID();
6868
const bucketName = `nhs-${argv.awsAccountId}-eu-west-2-${argv.environment}-supapi-test-letters`;
6969
const targetFilename = `${letterId}.pdf`;
70-
const groupId = argv.groupId ? argv.groupId : randomUUID();
71-
const specificationId = argv.specificationId
72-
? argv.specificationId
73-
: randomUUID();
70+
const groupId = argv.groupId ?? randomUUID();
71+
const specificationId = argv.specificationId ?? randomUUID();
7472
const { status } = argv;
7573
const { environment } = argv;
7674
const { ttlHours } = argv;
@@ -145,10 +143,8 @@ async function main() {
145143

146144
// parse args
147145
const { supplierId } = argv;
148-
const groupId = argv.groupId ? argv.groupId : randomUUID();
149-
const specificationId = argv.specificationId
150-
? argv.specificationId
151-
: randomUUID();
146+
const groupId = argv.groupId ?? randomUUID();
147+
const specificationId = argv.specificationId ?? randomUUID();
152148
const { status } = argv;
153149
const { environment } = argv;
154150
const { ttlHours } = argv;

scripts/utilities/letter-test-data/src/helpers/create_letter_helpers.ts renamed to scripts/utilities/letter-test-data/src/helpers/create-letter-helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
LetterRepository,
44
LetterStatusType,
55
} from "@internal/datastore";
6-
import { uploadFile } from "./s3_helpers";
6+
import uploadFile from "./s3-helpers";
77

88
export async function createLetter(params: {
99
letterId: string;

scripts/utilities/letter-test-data/src/helpers/s3_helpers.ts renamed to scripts/utilities/letter-test-data/src/helpers/s3-helpers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
22
import { readFileSync } from "node:fs";
33
import path from "node:path";
44

5-
export async function uploadFile(
5+
export default async function uploadFile(
66
bucketName: string,
77
supplierId: string,
88
sourceFilename: string,
@@ -24,5 +24,6 @@ export async function uploadFile(
2424
return await s3.send(command);
2525
} catch (error) {
2626
console.error("Error uploading file:", error);
27+
throw error;
2728
}
2829
}

scripts/utilities/letter-test-data/src/infrastructure/letter-repo-factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
33
import { pino } from "pino";
44
import { LetterRepository } from "@internal/datastore";
55

6-
export function createLetterRepository(
6+
export default function createLetterRepository(
77
environment: string,
88
ttlHours: number,
99
): LetterRepository {

0 commit comments

Comments
 (0)