Skip to content

Commit 928981a

Browse files
committed
CCM-11228: Enhance letter repository tests and error handling
1 parent 5d13c2c commit 928981a

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

internal/datastore/src/__test__/letter-repository.test.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,41 @@ describe('LetterRepository', () => {
6464

6565
test('adds a letter to the database', async () => {
6666
await letterRepository.putLetter(createLetter('supplier1', 'letter1'));
67-
6867
await checkLetterExists('supplier1', 'letter1');
6968
});
7069

70+
test('fetches a letter by id', async () => {
71+
await letterRepository.putLetter(createLetter('supplier1', 'letter1'));
72+
const letter = await letterRepository.getLetterById('supplier1', 'letter1');
73+
expect(letter).toEqual(expect.objectContaining({
74+
id: 'letter1',
75+
supplierId: 'supplier1',
76+
specificationId: 'specification1',
77+
groupId: 'group1',
78+
status: 'PENDING'
79+
}));
80+
});
81+
82+
test('throws an error when fetching a letter that does not exist', async () => {
83+
await expect(letterRepository.getLetterById('supplier1', 'letter1'))
84+
.rejects.toThrow("Letter with id letter1 not found for supplier supplier1");
85+
});
86+
87+
test('throws an error when creating a letter which already exists', async () => {
88+
await letterRepository.putLetter(createLetter('supplier1', 'letter1'));
89+
await expect(letterRepository.putLetter(createLetter('supplier1', 'letter1')))
90+
.rejects.toThrow("Letter with id letter1 already exists for supplier supplier1");
91+
});
92+
93+
test('rethrows errors from DynamoDB when creating a letter', async () => {
94+
const misconfiguredRepository = new LetterRepository(db.docClient, logger, {
95+
...db.config,
96+
lettersTableName: 'nonexistent-table'
97+
});
98+
await expect(misconfiguredRepository.putLetter(createLetter('supplier1', 'letter1')))
99+
.rejects.toThrow('Cannot do operations on a non-existent table');
100+
});
101+
71102
test('updates a letter\'s status in the database', async () => {
72103
await letterRepository.putLetter(createLetter('supplier1', 'letter1', 'PENDING'));
73104
await checkLetterStatus('supplier1', 'letter1', 'PENDING');
@@ -90,9 +121,17 @@ describe('LetterRepository', () => {
90121
});
91122

92123
test('can\t update a letter that does not exist', async () => {
93-
await expect(async () => {
94-
await letterRepository.updateLetterStatus('supplier1', 'letter1', 'DELIVERED');
95-
}).rejects.toThrow('Letter with id letter1 not found for supplier supplier1');
124+
await expect(letterRepository.updateLetterStatus('supplier1', 'letter1', 'DELIVERED'))
125+
.rejects.toThrow('Letter with id letter1 not found for supplier supplier1');
126+
});
127+
128+
test('update letter status rethrows errors from DynamoDB', async () => {
129+
const misconfiguredRepository = new LetterRepository(db.docClient, logger, {
130+
...db.config,
131+
lettersTableName: 'nonexistent-table'
132+
});
133+
await expect(misconfiguredRepository.updateLetterStatus(createLetter('supplier1', 'letter1', 'DELIVERED')))
134+
.rejects.toThrow('Cannot do operations on a non-existent table');
96135
});
97136

98137
test('should return a list of letters matching status', async () => {
@@ -145,6 +184,12 @@ describe('LetterRepository', () => {
145184
expect(secondPage.letters[48].id).toBe('letter099');
146185
});
147186

187+
test('letter list should return empty when no letters match status', async () => {
188+
const page = await letterRepository.getLettersByStatus('supplier1', 'PENDING');
189+
expect(page.letters).toHaveLength(0);
190+
expect(page.lastEvaluatedKey).toBeUndefined();
191+
});
192+
148193
test('letter list should warn about invalid data', async () => {
149194
await letterRepository.putLetter(createLetter('supplier1', 'letter1'));
150195
await db.docClient.send(new PutCommand({

internal/datastore/src/letter-repository.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,18 @@ export class LetterRepository {
2929
...letter,
3030
supplierStatus: `${letter.supplierId}#${letter.status}`
3131
};
32-
await this.ddbClient.send(new PutCommand({
33-
TableName: this.config.lettersTableName,
34-
Item: letterDb,
35-
ConditionExpression: 'attribute_not_exists(id)', // Ensure id is unique
36-
}));
37-
32+
try {
33+
await this.ddbClient.send(new PutCommand({
34+
TableName: this.config.lettersTableName,
35+
Item: letterDb,
36+
ConditionExpression: 'attribute_not_exists(id)', // Ensure id is unique
37+
}));
38+
} catch (error) {
39+
if (error instanceof Error && error.name === 'ConditionalCheckFailedException') {
40+
throw new Error(`Letter with id ${letter.id} already exists for supplier ${letter.supplierId}`);
41+
}
42+
throw error;
43+
}
3844
return letterDb;
3945
}
4046

@@ -73,11 +79,9 @@ export class LetterRepository {
7379
ExclusiveStartKey: extendedOptions.exclusiveStartKey
7480
}));
7581

76-
if (!result.Items) {
77-
throw new Error(`No letters found for supplier ${supplierId} with status ${status}`);
78-
}
7982
return {
80-
letters: result.Items.map(item => LetterSchema.safeParse(item))
83+
// Items is an empty array if no items match the query
84+
letters: result.Items!.map(item => LetterSchema.safeParse(item))
8185
.filter((result) => {
8286
if (!result.success) {
8387
this.log.warn(`Invalid letter data: ${result.error}`);
@@ -118,9 +122,6 @@ export class LetterRepository {
118122
throw error;
119123
}
120124

121-
if (!result.Attributes) {
122-
throw new Error(`Letter with id ${letterId} not found for supplier ${supplierId}`);
123-
}
124125
this.log.debug(`Updated letter ${letterId} to status ${status}`);
125126
return LetterSchema.parse(result.Attributes);
126127
}

0 commit comments

Comments
 (0)