Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save phillip-le/3f1763c62b14ab8ad93b2923a62d8f0c to your computer and use it in GitHub Desktop.
Save phillip-le/3f1763c62b14ab8ad93b2923a62d8f0c to your computer and use it in GitHub Desktop.
Unit Testing AWS SDK in TypeScript
it('should persist user to dynamodb', async () => {
await createUser(userInput);
expect(mockDynamoDbDocumentClient).toHaveReceivedCommandWith(PutCommand, {
TableName: 'TestUserTable',
Item: userToCreate,
});
});
it('should query user by role from dynamodb', async () => {
expect(mockDynamoDbDocumentClient).toHaveReceivedCommandWith(QueryCommand, {
TableName: config.userTableName,
IndexName: config.userTableRoleIndexName,
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ':role': role },
KeyConditionExpression: '#role = :role',
});
});
it('should query user by role from dynamodb', async () => {
expect(queryDynamoDb).toHaveBeenCalledWith<[QueryCommandInput]>({
TableName: config.userTableName,
IndexName: config.userTableRoleIndexName,
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ':role': role },
KeyConditionExpression: '#role = :role',
});
});
// AWS SDK v3
expect(putDynamoDb).toHaveBeenCalledWith<[PutCommandInput]>({
TableName: config.userTableName,
Item: createdUser,
});
// AWS SDK v2
expect(putDynamoDb).toHaveBeenCalledWith<
[DynamoDB.DocumentClient.PutItemInput]
>({
TableName: config.userTableName,
Item: createdUser,
});
export const createUser = async (input: CreateUserInput): Promise<User> => {
const createdAt = new Date().toISOString();
const userToCreate: User = {
id: randomUUID(),
email: input.email,
role: input.role,
createdAt,
updatedAt: createdAt,
};
await dynamoDbDocumentClient.send(
new PutCommand({
TableName: config.userTableName,
Item: userToCreate,
}),
);
return userToCreate;
};
export const getUsersByRole = async (
role: Role,
): Promise<GetUsersByRoleOutput> => {
const { Items: users } = await dynamoDbDocumentClient.send(
new QueryCommand({
TableName: config.userTableName,
IndexName: config.userTableRoleIndexName,
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ':role': role },
KeyConditionExpression: '#role = :role',
}),
);
if (!maybeUsers) {
return [];
}
return users as User[];
};
export const getUsersByRoleDynamoDb = async (
role: Role,
): Promise<GetUsersByRoleOutput> => {
const { Items: users } = await queryDynamoDb({
TableName: config.userTableName,
IndexName: config.userTableRoleIndexName,
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ':role': role },
KeyConditionExpression: '#role = :role',
});
if (!users) {
return [];
}
return users as User[];
};
import 'aws-sdk-client-mock-jest';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
const dynamoDbClient = new DynamoDBClient({ region: 'ap-southeast-2' });
export const dynamoDbDocumentClient =
DynamoDBDocumentClient.from(dynamoDbClient);
yarn add -D aws-sdk-client-mock-jest
yarn add -D aws-sdk-client-mock
yarn add @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
import { mockClient } from 'aws-sdk-client-mock';
const mockDynamoDbDocumentClient = mockClient(dynamoDbDocumentClient);
jest.mock('../../../aws-sdk-v3/dynamodb');
it('should query user by role from dynamodb', async () => {
const role: Role = 'READER';
const mockReaderUser: User = {
...mockUser,
role,
};
jest.mocked(queryDynamoDb).mockResolvedValue({
$metadata: {},
Items: [mockReaderUser],
});
});
export const queryDynamoDb = async (
params: DynamoDB.DocumentClient.QueryInput,
): Promise<DynamoDB.DocumentClient.QueryOutput> =>
await dynamoDbDocumentClient.query(params).promise();
const { Items: maybeUsers } = await dynamoDbDocumentClient
.query({
TableName: config.userTableName,
IndexName: config.userTableRoleIndexName,
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ':role': role },
KeyConditionExpression: '#role = :role',
})
.promise();
it('should create user with readonly properties and put in dynamodb', async () => {
mockDynamoDbDocumentClient.on(PutCommand).resolves({});
});
it('should query user by role from dynamodb', async () => {
const role: Role = 'READER';
const mockReaderUser: User = {
id: 'TestUserId',
email: 'test@email.com',
role,
createdAt: '2023-09-10T05:58:16.945Z',
updatedAt: '2023-09-10T05:58:16.945Z',
};
mockDynamoDbDocumentClient.on(QueryCommand).resolves({
Items: [mockReaderUser],
});
});
expect(putDynamoDb).toHaveBeenCalledWith<Parameters<typeof putDynamoDb>>({
TableName: config.userTableName,
Item: createdUser,
});
it('should query user by role from dynamodb', async () => {
const mockReaderUser: User = {
id: 'TestUserId',
email: 'test@email.com',
role: 'READER',
createdAt: '2023-09-10T05:58:16.945Z',
updatedAt: '2023-09-10T05:58:16.945Z',
};
const mockQueryDynamoDb = jest.fn().mockImplementation(() => ({
promise: jest.fn().mockResolvedValue({ Items: [mockReaderUser] }),
}));
jest
.spyOn(dynamoDbDocumentClient, 'query')
.mockImplementation(mockQueryDynamoDb);
await expect(getUsersByRole('READER')).resolves.toEqual([mockReaderUser]);
expect(mockQueryDynamoDb).toHaveBeenCalledWith<
[DynamoDB.DocumentClient.QueryInput]
>({
TableName: config.userTableName,
IndexName: config.userTableRoleIndexName,
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ':role': mockReaderUser.role },
KeyConditionExpression: '#role = :role',
});
});
export const queryDynamoDb = async (
params: QueryCommandInput,
): Promise<QueryCommandOutput> =>
await dynamoDbDocumentClient.send(new QueryCommand(params));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment