From ddb2b77bcf857b3e54213b2468c095671af60381 Mon Sep 17 00:00:00 2001 From: James Gregory Date: Mon, 29 Nov 2021 21:39:19 +1100 Subject: [PATCH] feat(lambda): postConfirmation called in signUp If the PreSignUp trigger returns autoConfirmUser then also call the PostConfirmation trigger after the user has been saved --- src/targets/signUp.test.ts | 138 ++++++++++++++++++++++++++++++++----- src/targets/signUp.ts | 14 +++- 2 files changed, 133 insertions(+), 19 deletions(-) diff --git a/src/targets/signUp.test.ts b/src/targets/signUp.test.ts index fd30f16d..5e914a13 100644 --- a/src/targets/signUp.test.ts +++ b/src/targets/signUp.test.ts @@ -147,28 +147,130 @@ describe("SignUp target", () => { ).rejects.toBeInstanceOf(UserLambdaValidationError); }); - it("confirms the user if the lambda returns autoConfirmUser=true", async () => { - mockUserPoolService.getUserByUsername.mockResolvedValue(null); - mockTriggers.preSignUp.mockResolvedValue({ - autoConfirmUser: true, + describe("autoConfirmUser=true", () => { + beforeEach(() => { + mockUserPoolService.getUserByUsername.mockResolvedValue(null); + mockTriggers.preSignUp.mockResolvedValue({ + autoConfirmUser: true, + }); }); - await signUp({ - ClientId: "clientId", - ClientMetadata: { - client: "metadata", - }, - Password: "pwd", - Username: "user-supplied", - UserAttributes: [{ Name: "email", Value: "example@example.com" }], - ValidationData: [{ Name: "another", Value: "attribute" }], + it("confirms the user", async () => { + await signUp({ + ClientId: "clientId", + ClientMetadata: { + client: "metadata", + }, + Password: "pwd", + Username: "user-supplied", + UserAttributes: [{ Name: "email", Value: "example@example.com" }], + ValidationData: [{ Name: "another", Value: "attribute" }], + }); + + expect(mockUserPoolService.saveUser).toHaveBeenCalledWith( + expect.objectContaining({ + UserStatus: "CONFIRMED", + }) + ); }); - expect(mockUserPoolService.saveUser).toHaveBeenCalledWith( - expect.objectContaining({ - UserStatus: "CONFIRMED", - }) - ); + describe("when PostConfirmation trigger is enabled", () => { + beforeEach(() => { + mockTriggers.enabled.mockImplementation( + (trigger) => + trigger === "PreSignUp" || trigger === "PostConfirmation" + ); + }); + + it("calls the PostConfirmation trigger lambda", async () => { + await signUp({ + ClientId: "clientId", + ClientMetadata: { + client: "metadata", + }, + Password: "pwd", + Username: "user-supplied", + UserAttributes: [{ Name: "email", Value: "example@example.com" }], + ValidationData: [{ Name: "another", Value: "attribute" }], + }); + + expect(mockTriggers.postConfirmation).toHaveBeenCalledWith({ + clientId: "clientId", + clientMetadata: { + client: "metadata", + }, + source: "PostConfirmation_ConfirmSignUp", + userAttributes: [ + { Name: "sub", Value: expect.stringMatching(UUID) }, + { Name: "email", Value: "example@example.com" }, + ], + userPoolId: "test", + username: "user-supplied", + validationData: undefined, + }); + }); + + it("throws if the PostConfirmation lambda fails", async () => { + mockUserPoolService.getUserByUsername.mockResolvedValue(null); + mockTriggers.postConfirmation.mockRejectedValue( + new UserLambdaValidationError() + ); + + await expect( + signUp({ + ClientId: "clientId", + ClientMetadata: { + client: "metadata", + }, + Password: "pwd", + Username: "user-supplied", + UserAttributes: [{ Name: "email", Value: "example@example.com" }], + ValidationData: [{ Name: "another", Value: "attribute" }], + }) + ).rejects.toBeInstanceOf(UserLambdaValidationError); + }); + }); + }); + + describe("autoConfirmUser=false", () => { + beforeEach(() => { + mockUserPoolService.getUserByUsername.mockResolvedValue(null); + mockTriggers.preSignUp.mockResolvedValue({ + autoConfirmUser: false, + }); + }); + + it("does not confirm the user", async () => { + await signUp({ + ClientId: "clientId", + ClientMetadata: { + client: "metadata", + }, + Password: "pwd", + Username: "user-supplied", + UserAttributes: [{ Name: "email", Value: "example@example.com" }], + ValidationData: [{ Name: "another", Value: "attribute" }], + }); + + expect(mockUserPoolService.saveUser).toHaveBeenCalledWith( + expect.objectContaining({ + UserStatus: "UNCONFIRMED", + }) + ); + }); + + it("does not call the PostConfirmation trigger lambda", async () => { + mockUserPoolService.getUserByUsername.mockResolvedValue(null); + + await signUp({ + ClientId: "clientId", + Password: "pwd", + Username: "user-supplied", + UserAttributes: [{ Name: "email", Value: "example@example.com" }], + }); + + expect(mockTriggers.postConfirmation).not.toHaveBeenCalled(); + }); }); it("verifies the user's email if the lambda returns autoVerifyEmail=true and the user has an email attribute", async () => { diff --git a/src/targets/signUp.ts b/src/targets/signUp.ts index feab5e82..3e37a3b6 100644 --- a/src/targets/signUp.ts +++ b/src/targets/signUp.ts @@ -166,7 +166,19 @@ export const SignUp = ConfirmationCode: code, }); - // TODO: call PostConfirmation if PreSignUp confirms auto confirms the user + if ( + user.UserStatus === "CONFIRMED" && + triggers.enabled("PostConfirmation") + ) { + await triggers.postConfirmation({ + clientId: req.ClientId, + clientMetadata: req.ClientMetadata, + source: "PostConfirmation_ConfirmSignUp", + userAttributes: user.Attributes, + username: user.Username, + userPoolId: userPool.config.Id, + }); + } return { CodeDeliveryDetails: deliveryDetails ?? undefined,