import { Verification } from "verification" ; import { chance } from "_/helpers" ; import { mockDynamoDBDocumentClientDeleteWithError , mockDynamoDBDocumentClientDeleteWithResult , mockDynamoDBDocumentClientDeleteWithoutResult , mockDynamoDBDocumentClientPutWithError , mockDynamoDBDocumentClientPutWithSuccess , mockSNSPublishWithError , mockSNSPublishWithSuccess , restoreDynamoDBDocumentClientDelete , restoreDynamoDBDocumentClientPut , restoreSNSPublish } from "_/mocks/vendor/aws-sdk" ; import { mockVerificationCode , mockVerificationContext } from "_/mocks/verification" ; describe ( "verification" , ( ) => { describe ( "Verification" , ( ) => { describe ( "#issue" , ( ) => { const subject = chance . guid ( ) ; const context = mockVerificationContext ( ) ; afterEach ( ( ) => { restoreDynamoDBDocumentClientPut ( ) ; restoreSNSPublish ( ) ; } ) ; it ( "should resolve with verification code" , async ( ) => { mockDynamoDBDocumentClientPutWithSuccess ( ) ; mockSNSPublishWithSuccess ( ) ; const verification = new Verification ( ) ; const code = await verification . issue ( context , subject ) ; expect ( code . id ) . toMatch ( /^[a-f0-9]{32}$/ ) ; expect ( code . context ) . toEqual ( context ) ; expect ( code . subject ) . toEqual ( subject ) ; expect ( code . expires ) . toBeGreaterThan ( 0 ) ; } ) ; it ( "should set expiry date to 24 hours from now" , async ( ) => { mockDynamoDBDocumentClientPutWithSuccess ( ) ; mockSNSPublishWithSuccess ( ) ; const verification = new Verification ( ) ; const code = await verification . issue ( context , subject ) ; expect ( code . expires ) . toBeGreaterThanOrEqual ( Math . floor ( Date . now ( ) / 1000 ) + 59 * 60 * 24 ) ; } ) ; it ( "should store verification code in AWS DynamoDB" , async ( ) => { const putMock = mockDynamoDBDocumentClientPutWithSuccess ( ) ; mockSNSPublishWithSuccess ( ) ; const verification = new Verification ( ) ; const code = await verification . issue ( context , subject ) ; expect ( putMock ) . toHaveBeenCalledWith ( { TableName : jasmine . any ( String ) , Item : code } ) ; } ) ; it ( "should publish verification code via AWS SNS" , async ( ) => { mockDynamoDBDocumentClientPutWithSuccess ( ) ; const publishMock = mockSNSPublishWithSuccess ( ) ; const verification = new Verification ( ) ; const code = await verification . issue ( context , subject ) ; expect ( publishMock ) . toHaveBeenCalledWith ( { TopicArn : jasmine . any ( String ) , Message : JSON . stringify ( code ) } ) ; } ) ; it ( "should reject on AWS DynamoDB error" , async ( done ) => { const errMock = new Error ( ) ; const putMock = mockDynamoDBDocumentClientPutWithError ( errMock ) ; mockSNSPublishWithSuccess ( ) ; try { const verification = new Verification ( ) ; await verification . issue ( context , subject ) ; done . fail ( ) ; } catch ( err ) { expect ( putMock ) . toHaveBeenCalled ( ) ; expect ( err ) . toBe ( errMock ) ; done ( ) ; } } ) ; it ( "should reject on AWS SNS error" , async ( done ) => { const errMock = new Error ( ) ; mockDynamoDBDocumentClientPutWithSuccess ( ) ; const publishMock = mockSNSPublishWithError ( errMock ) ; try { const verification = new Verification ( ) ; await verification . issue ( context , subject ) ; done . fail ( ) ; } catch ( err ) { expect ( publishMock ) . toHaveBeenCalled ( ) ; expect ( err ) . toBe ( errMock ) ; done ( ) ; } } ) ; } ) ; describe ( "#claim" , ( ) => { const code = mockVerificationCode ( ) ; afterEach ( ( ) => { restoreDynamoDBDocumentClientDelete ( ) ; } ) ; it ( "should resolve with verification code" , async ( ) => { mockDynamoDBDocumentClientDeleteWithResult ( code ) ; const verification = new Verification ( ) ; expect ( await verification . claim ( code . context , code . id ) ) . toEqual ( code ) ; } ) ; it ( "should delete verification code from DynamoDB" , async ( ) => { const deleteMock = mockDynamoDBDocumentClientDeleteWithResult ( code ) ; const verification = new Verification ( ) ; await verification . claim ( code . context , code . id ) ; expect ( deleteMock ) . toHaveBeenCalledWith ( { TableName : jasmine . any ( String ) , Key : { id : code . id } , ReturnValues : "ALL_OLD" } ) ; } ) ; it ( "should reject on invalid verification code" , async ( done ) => { const deleteMock = mockDynamoDBDocumentClientDeleteWithoutResult ( ) ; try { const verification = new Verification ( ) ; await verification . claim ( code . context , code . id ) ; done . fail ( ) ; } catch ( err ) { expect ( deleteMock ) . toHaveBeenCalled ( ) ; expect ( err ) . toEqual ( new Error ( "Invalid verification code" ) ) ; done ( ) ; } } ) ; it ( "should reject on invalid verification context" , async ( done ) => { const deleteMock = mockDynamoDBDocumentClientDeleteWithResult ( mockVerificationCode ( "register" ) ) ; try { const verification = new Verification ( ) ; await verification . claim ( "reset" , code . id ) ; done . fail ( ) ; } catch ( err ) { expect ( deleteMock ) . toHaveBeenCalled ( ) ; expect ( err ) . toEqual ( new Error ( "Invalid verification code" ) ) ; done ( ) ; } } ) ; it ( "should reject on AWS DynamoDB error" , async ( done ) => { const errMock = new Error ( ) ; const deleteMock = mockDynamoDBDocumentClientDeleteWithError ( errMock ) ; try { const verification = new Verification ( ) ; await verification . claim ( code . context , code . id ) ; done . fail ( ) ; } catch ( err ) { expect ( deleteMock ) . toHaveBeenCalled ( ) ; expect ( err ) . toBe ( errMock ) ; done ( ) ; } } ) ; } ) ; } ) ; } ) ;