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
790 stars 38 forks source link

SQSClient received matching "DeleteMessageCommand" 0 times, after "SendMessageCommand" is run #210

Closed steven-so closed 7 months ago

steven-so commented 7 months ago

Checklist

Bug description

I'm running into a problem that doesn't make sense to me:

Expected SQSClient to receive "DeleteMessageCommand" with {"QueueUrl": "https://sqs.us-west-2.amazonaws.com/***", "ReceiptHandle": "***"}                                                                          
    SQSClient received matching "DeleteMessageCommand" 0 times 

I'm writing tests for a long polling loop. Inside the loop I call (and await) a function, like sendToQueue in the reproduction, that sends the message to another queue, and deletes it from the current queue.

I don't understand why DeleteMessageCommand is not being shown as being called by the test runner.

If I remove the code that performs the "SendMessageCommand", or move the code to "DeleteMessageCommand" before "SendMessageCommand", then I see that "DeleteMessageCommand" was called. In the case I run "DeleteMessageCommand" before "SendMessageCommand," then it shows "SendMessageCommand" was not called.

It seems like the test cannot recognize both as being called, however when I run the function in production against the actual queue it appears the messages are both sent and deleted properly.

*Sorry I'm new to AWS SQS, writing tests, and creating github issues, so please have mercy. :)

Reproduction

it("forwards valid message to myqueue", async () => {
  sqsMock
    .on(ReceiveMessageCommand)
    .resolves(mockReceiveMessageValid)
    .on(SendMessageCommand)
    .resolves(mockSendMessageResult)
    .on(DeleteMessageCommand)
    .resolves({});

  await expect(myPollFunction()).resolves.not.toThrow();

  expect(sqsMock).toHaveReceivedCommandWith(SendMessageCommand, {
    QueueUrl: OTHER_QUEUE_URL
    MessageBody: mockBody,
  });

  expect(sqsMock).toHaveReceivedCommandWith(DeleteMessageCommand, {
    QueueUrl: CURRENT_QUEUE_URL
    ReceiptHandle: mockReceiptHandle,
  });
});
export default async function sendToQueue({
  MessageBody,
  ReceiptHandle,
}: {
  MessageBody: string;
  ReceiptHandle: string;
}) {
  try {
    const sendParams = {
      QueueUrl: OTHER_QUEUE_URL, 
      MessageBody: MessageBody,
    };

    const sendCommand = new SendMessageCommand(sendParams);
    const sendResponse = await sqs.send(sendCommand);

    const deleteParams = {
      QueueUrl: CURRENT_QUEUE_URL, 
      ReceiptHandle: ReceiptHandle, 
    };

    const deleteCommand = new DeleteMessageCommand(deleteParams);
    const deleteResponse = await sqs.send(deleteCommand);
  } catch (err) {
    console.error("Failed to forward and delete", err);
  }
}

Environment

steven-so commented 7 months ago

My bad.

I discovered the the await was running inside of a .forEach and the test was ending before each .forEach iteration was completed.