m-radzikowski / aws-sdk-client-mock

AWS JavaScript SDK v3 mocks for easy unit testing. 🖋️ Typed 🔬 Tested 📄 Documented 🛠️ Maintained
https://m-radzikowski.github.io/aws-sdk-client-mock/
MIT License
811 stars 40 forks source link

.toHaveReceivedCommandWith ignoring DeleteCommand and ScanCommand #224

Closed ManuelCodes closed 2 months ago

ManuelCodes commented 6 months ago

Checklist

Bug description

Hey there,

Just wanted to flag an issue I'm encountering while running unit tests for a Lambda function with DynamoDB CRUD. It seems like the tests are skipping DeleteCommand and ScanCommand, while PutCommand, QueryCommand, and TransactWriteItemsCommand work fine.

Here is the output:

image

In case that it is not a bug. Could someone guide me what I am doing wrong?

Thanks in advance

Reproduction

organizations.test.ts

import 'aws-sdk-client-mock-jest';
import {
    DynamoDBDocumentClient,
   PutCommand,
   QueryCommand,
   DeleteCommand,
   ScanCommand
} from "@aws-sdk/lib-dynamodb";
import { TransactWriteItemsCommand,  } from "@aws-sdk/client-dynamodb";

import { mockClient,  } from 'aws-sdk-client-mock';

const mockDynamoDbDocumentClient = mockClient(DynamoDBDocumentClient);

it("should test deleting an organization", async () => {
        mockEvent.body = JSON.stringify({
            "id": "2",
            "organization_name": "ORG#SOMETHING",
        });
        mockDynamoDbDocumentClient.on(DeleteCommand).resolvesOnce({});
        const response = await organizations.deleteOrganization(mockEvent, mockContext, jest.fn());

        //LINE BELOW NOT WORKING
        expect(mockDynamoDbDocumentClient).toHaveReceivedCommandWith(DeleteCommand, {}); 

        expect(response).toMatchObject({
            statusCode: 200,
            body: JSON.stringify('ORG#SOMETHING has been deleted')
        });
});

organizations.ts


export const deleteOrganization:APIGatewayProxyHandler = async (event: APIGatewayProxyEvent, _context: Context, _cb) => {
    const { id, organization_name } = JSON.parse(event.body!);

    try {
        const params = {
            TableName: TIRESHOP_TABLE_NAME,
            Key: { pk:  id, sk:  organization_name },
            //ConditionExpression: "attribute_exists(pk) and attribute_exists(sk)"
        }
        const command = new DeleteCommand(params);
        await client.send(command);

        return {
            statusCode: 200,
            body: JSON.stringify(`${organization_name} has been deleted`)
        };
    } catch(err) {
        console.log(err);
        return {
            statusCode: 500,
            body: JSON.stringify("unknown error")
        };
    }
};

Environment

m-radzikowski commented 5 months ago

This works perfectly fine for me:

import {DeleteCommand, DynamoDBDocumentClient} from "@aws-sdk/lib-dynamodb";
import {DynamoDBClient} from "@aws-sdk/client-dynamodb";
import {mockClient} from 'aws-sdk-client-mock';
import 'aws-sdk-client-mock-jest';

const client = DynamoDBDocumentClient.from(new DynamoDBClient());

export const deleteOrganization = async () => {
  try {
    const params = {
      TableName: '',
      Key: {pk: '', sk: 'organization_name'},
    }
    const command = new DeleteCommand(params);
    await client.send(command);

    return {
      statusCode: 200,
      body: JSON.stringify(`ORG#SOMETHING has been deleted`),
    };
  } catch (err) {
    console.log(err);
    return {
      statusCode: 500,
      body: JSON.stringify("unknown error"),
    };
  }
};

const mockDynamoDbDocumentClient = mockClient(DynamoDBDocumentClient);

it("should test deleting an organization", async () => {
  mockDynamoDbDocumentClient.on(DeleteCommand).resolvesOnce({});
  const response = await deleteOrganization();

  expect(mockDynamoDbDocumentClient).toHaveReceivedCommandWith(DeleteCommand, {});

  expect(response).toMatchObject({
    statusCode: 200,
    body: JSON.stringify('ORG#SOMETHING has been deleted'),
  });
});

Tested with both AWS SDK v3.565.0 and v3.588.0 (current latest).

One note - if you don't need any assertions on the command content, you can use toHaveReceivedCommand() instead of toHaveReceivedCommandWith(). But still it works fine with empty object.

If the problem persists, please create a sample repo with reproduction and I'll take a look.