Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 37

Testing DELETE Endpoints: 204 and 404 Scenarios

Recommended resources

Introduction

In the last lesson, you mastered writing integration tests for your PUT endpoint, ensuring it correctly handles both successful updates (200 OK) and not-found errors (404 Not Found). You're now ready to test the final piece of our core CRUD functionality: the DELETE endpoint.

This lesson will guide you through writing integration tests for resource deletion. By the end, you'll be able to implement two critical test cases:

  1. Successful Deletion: Verifying that a DELETE request to an existing resource returns a 204 No Content status.
  2. Not-Found Error: Confirming that attempting to delete a non-existent resource correctly returns a 404 Not Found status.

These tests are crucial for building a resilient API and are a common requirement in certification exams.


1. Testing a Successful Deletion (204 No Content)

The "happy path" for a DELETE request is straightforward: a client provides a valid ID, the server removes the corresponding resource from the database, and confirms success. The standard HTTP status code for a successful DELETE operation that returns no data is 204 No Content. Your test must verify this behavior.

The Test Flow:

  1. Setup: Define a valid ID for a resource you intend to delete. Mock Model.findByIdAndDelete() to resolve with a document object. Resolving with the object simulates that the document was found and successfully passed to the deletion logic.
  2. Action: Use Supertest to send a DELETE request to your endpoint (e.g., /api/products/:id).
  3. Assertion: Verify that the status code is 204. Since a 204 response must not have a body, you can also assert that the response body is empty.

Here is the implementation pattern:

// In tests/routes/productRoutes.test.js

describe('DELETE /api/products/:id', () => {
  it('should delete the product and return 204 status', async () => {
    // 1. Setup
    const productId = '60d21b4667d0d8992e610c87';
    // Mock the Mongoose method to simulate a successful find and delete
    Product.findByIdAndDelete.mockResolvedValue({ _id: productId, name: 'Old Product' });

    // 2. Action
    const res = await request(server).delete(`/api/products/${productId}`);

    // 3. Assertion
    expect(res.statusCode).toBe(204);
    expect(res.body).toEqual({}); // Body should be empty

    // Verify the mock was called correctly
    expect(Product.findByIdAndDelete).toHaveBeenCalledWith(productId);
  });
});

This test ensures that your controller correctly calls the Mongoose findByIdAndDelete method and returns the appropriate 204 status upon success.


2. Testing Not-Found Errors (404 Not Found)

Your API must handle attempts to delete resources that don't exist. The controller should detect when findByIdAndDelete returns null (indicating no document was found) and respond with a 404 Not Found error.

The Test Flow:

  1. Setup: Use an ID that is a valid format but doesn't exist in the database. Mock Model.findByIdAndDelete() to resolve with null.
  2. Action: Send a DELETE request using the non-existent ID.
  3. Assertion: Verify that the status code is 404 and that your API returns a clear error message in the response body.

Here is how you implement this "sad path" test:

// Add this 'it' block inside your 'DELETE /api/products/:id' describe block

it('should return 404 status if product is not found', async () => {
  // 1. Setup
  const nonExistentId = '123456789012345678901234';
  // Mock the Mongoose method to return null, simulating a not-found case
  Product.findByIdAndDelete.mockResolvedValue(null);

  // 2. Action
  const res = await request(server).delete(`/api/products/${nonExistentId}`);

  // 3. Assertion
  expect(res.statusCode).toBe(404);
  // Check for the error message your API sends in this case
  expect(res.body.message).toBe('Product not found');
});

With these two tests, your DELETE endpoint is now fully covered. A successful test run gives you confidence that your deletion logic is robust.

Successful Integration Test Results for a Todo API
This image shows a passed test suite from a real project. Notice the two tests under `DELETE /todo/:id`: one for successfully deleting an item and another for handling a non-existent item with a 404 error. This is exactly the result you are aiming for.

A Complete E2E Test Example

To see how these tests fit into a complete end-to-end test file, the following resource provides an excellent, practical example. It uses a simple in-memory array instead of Mongoose, but the Supertest patterns for testing the DELETE route are identical to what you need.

Ensuring API Stability End-to-End with Jest and Supertest

The following resource provides a full end-to-end test file. Pay close attention to the two test cases for the DELETE endpoint, as they perfectly demonstrate the patterns for success (204) and failure (404).

In the __tests__/items.e2e.test.js code block, find the describe('Items API E2E Tests', ...) section. Scroll down to the last two test cases: it('should delete an item', ...) and it('should return 404 when trying to delete a non-existent item', ...). Analyze how they use request(app).delete() and assert the status codes 204 and 404 respectively.

Studying this example will solidify your understanding of how to structure these critical tests in preparation for your exam.


Conclusion

You have now completed the test suite for all core CRUD operations. You can write focused integration tests that validate the behavior of your GET, POST, PUT, and DELETE endpoints, covering both successful operations and common error conditions like 404 Not Found.

Key Takeaways:

  • Test for Success (204):
    • Mock Model.findByIdAndDelete() to resolve with a document.
    • Send a DELETE request with a valid ID: .delete('/path/:id').
    • Assert the status is 204 and the response body is empty.
  • Test for Not Found (404):
    • Mock Model.findByIdAndDelete() to resolve with null.
    • Send a DELETE request with a non-existent ID.
    • Assert the status is 404 and check for an appropriate error message.

Next Up:

With a fully tested CRUD API, we will now move on to a new feature. In the next lesson, you will learn how to handle file uploads by integrating and configuring the Multer middleware.