@@ -7,15 +7,14 @@ import {
77 setupDynamoDBContainer ,
88} from "./db" ;
99import { LetterRepository } from "../letter-repository" ;
10- import { Letter } from "../types" ;
10+ import { InsertLetter , Letter , UpdateLetter , UpsertLetter } from "../types" ;
1111import { LogStream , createTestLogger } from "./logs" ;
12- import { LetterDto } from "../../../../lambdas/api-handler/src/contracts/letters" ;
1312
1413function createLetter (
1514 supplierId : string ,
1615 letterId : string ,
1716 status : Letter [ "status" ] = "PENDING" ,
18- ) : Omit < Letter , "ttl" | "supplierStatus" | "supplierStatusSk" > {
17+ ) : InsertLetter {
1918 return {
2019 id : letterId ,
2120 supplierId,
@@ -126,14 +125,14 @@ describe("LetterRepository", () => {
126125 await letterRepository . putLetter ( letter ) ;
127126 await checkLetterStatus ( "supplier1" , "letter1" , "PENDING" ) ;
128127
129- const letterDto : LetterDto = {
128+ const updateLetter : UpdateLetter = {
130129 id : "letter1" ,
131130 supplierId : "supplier1" ,
132131 status : "REJECTED" ,
133132 reasonCode : "R01" ,
134133 reasonText : "Reason text" ,
135134 } ;
136- await letterRepository . updateLetterStatus ( letterDto ) ;
135+ await letterRepository . updateLetterStatus ( updateLetter ) ;
137136
138137 const updatedLetter = await letterRepository . getLetterById (
139138 "supplier1" ,
@@ -159,7 +158,7 @@ describe("LetterRepository", () => {
159158 // Month is zero-indexed in JavaScript Date
160159 // Day is one-indexed
161160 jest . setSystemTime ( new Date ( 2020 , 1 , 2 ) ) ;
162- const letterDto : LetterDto = {
161+ const letterDto : UpdateLetter = {
163162 id : "letter1" ,
164163 supplierId : "supplier1" ,
165164 status : "DELIVERED" ,
@@ -175,13 +174,13 @@ describe("LetterRepository", () => {
175174 } ) ;
176175
177176 test ( "can't update a letter that does not exist" , async ( ) => {
178- const letterDto : LetterDto = {
177+ const updateLetter : UpdateLetter = {
179178 id : "letter1" ,
180179 supplierId : "supplier1" ,
181180 status : "DELIVERED" ,
182181 } ;
183182 await expect (
184- letterRepository . updateLetterStatus ( letterDto ) ,
183+ letterRepository . updateLetterStatus ( updateLetter ) ,
185184 ) . rejects . toThrow (
186185 "Letter with id letter1 not found for supplier supplier1" ,
187186 ) ;
@@ -193,13 +192,13 @@ describe("LetterRepository", () => {
193192 lettersTableName : "nonexistent-table" ,
194193 } ) ;
195194
196- const letterDto : LetterDto = {
195+ const updateLetter : UpdateLetter = {
197196 id : "letter1" ,
198197 supplierId : "supplier1" ,
199198 status : "DELIVERED" ,
200199 } ;
201200 await expect (
202- misconfiguredRepository . updateLetterStatus ( letterDto ) ,
201+ misconfiguredRepository . updateLetterStatus ( updateLetter ) ,
203202 ) . rejects . toThrow ( "Cannot do operations on a non-existent table" ) ;
204203 } ) ;
205204
@@ -238,12 +237,12 @@ describe("LetterRepository", () => {
238237 ) ;
239238 expect ( pendingLetters . letters ) . toHaveLength ( 2 ) ;
240239
241- const letterDto : LetterDto = {
240+ const updateLetter : UpdateLetter = {
242241 id : "letter1" ,
243242 supplierId : "supplier1" ,
244243 status : "DELIVERED" ,
245244 } ;
246- await letterRepository . updateLetterStatus ( letterDto ) ;
245+ await letterRepository . updateLetterStatus ( updateLetter ) ;
247246 const remainingLetters = await letterRepository . getLettersByStatus (
248247 "supplier1" ,
249248 "PENDING" ,
@@ -457,4 +456,119 @@ describe("LetterRepository", () => {
457456 ] ) ,
458457 ) . rejects . toThrow ( "Cannot do operations on a non-existent table" ) ;
459458 } ) ;
459+
460+ test ( "successful upsert (update status) returns updated letter" , async ( ) => {
461+ const insertLetter : InsertLetter = createLetter ( "supplier1" , "letter1" ) ;
462+
463+ const existingLetter = await letterRepository . putLetter ( insertLetter ) ;
464+
465+ const result = await letterRepository . upsertLetter ( {
466+ id : "letter1" ,
467+ supplierId : "supplier1" ,
468+ status : "REJECTED" ,
469+ reasonCode : "R01" ,
470+ reasonText : "R01 text" ,
471+ } ) ;
472+
473+ expect ( result ) . toEqual (
474+ expect . objectContaining ( {
475+ id : "letter1" ,
476+ status : "REJECTED" ,
477+ specificationId : "specification1" ,
478+ groupId : "group1" ,
479+ reasonCode : "R01" ,
480+ reasonText : "R01 text" ,
481+ supplierId : "supplier1" ,
482+ url : "s3://bucket/letter1.pdf" ,
483+ supplierStatus : "supplier1#REJECTED" ,
484+ } ) ,
485+ ) ;
486+ expect ( Date . parse ( result . updatedAt ) ) . toBeGreaterThan (
487+ Date . parse ( existingLetter . updatedAt ) ,
488+ ) ;
489+ expect ( Date . parse ( result . updatedAt ) ) . toBeLessThan ( Date . now ( ) ) ;
490+ expect ( result . createdAt ) . toBe ( existingLetter . createdAt ) ;
491+ expect ( result . createdAt ) . toBe ( result . supplierStatusSk ) ;
492+ expect ( result . ttl ) . toBe ( existingLetter . ttl ) ;
493+ } ) ;
494+
495+ test ( "successful upsert (insert) returns created letter" , async ( ) => {
496+ const upsertLetter : UpsertLetter = {
497+ id : "letter1" ,
498+ status : "PENDING" ,
499+ specificationId : "specification1" ,
500+ groupId : "group1" ,
501+ supplierId : "supplier1" ,
502+ url : "s3://bucket/letter1.pdf" ,
503+ } ;
504+
505+ const beforeInsert = Date . now ( ) - 1 ; // widen window
506+
507+ const result = await letterRepository . upsertLetter ( upsertLetter ) ;
508+
509+ expect ( result ) . toEqual (
510+ expect . objectContaining ( {
511+ id : "letter1" ,
512+ status : "PENDING" ,
513+ specificationId : "specification1" ,
514+ groupId : "group1" ,
515+ supplierId : "supplier1" ,
516+ url : "s3://bucket/letter1.pdf" ,
517+ } ) ,
518+ ) ;
519+
520+ expect ( Date . parse ( result . updatedAt ) ) . toBeGreaterThan ( beforeInsert ) ;
521+ expect ( Date . parse ( result . updatedAt ) ) . toBeLessThan ( Date . now ( ) ) ;
522+ expect ( result . createdAt ) . toBe ( result . updatedAt ) ;
523+ expect ( result . supplierStatusSk ) . toBe ( result . createdAt ) ;
524+ } ) ;
525+
526+ test ( "unsuccessful upsert should throw error" , async ( ) => {
527+ const mockSend = jest . fn ( ) . mockResolvedValue ( { Items : null } ) ;
528+ const mockDdbClient = { send : mockSend } as any ;
529+ const repo = new LetterRepository (
530+ mockDdbClient ,
531+ { debug : jest . fn ( ) } as any ,
532+ { lettersTableName : "letters" , lettersTtlHours : 1 } ,
533+ ) ;
534+
535+ await expect (
536+ repo . upsertLetter ( {
537+ id : "letter1" ,
538+ status : "PENDING" ,
539+ supplierId : "supplier1" ,
540+ } ) ,
541+ ) . rejects . toThrow ( "upsertLetter: no attributes returned" ) ;
542+ } ) ;
543+
544+ test ( "successful upsert without status" , async ( ) => {
545+ const insertLetter : InsertLetter = createLetter ( "supplier1" , "letter1" ) ;
546+
547+ const existingLetter = await letterRepository . putLetter ( insertLetter ) ;
548+
549+ const result = await letterRepository . upsertLetter ( {
550+ id : "letter1" ,
551+ supplierId : "supplier1" ,
552+ url : "s3://updatedBucket/letter1.pdf" ,
553+ } ) ;
554+
555+ expect ( result ) . toEqual (
556+ expect . objectContaining ( {
557+ id : "letter1" ,
558+ status : "PENDING" ,
559+ specificationId : "specification1" ,
560+ groupId : "group1" ,
561+ supplierId : "supplier1" ,
562+ url : "s3://updatedBucket/letter1.pdf" ,
563+ supplierStatus : "supplier1#PENDING" ,
564+ } ) ,
565+ ) ;
566+ expect ( Date . parse ( result . updatedAt ) ) . toBeGreaterThan (
567+ Date . parse ( existingLetter . updatedAt ) ,
568+ ) ;
569+ expect ( Date . parse ( result . updatedAt ) ) . toBeLessThan ( Date . now ( ) ) ;
570+ expect ( result . createdAt ) . toBe ( existingLetter . createdAt ) ;
571+ expect ( result . createdAt ) . toBe ( result . supplierStatusSk ) ;
572+ expect ( result . ttl ) . toBe ( existingLetter . ttl ) ;
573+ } ) ;
460574} ) ;
0 commit comments