From c3dc0921ae116a356a9bee39df461795285f7c6b Mon Sep 17 00:00:00 2001 From: James Gregory Date: Wed, 24 Nov 2021 22:10:09 +1100 Subject: [PATCH] feat(api): createGroup support --- README.md | 1 + integration-tests/aws-sdk/createGroup.test.ts | 65 ++++++++++++++ src/__tests__/mockUserPoolClient.ts | 17 ++++ src/services/triggers/customMessage.test.ts | 15 +--- .../triggers/postConfirmation.test.ts | 15 +--- src/services/triggers/userMigration.test.ts | 15 +--- src/services/userPoolClient.test.ts | 89 +++++++++++++++++++ src/services/userPoolClient.ts | 45 ++++++++++ src/targets/confirmForgotPassword.test.ts | 29 +++--- src/targets/confirmSignUp.test.ts | 29 +++--- src/targets/createGroup.test.ts | 57 ++++++++++++ src/targets/createGroup.ts | 43 +++++++++ src/targets/createUserPoolClient.test.ts | 21 ++--- src/targets/describeUserPoolClient.test.ts | 17 +--- src/targets/forgotPassword.test.ts | 30 ++----- src/targets/getUser.test.ts | 21 ++--- src/targets/initiateAuth.test.ts | 44 ++++----- src/targets/listUsers.test.ts | 19 ++-- src/targets/respondToAuthChallenge.test.ts | 23 ++--- src/targets/router.ts | 2 + src/targets/signUp.test.ts | 28 ++---- 21 files changed, 410 insertions(+), 215 deletions(-) create mode 100644 integration-tests/aws-sdk/createGroup.test.ts create mode 100644 src/__tests__/mockUserPoolClient.ts create mode 100644 src/targets/createGroup.test.ts create mode 100644 src/targets/createGroup.ts diff --git a/README.md b/README.md index 944fd01b..a7e5a8dc 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ A _Good Enough_ offline emulator for [Amazon Cognito](https://aws.amazon.com/cog - [ChangePassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ChangePassword.html) (community contributed, incomplete) - [ConfirmForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html) - [ConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmSignUp.html) +- [CreateGroup](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateGroup.html) - [CreateUserPoolClient](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html) - [DescribeUserPoolClient](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_DescribeUserPoolClient.html) - [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html) diff --git a/integration-tests/aws-sdk/createGroup.test.ts b/integration-tests/aws-sdk/createGroup.test.ts new file mode 100644 index 00000000..025d8533 --- /dev/null +++ b/integration-tests/aws-sdk/createGroup.test.ts @@ -0,0 +1,65 @@ +import { ClockFake } from "../../src/__tests__/clockFake"; +import { UUID } from "../../src/__tests__/patterns"; +import { withCognitoSdk } from "./setup"; + +const currentDate = new Date(); +const roundedDate = new Date(currentDate.getTime()); +roundedDate.setMilliseconds(0); + +const clock = new ClockFake(currentDate); + +describe( + "CognitoIdentityServiceProvider.createGroup", + withCognitoSdk( + (Cognito) => { + it("creates a group with only the required parameters", async () => { + const client = Cognito(); + + const createGroupResult = await client + .createGroup({ + GroupName: "abc", + UserPoolId: "test", + }) + .promise(); + + expect(createGroupResult).toEqual({ + Group: { + CreationDate: roundedDate, + GroupName: "abc", + LastModifiedDate: roundedDate, + UserPoolId: "test", + }, + }); + }); + + it("creates a group with all parameters", async () => { + const client = Cognito(); + + const createGroupResult = await client + .createGroup({ + Description: "Description", + GroupName: "abc", + Precedence: 1, + RoleArn: "arn", + UserPoolId: "test", + }) + .promise(); + + expect(createGroupResult).toEqual({ + Group: { + CreationDate: roundedDate, + Description: "Description", + GroupName: "abc", + LastModifiedDate: roundedDate, + Precedence: 1, + RoleArn: "arn", + UserPoolId: "test", + }, + }); + }); + }, + { + clock, + } + ) +); diff --git a/src/__tests__/mockUserPoolClient.ts b/src/__tests__/mockUserPoolClient.ts new file mode 100644 index 00000000..fa1abfe2 --- /dev/null +++ b/src/__tests__/mockUserPoolClient.ts @@ -0,0 +1,17 @@ +import { UserPoolClient } from "../services"; + +export const MockUserPoolClient = { + config: { + Id: "test", + } as Record, + createAppClient: jest.fn() as jest.MockedFunction< + UserPoolClient["createAppClient"] + >, + getUserByUsername: jest.fn() as jest.MockedFunction< + UserPoolClient["getUserByUsername"] + >, + listUsers: jest.fn() as jest.MockedFunction, + saveUser: jest.fn() as jest.MockedFunction, + listGroups: jest.fn() as jest.MockedFunction, + saveGroup: jest.fn() as jest.MockedFunction, +}; diff --git a/src/services/triggers/customMessage.test.ts b/src/services/triggers/customMessage.test.ts index ca073dc1..fc06b059 100644 --- a/src/services/triggers/customMessage.test.ts +++ b/src/services/triggers/customMessage.test.ts @@ -1,4 +1,5 @@ import { MockLogger } from "../../__tests__/mockLogger"; +import { MockUserPoolClient } from "../../__tests__/mockUserPoolClient"; import { CognitoClient } from "../cognitoClient"; import { Lambda } from "../lambda"; import { UserPoolClient } from "../userPoolClient"; @@ -7,7 +8,6 @@ import { CustomMessage, CustomMessageTrigger } from "./customMessage"; describe("CustomMessage trigger", () => { let mockLambda: jest.Mocked; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let customMessage: CustomMessageTrigger; beforeEach(() => { @@ -15,19 +15,10 @@ describe("CustomMessage trigger", () => { enabled: jest.fn(), invoke: jest.fn(), }; - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; customMessage = CustomMessage( diff --git a/src/services/triggers/postConfirmation.test.ts b/src/services/triggers/postConfirmation.test.ts index 80d34738..511b04dc 100644 --- a/src/services/triggers/postConfirmation.test.ts +++ b/src/services/triggers/postConfirmation.test.ts @@ -1,4 +1,5 @@ import { MockLogger } from "../../__tests__/mockLogger"; +import { MockUserPoolClient } from "../../__tests__/mockUserPoolClient"; import { Lambda } from "../lambda"; import { UserPoolClient } from "../userPoolClient"; import { PostConfirmation, PostConfirmationTrigger } from "./postConfirmation"; @@ -7,7 +8,6 @@ import { CognitoClient } from "../cognitoClient"; describe("PostConfirmation trigger", () => { let mockLambda: jest.Mocked; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let postConfirmation: PostConfirmationTrigger; beforeEach(() => { @@ -15,19 +15,10 @@ describe("PostConfirmation trigger", () => { enabled: jest.fn(), invoke: jest.fn(), }; - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; postConfirmation = PostConfirmation( { diff --git a/src/services/triggers/userMigration.test.ts b/src/services/triggers/userMigration.test.ts index 0688a206..1f4104eb 100644 --- a/src/services/triggers/userMigration.test.ts +++ b/src/services/triggers/userMigration.test.ts @@ -1,3 +1,4 @@ +import { MockUserPoolClient } from "../../__tests__/mockUserPoolClient"; import { UUID } from "../../__tests__/patterns"; import { NotAuthorizedError } from "../../errors"; import { DateClock } from "../clock"; @@ -9,7 +10,6 @@ import { UserMigration, UserMigrationTrigger } from "./userMigration"; describe("UserMigration trigger", () => { let mockLambda: jest.Mocked; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let userMigration: UserMigrationTrigger; beforeEach(() => { @@ -17,19 +17,10 @@ describe("UserMigration trigger", () => { enabled: jest.fn(), invoke: jest.fn(), }; - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; userMigration = UserMigration({ diff --git a/src/services/userPoolClient.test.ts b/src/services/userPoolClient.test.ts index f69a7192..50932883 100644 --- a/src/services/userPoolClient.test.ts +++ b/src/services/userPoolClient.test.ts @@ -10,6 +10,7 @@ import { User, UserPoolClient, UserPoolClientService, + Group, } from "./userPoolClient"; describe("User Pool Client", () => { @@ -358,4 +359,92 @@ describe("User Pool Client", () => { }); }); }); + + describe("saveGroup", () => { + it("saves the group", async () => { + const now = new Date().getTime(); + const set = jest.fn(); + + const userPool = await UserPoolClientService.create( + mockClientsDataStore, + clock, + () => + Promise.resolve({ + set, + get: jest.fn(), + getRoot: jest.fn(), + }), + { Id: "local", UsernameAttributes: [] }, + MockLogger + ); + + await userPool.saveGroup({ + CreationDate: now, + Description: "Description", + GroupName: "theGroupName", + LastModifiedDate: now, + Precedence: 1, + RoleArn: "ARN", + }); + + expect(set).toHaveBeenCalledWith(["Groups", "theGroupName"], { + CreationDate: now, + Description: "Description", + GroupName: "theGroupName", + LastModifiedDate: now, + Precedence: 1, + RoleArn: "ARN", + }); + }); + }); + + describe("listGroups", () => { + let userPool: UserPoolClient; + + beforeEach(async () => { + const options = { + Id: "local", + }; + const groups: Record = { + theGroupName: { + CreationDate: new Date().getTime(), + Description: "Description", + GroupName: "theGroupName", + LastModifiedDate: new Date().getTime(), + Precedence: 1, + RoleArn: "ARN", + }, + }; + + const get = jest.fn((key) => { + if (key === "Groups") { + return Promise.resolve(groups); + } else if (key === "Options") { + return Promise.resolve(options); + } + + return Promise.resolve(null); + }); + userPool = await UserPoolClientService.create( + mockClientsDataStore, + clock, + () => + Promise.resolve({ + set: jest.fn(), + get, + getRoot: jest.fn(), + }), + options, + MockLogger + ); + }); + + it("returns existing groups", async () => { + const groups = await userPool.listGroups(); + + expect(groups).not.toBeNull(); + expect(groups).toHaveLength(1); + expect(groups[0].GroupName).toEqual("theGroupName"); + }); + }); }); diff --git a/src/services/userPoolClient.ts b/src/services/userPoolClient.ts index a981dde4..9e526938 100644 --- a/src/services/userPoolClient.ts +++ b/src/services/userPoolClient.ts @@ -55,6 +55,33 @@ export interface User { MFACode?: string; } +export interface Group { + /** + * The name of the group. + */ + GroupName: string; + /** + * A string containing the description of the group. + */ + Description?: string; + /** + * The role ARN for the group. + */ + RoleArn?: string; + /** + * A nonnegative integer value that specifies the precedence of this group relative to the other groups that a user can belong to in the user pool. If a user belongs to two or more groups, it is the group with the highest precedence whose role ARN will be used in the cognito:roles and cognito:preferred_role claims in the user's tokens. Groups with higher Precedence values take precedence over groups with lower Precedence values or with null Precedence values. Two groups can have the same Precedence value. If this happens, neither group takes precedence over the other. If two groups with the same Precedence have the same role ARN, that role is used in the cognito:preferred_role claim in tokens for users in each group. If the two groups have different role ARNs, the cognito:preferred_role claim is not set in users' tokens. The default Precedence value is null. + */ + Precedence?: number; + /** + * The date the group was last modified. + */ + LastModifiedDate: number; + /** + * The date the group was created. + */ + CreationDate: number; +} + type UsernameAttribute = "email" | "phone_number"; export interface UserPool { @@ -70,6 +97,8 @@ export interface UserPoolClient { getUserByUsername(username: string): Promise; listUsers(): Promise; saveUser(user: User): Promise; + listGroups(): Promise; + saveGroup(group: Group): Promise; } export type CreateUserPoolClient = ( @@ -193,4 +222,20 @@ export class UserPoolClientService implements UserPoolClient { await this.dataStore.set(["Users", user.Username], user); } + + async listGroups(): Promise { + this.logger.debug("listGroups"); + const groups = await this.dataStore.get>( + "Groups", + {} + ); + + return Object.values(groups); + } + + async saveGroup(group: Group) { + this.logger.debug("saveGroup", group); + + await this.dataStore.set(["Groups", group.GroupName], group); + } } diff --git a/src/targets/confirmForgotPassword.test.ts b/src/targets/confirmForgotPassword.test.ts index 2a30d9d1..54791747 100644 --- a/src/targets/confirmForgotPassword.test.ts +++ b/src/targets/confirmForgotPassword.test.ts @@ -1,6 +1,7 @@ import { ClockFake } from "../__tests__/clockFake"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { CodeMismatchError, UserNotFoundError } from "../errors"; -import { CognitoClient, UserPoolClient, Triggers } from "../services"; +import { CognitoClient, Triggers } from "../services"; import { ConfirmForgotPassword, ConfirmForgotPasswordTarget, @@ -9,7 +10,6 @@ import { describe("ConfirmForgotPassword target", () => { let confirmForgotPassword: ConfirmForgotPasswordTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let mockTriggers: jest.Mocked; const currentDate = new Date(2020, 1, 2, 3, 4, 5); @@ -18,19 +18,10 @@ describe("ConfirmForgotPassword target", () => { beforeEach(() => { clock = new ClockFake(currentDate); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; mockTriggers = { enabled: jest.fn(), @@ -47,7 +38,7 @@ describe("ConfirmForgotPassword target", () => { }); it("throws if user doesn't exist", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await expect( confirmForgotPassword({ @@ -60,7 +51,7 @@ describe("ConfirmForgotPassword target", () => { }); it("throws if confirmation code doesn't match stored value", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, @@ -83,7 +74,7 @@ describe("ConfirmForgotPassword target", () => { describe("when code matches", () => { it("updates the user's password", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, @@ -104,7 +95,7 @@ describe("ConfirmForgotPassword target", () => { Password: "newPassword", }); - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: undefined, Enabled: true, @@ -120,7 +111,7 @@ describe("ConfirmForgotPassword target", () => { it("invokes the trigger", async () => { mockTriggers.enabled.mockReturnValue(true); - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, @@ -157,7 +148,7 @@ describe("ConfirmForgotPassword target", () => { it("doesn't invoke the trigger", async () => { mockTriggers.enabled.mockReturnValue(false); - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, diff --git a/src/targets/confirmSignUp.test.ts b/src/targets/confirmSignUp.test.ts index e3f21805..17cb01fb 100644 --- a/src/targets/confirmSignUp.test.ts +++ b/src/targets/confirmSignUp.test.ts @@ -1,12 +1,12 @@ import { ClockFake } from "../__tests__/clockFake"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { CodeMismatchError, NotAuthorizedError } from "../errors"; -import { CognitoClient, Triggers, UserPoolClient } from "../services"; +import { CognitoClient, Triggers } from "../services"; import { ConfirmSignUp, ConfirmSignUpTarget } from "./confirmSignUp"; describe("ConfirmSignUp target", () => { let confirmSignUp: ConfirmSignUpTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let mockTriggers: jest.Mocked; let clock: ClockFake; @@ -15,19 +15,10 @@ describe("ConfirmSignUp target", () => { beforeEach(() => { clock = new ClockFake(originalDate); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; mockTriggers = { enabled: jest.fn(), @@ -44,7 +35,7 @@ describe("ConfirmSignUp target", () => { }); it("throws if user doesn't exist", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await expect( confirmSignUp({ @@ -57,7 +48,7 @@ describe("ConfirmSignUp target", () => { }); it("throws if confirmation code doesn't match stored value", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, @@ -80,7 +71,7 @@ describe("ConfirmSignUp target", () => { describe("when code matches", () => { it("updates the user's confirmed status", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, @@ -101,7 +92,7 @@ describe("ConfirmSignUp target", () => { ForceAliasCreation: false, }); - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: undefined, Enabled: true, @@ -117,7 +108,7 @@ describe("ConfirmSignUp target", () => { it("invokes the trigger", async () => { mockTriggers.enabled.mockReturnValue(true); - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, @@ -154,7 +145,7 @@ describe("ConfirmSignUp target", () => { it("doesn't invoke the trigger", async () => { mockTriggers.enabled.mockReturnValue(false); - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "4567", Enabled: true, diff --git a/src/targets/createGroup.test.ts b/src/targets/createGroup.test.ts new file mode 100644 index 00000000..3c77d39a --- /dev/null +++ b/src/targets/createGroup.test.ts @@ -0,0 +1,57 @@ +import { ClockFake } from "../__tests__/clockFake"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; +import { CognitoClient } from "../services"; +import { CreateGroup, CreateGroupTarget } from "./createGroup"; + +describe("CreateGroup target", () => { + let createGroup: CreateGroupTarget; + let mockCognitoClient: jest.Mocked; + let clock: ClockFake; + + const originalDate = new Date(2020, 1, 2, 3, 4, 5); + + beforeEach(() => { + clock = new ClockFake(originalDate); + + mockCognitoClient = { + getAppClient: jest.fn(), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), + }; + + createGroup = CreateGroup({ + clock, + cognitoClient: mockCognitoClient, + }); + }); + + it("creates a group", async () => { + MockUserPoolClient.getUserByUsername.mockResolvedValue({ + Attributes: [{ Name: "email", Value: "example@example.com" }], + ConfirmationCode: "4567", + Enabled: true, + Password: "pwd", + UserCreateDate: originalDate.getTime(), + UserLastModifiedDate: originalDate.getTime(), + UserStatus: "UNCONFIRMED", + Username: "0000-0000", + }); + + await createGroup({ + Description: "Description", + GroupName: "theGroupName", + Precedence: 1, + RoleArn: "ARN", + UserPoolId: "test", + }); + + expect(MockUserPoolClient.saveGroup).toHaveBeenCalledWith({ + CreationDate: originalDate.getTime(), + Description: "Description", + GroupName: "theGroupName", + LastModifiedDate: originalDate.getTime(), + Precedence: 1, + RoleArn: "ARN", + }); + }); +}); diff --git a/src/targets/createGroup.ts b/src/targets/createGroup.ts new file mode 100644 index 00000000..7d6b238a --- /dev/null +++ b/src/targets/createGroup.ts @@ -0,0 +1,43 @@ +import { + CreateGroupRequest, + CreateGroupResponse, +} from "aws-sdk/clients/cognitoidentityserviceprovider"; +import { Services } from "../services"; +import { Group } from "../services/userPoolClient"; + +export type CreateGroupTarget = ( + body: CreateGroupRequest +) => Promise; + +type CreateGroupServices = Pick; + +export const CreateGroup = ({ + cognitoClient, + clock, +}: CreateGroupServices): CreateGroupTarget => async (req) => { + const userPool = await cognitoClient.getUserPool(req.UserPoolId); + + const now = clock.get().getTime(); + const group: Group = { + CreationDate: now, + Description: req.Description, + GroupName: req.GroupName, + LastModifiedDate: now, + Precedence: req.Precedence, + RoleArn: req.RoleArn, + }; + + await userPool.saveGroup(group); + + return { + Group: { + CreationDate: new Date(group.CreationDate), + Description: group.Description, + GroupName: group.GroupName, + LastModifiedDate: new Date(group.LastModifiedDate), + Precedence: group.Precedence, + RoleArn: group.RoleArn, + UserPoolId: req.UserPoolId, + }, + }; +}; diff --git a/src/targets/createUserPoolClient.test.ts b/src/targets/createUserPoolClient.test.ts index 657eee17..65655b04 100644 --- a/src/targets/createUserPoolClient.test.ts +++ b/src/targets/createUserPoolClient.test.ts @@ -1,5 +1,6 @@ import { advanceTo } from "jest-date-mock"; -import { CognitoClient, UserPoolClient } from "../services"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; +import { CognitoClient } from "../services"; import { AppClient } from "../services/appClient"; import { CreateUserPoolClient, @@ -9,26 +10,16 @@ import { describe("CreateUserPoolClient target", () => { let createUserPoolClient: CreateUserPoolClientTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let now: Date; beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); advanceTo(now); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; createUserPoolClient = CreateUserPoolClient({ @@ -46,14 +37,14 @@ describe("CreateUserPoolClient target", () => { ClientId: "abc", ClientName: "clientName", }; - mockUserPoolClient.createAppClient.mockResolvedValue(createdAppClient); + MockUserPoolClient.createAppClient.mockResolvedValue(createdAppClient); const result = await createUserPoolClient({ ClientName: "clientName", UserPoolId: "userPoolId", }); - expect(mockUserPoolClient.createAppClient).toHaveBeenCalledWith( + expect(MockUserPoolClient.createAppClient).toHaveBeenCalledWith( "clientName" ); diff --git a/src/targets/describeUserPoolClient.test.ts b/src/targets/describeUserPoolClient.test.ts index 1084ecd6..dbd723c6 100644 --- a/src/targets/describeUserPoolClient.test.ts +++ b/src/targets/describeUserPoolClient.test.ts @@ -1,6 +1,7 @@ import { advanceTo } from "jest-date-mock"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { ResourceNotFoundError } from "../errors"; -import { CognitoClient, UserPoolClient } from "../services"; +import { CognitoClient } from "../services"; import { AppClient } from "../services/appClient"; import { DescribeUserPoolClient, @@ -10,26 +11,16 @@ import { describe("DescribeUserPoolClient target", () => { let describeUserPoolClient: DescribeUserPoolClientTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let now: Date; beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); advanceTo(now); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; describeUserPoolClient = DescribeUserPoolClient({ diff --git a/src/targets/forgotPassword.test.ts b/src/targets/forgotPassword.test.ts index 99d3b183..a3f4325c 100644 --- a/src/targets/forgotPassword.test.ts +++ b/src/targets/forgotPassword.test.ts @@ -1,17 +1,12 @@ import { ClockFake } from "../__tests__/clockFake"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { UserNotFoundError } from "../errors"; -import { - CognitoClient, - UserPoolClient, - Messages, - MessageDelivery, -} from "../services"; +import { CognitoClient, Messages, MessageDelivery } from "../services"; import { ForgotPassword, ForgotPasswordTarget } from "./forgotPassword"; describe("ForgotPassword target", () => { let forgotPassword: ForgotPasswordTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let mockMessageDelivery: jest.Mocked; let mockMessages: jest.Mocked; let mockOtp: jest.MockedFunction<() => string>; @@ -20,19 +15,10 @@ describe("ForgotPassword target", () => { beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; mockMessageDelivery = { deliver: jest.fn(), @@ -56,7 +42,7 @@ describe("ForgotPassword target", () => { }); it("throws if user doesn't exist", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await expect( forgotPassword({ @@ -67,7 +53,7 @@ describe("ForgotPassword target", () => { }); it("sends a confirmation code to the user's email address", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], Enabled: true, Password: "hunter2", @@ -110,7 +96,7 @@ describe("ForgotPassword target", () => { }); it("saves the confirmation code on the user for comparison when confirming", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [{ Name: "email", Value: "example@example.com" }], Enabled: true, Password: "hunter2", @@ -125,7 +111,7 @@ describe("ForgotPassword target", () => { Username: "0000-0000", }); - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ Attributes: [{ Name: "email", Value: "example@example.com" }], ConfirmationCode: "1234", Enabled: true, diff --git a/src/targets/getUser.test.ts b/src/targets/getUser.test.ts index b4f85840..538743f3 100644 --- a/src/targets/getUser.test.ts +++ b/src/targets/getUser.test.ts @@ -2,34 +2,25 @@ import { advanceTo } from "jest-date-mock"; import jwt from "jsonwebtoken"; import * as uuid from "uuid"; import { MockLogger } from "../__tests__/mockLogger"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { InvalidParameterError, UserNotFoundError } from "../errors"; import PrivateKey from "../keys/cognitoLocal.private.json"; -import { CognitoClient, UserPoolClient } from "../services"; +import { CognitoClient } from "../services"; import { GetUser, GetUserTarget } from "./getUser"; describe("GetUser target", () => { let getUser: GetUserTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let now: Date; beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); advanceTo(now); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; getUser = GetUser( @@ -41,7 +32,7 @@ describe("GetUser target", () => { }); it("parses token get user by sub", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [], UserStatus: "CONFIRMED", Password: "hunter2", @@ -90,7 +81,7 @@ describe("GetUser target", () => { }); it("throws if user doesn't exist", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await expect( getUser({ diff --git a/src/targets/initiateAuth.test.ts b/src/targets/initiateAuth.test.ts index 7d00728e..9c94e908 100644 --- a/src/targets/initiateAuth.test.ts +++ b/src/targets/initiateAuth.test.ts @@ -1,5 +1,6 @@ import jwt from "jsonwebtoken"; import { ClockFake } from "../__tests__/clockFake"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { UUID } from "../__tests__/patterns"; import { InvalidPasswordError, @@ -9,7 +10,6 @@ import { import PublicKey from "../keys/cognitoLocal.public.json"; import { CognitoClient, - UserPoolClient, Messages, Triggers, MessageDelivery, @@ -20,7 +20,6 @@ import { InitiateAuth, InitiateAuthTarget } from "./initiateAuth"; describe("InitiateAuth target", () => { let initiateAuth: InitiateAuthTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let mockMessageDelivery: jest.Mocked; let mockMessages: jest.Mocked; let mockOtp: jest.MockedFunction<() => string>; @@ -30,19 +29,10 @@ describe("InitiateAuth target", () => { beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; mockMessageDelivery = { deliver: jest.fn(), @@ -74,7 +64,7 @@ describe("InitiateAuth target", () => { describe("USER_PASSWORD_AUTH auth flow", () => { it("throws if password is incorrect", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [], UserStatus: "CONFIRMED", Password: "hunter2", @@ -97,7 +87,7 @@ describe("InitiateAuth target", () => { }); it("throws when user requires reset", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [], UserStatus: "RESET_REQUIRED", Password: "hunter2", @@ -132,7 +122,7 @@ describe("InitiateAuth target", () => { Enabled: true, Attributes: [], }); - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); const output = await initiateAuth({ ClientId: "clientId", @@ -151,7 +141,7 @@ describe("InitiateAuth target", () => { describe("when User Migration trigger is disabled", () => { it("throws", async () => { mockTriggers.enabled.mockReturnValue(false); - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await expect( initiateAuth({ @@ -170,7 +160,7 @@ describe("InitiateAuth target", () => { describe("when password matches", () => { describe("when MFA is ON", () => { beforeEach(() => { - mockUserPoolClient.config.MfaConfiguration = "ON"; + MockUserPoolClient.config.MfaConfiguration = "ON"; }); describe("when user has SMS_MFA configured", () => { @@ -197,7 +187,7 @@ describe("InitiateAuth target", () => { }, ], }; - mockUserPoolClient.getUserByUsername.mockResolvedValue(user); + MockUserPoolClient.getUserByUsername.mockResolvedValue(user); }); it("sends MFA code to user", async () => { @@ -223,7 +213,7 @@ describe("InitiateAuth target", () => { ); // also saves the code on the user for comparison later - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ ...user, MFACode: "1234", }); @@ -232,7 +222,7 @@ describe("InitiateAuth target", () => { describe("when user doesn't have MFA configured", () => { beforeEach(() => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [], UserStatus: "CONFIRMED", Password: "hunter2", @@ -260,7 +250,7 @@ describe("InitiateAuth target", () => { describe("when MFA is OPTIONAL", () => { beforeEach(() => { - mockUserPoolClient.config.MfaConfiguration = "OPTIONAL"; + MockUserPoolClient.config.MfaConfiguration = "OPTIONAL"; }); describe("when user has SMS_MFA configured", () => { @@ -287,7 +277,7 @@ describe("InitiateAuth target", () => { }, ], }; - mockUserPoolClient.getUserByUsername.mockResolvedValue(user); + MockUserPoolClient.getUserByUsername.mockResolvedValue(user); }); it("sends MFA code to user", async () => { @@ -313,7 +303,7 @@ describe("InitiateAuth target", () => { ); // also saves the code on the user for comparison later - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ ...user, MFACode: "1234", }); @@ -322,7 +312,7 @@ describe("InitiateAuth target", () => { describe("when user doesn't have MFA configured", () => { beforeEach(() => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [ { Name: "sub", Value: "0000-0000" }, { Name: "email", Value: "example@example.com" }, @@ -405,11 +395,11 @@ describe("InitiateAuth target", () => { describe("when MFA is OFF", () => { beforeEach(() => { - mockUserPoolClient.config.MfaConfiguration = "OFF"; + MockUserPoolClient.config.MfaConfiguration = "OFF"; }); it("generates tokens", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [ { Name: "sub", Value: "0000-0000" }, { Name: "email", Value: "example@example.com" }, diff --git a/src/targets/listUsers.test.ts b/src/targets/listUsers.test.ts index 2b6f67df..f67f88f2 100644 --- a/src/targets/listUsers.test.ts +++ b/src/targets/listUsers.test.ts @@ -1,30 +1,21 @@ import { advanceTo } from "jest-date-mock"; -import { CognitoClient, UserPoolClient } from "../services"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; +import { CognitoClient } from "../services"; import { ListUsers, ListUsersTarget } from "./listUsers"; describe("ListUsers target", () => { let listUsers: ListUsersTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let now: Date; beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); advanceTo(now); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; listUsers = ListUsers({ @@ -33,7 +24,7 @@ describe("ListUsers target", () => { }); it("lists users and removes Cognito Local fields", async () => { - mockUserPoolClient.listUsers.mockResolvedValue([ + MockUserPoolClient.listUsers.mockResolvedValue([ { Attributes: [], UserStatus: "CONFIRMED", diff --git a/src/targets/respondToAuthChallenge.test.ts b/src/targets/respondToAuthChallenge.test.ts index 4ad623e0..3fed10bb 100644 --- a/src/targets/respondToAuthChallenge.test.ts +++ b/src/targets/respondToAuthChallenge.test.ts @@ -1,10 +1,11 @@ import { advanceTo } from "jest-date-mock"; import jwt from "jsonwebtoken"; import { ClockFake } from "../__tests__/clockFake"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { UUID } from "../__tests__/patterns"; import { CodeMismatchError, NotAuthorizedError } from "../errors"; import PublicKey from "../keys/cognitoLocal.public.json"; -import { CognitoClient, UserPoolClient } from "../services"; +import { CognitoClient } from "../services"; import { RespondToAuthChallenge, RespondToAuthChallengeTarget, @@ -13,26 +14,16 @@ import { describe("RespondToAuthChallenge target", () => { let respondToAuthChallenge: RespondToAuthChallengeTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let now: Date; beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); advanceTo(now); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; respondToAuthChallenge = RespondToAuthChallenge({ @@ -42,7 +33,7 @@ describe("RespondToAuthChallenge target", () => { }); it("throws if user doesn't exist", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await expect( respondToAuthChallenge({ @@ -59,7 +50,7 @@ describe("RespondToAuthChallenge target", () => { describe("when code matches", () => { it("generates tokens", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [ { Name: "sub", Value: "0000-0000" }, { Name: "email", Value: "example@example.com" }, @@ -138,7 +129,7 @@ describe("RespondToAuthChallenge target", () => { describe("when code is incorrect", () => { it("throws an error", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [ { Name: "sub", Value: "0000-0000" }, { Name: "email", Value: "example@example.com" }, diff --git a/src/targets/router.ts b/src/targets/router.ts index 7024c5e6..ed25520f 100644 --- a/src/targets/router.ts +++ b/src/targets/router.ts @@ -3,6 +3,7 @@ import { Services } from "../services"; import { UnsupportedError } from "../errors"; import { ConfirmForgotPassword } from "./confirmForgotPassword"; import { ConfirmSignUp } from "./confirmSignUp"; +import { CreateGroup } from "./createGroup"; import { CreateUserPoolClient } from "./createUserPoolClient"; import { DescribeUserPoolClient } from "./describeUserPoolClient"; import { ForgotPassword } from "./forgotPassword"; @@ -27,6 +28,7 @@ export const Targets = { ChangePassword, ConfirmForgotPassword, ConfirmSignUp, + CreateGroup, CreateUserPoolClient, DescribeUserPoolClient, ForgotPassword, diff --git a/src/targets/signUp.test.ts b/src/targets/signUp.test.ts index b4558205..026c6a2f 100644 --- a/src/targets/signUp.test.ts +++ b/src/targets/signUp.test.ts @@ -1,5 +1,6 @@ import { ClockFake } from "../__tests__/clockFake"; import { MockLogger } from "../__tests__/mockLogger"; +import { MockUserPoolClient } from "../__tests__/mockUserPoolClient"; import { UUID } from "../__tests__/patterns"; import { UsernameExistsError } from "../errors"; import { @@ -7,14 +8,12 @@ import { MessageDelivery, Messages, Triggers, - UserPoolClient, } from "../services"; import { SignUp, SignUpTarget } from "./signUp"; describe("SignUp target", () => { let signUp: SignUpTarget; let mockCognitoClient: jest.Mocked; - let mockUserPoolClient: jest.Mocked; let mockMessageDelivery: jest.Mocked; let mockMessages: jest.Mocked; let mockOtp: jest.MockedFunction<() => string>; @@ -24,19 +23,10 @@ describe("SignUp target", () => { beforeEach(() => { now = new Date(2020, 1, 2, 3, 4, 5); - mockUserPoolClient = { - config: { - Id: "test", - }, - createAppClient: jest.fn(), - getUserByUsername: jest.fn(), - listUsers: jest.fn(), - saveUser: jest.fn(), - }; mockCognitoClient = { getAppClient: jest.fn(), - getUserPool: jest.fn().mockResolvedValue(mockUserPoolClient), - getUserPoolForClientId: jest.fn().mockResolvedValue(mockUserPoolClient), + getUserPool: jest.fn().mockResolvedValue(MockUserPoolClient), + getUserPoolForClientId: jest.fn().mockResolvedValue(MockUserPoolClient), }; mockMessageDelivery = { deliver: jest.fn(), @@ -70,7 +60,7 @@ describe("SignUp target", () => { }); it("throws if user already exists", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue({ + MockUserPoolClient.getUserByUsername.mockResolvedValue({ Attributes: [], Enabled: true, Password: "hunter2", @@ -91,7 +81,7 @@ describe("SignUp target", () => { }); it("saves a new user", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); await signUp({ ClientId: "clientId", @@ -100,7 +90,7 @@ describe("SignUp target", () => { UserAttributes: [{ Name: "email", Value: "example@example.com" }], }); - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ Attributes: [ { Name: "sub", @@ -118,7 +108,7 @@ describe("SignUp target", () => { }); it("sends a confirmation code to the user's email address", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); mockOtp.mockReturnValue("1234"); await signUp({ @@ -151,7 +141,7 @@ describe("SignUp target", () => { }); it("saves the confirmation code on the user for comparison when confirming", async () => { - mockUserPoolClient.getUserByUsername.mockResolvedValue(null); + MockUserPoolClient.getUserByUsername.mockResolvedValue(null); mockOtp.mockReturnValue("1234"); await signUp({ @@ -161,7 +151,7 @@ describe("SignUp target", () => { UserAttributes: [{ Name: "email", Value: "example@example.com" }], }); - expect(mockUserPoolClient.saveUser).toHaveBeenCalledWith({ + expect(MockUserPoolClient.saveUser).toHaveBeenCalledWith({ Attributes: [ { Name: "sub", Value: expect.stringMatching(UUID) }, { Name: "email", Value: "example@example.com" },