Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Sunshine And March Vibes (2025 Wallpapers Edition)

      May 9, 2025

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      May 9, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      May 9, 2025

      How To Prevent WordPress SQL Injection Attacks

      May 9, 2025

      Your password manager is under attack, and this new threat makes it worse: How to defend yourself

      May 9, 2025

      EcoFlow’s new backyard solar energy system starts at $599 – no installation crews or permits needed

      May 9, 2025

      Why Sonos’ cheapest smart speaker is one of my favorites – even a year after its release

      May 9, 2025

      7 productivity gadgets I can’t live without (and why they make such a big difference)

      May 9, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Tap into Your PHP Potential with Free Projects at PHPGurukul

      May 9, 2025
      Recent

      Tap into Your PHP Potential with Free Projects at PHPGurukul

      May 9, 2025

      Preparing for AI? Here’s How PIM Gets Your Data in Shape

      May 9, 2025

      A Closer Look at the AI Assistant of Oracle Analytics

      May 9, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      kew v3.2.0 improves internet radio support and more

      May 9, 2025
      Recent

      kew v3.2.0 improves internet radio support and more

      May 9, 2025

      GNOME Replace Totem Video Player with Showtime

      May 9, 2025

      Placemark is a web-based tool for geospatial data

      May 9, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»Supertest: The Ultimate Guide to Testing Node.js APIs

    Supertest: The Ultimate Guide to Testing Node.js APIs

    May 9, 2025

    API testing is crucial for ensuring that your backend services work correctly and reliably. APIs often serve as the backbone of web and mobile applications, so catching bugs early through automated tests can save time and prevent costly issues in production. For Node.js developers and testers, the Supertest API library offers a powerful yet simple way to automate HTTP endpoint testing as part of your workflow. Supertest is a Node.js library (built on the Superagent HTTP client) designed specifically for testing web APIs. It allows you to simulate HTTP requests to your Node.js server and assert the responses without needing to run a browser or a separate client. This means you can test your RESTful endpoints directly in code, making it ideal for integration and end-to-end testing of your server logic. Developers and QA engineers favor Supertest because it is:

    • Lightweight and code-driven – No GUI or separate app required, just JavaScript code.
    • Seamlessly integrated with Node.js frameworks – Works great with Express or any Node HTTP server.
    • Comprehensive – Lets you control headers, authentication, request payloads, and cookies in tests.
    • CI/CD friendly – Easily runs in automated pipelines, returning standard exit codes on test pass/fail.
    • Familiar to JavaScript developers – You write tests in JS/TS, using popular test frameworks like Jest or Mocha, so there’s no context-switching to a new language.

    In this guide, we’ll walk through how to set up and use Supertest API for testing various HTTP methods (GET, POST, PUT, DELETE), validate responses (status codes, headers, and bodies), handle authentication, and even mock external API calls. We’ll also discuss how to integrate these tests into CI/CD pipelines and share best practices for effective API testing. By the end, you’ll be confident in writing robust API tests for your Node.js applications using Supertest.

    Related Blogs

    API Testing with Playwright: A Comprehensive Guide

    Bruno API Automation: A Comprehensive Guide

    Setting Up Supertest in Your Node.js Project

    Before writing tests, you need to add Supertest to your project and set up a testing environment. Assuming you already have a Node.js application (for example, an Express app), follow these steps to get started:

    • Install Supertest (and a test runner): Supertest is typically used with a testing framework like Jest or Mocha. If you don’t have a test runner set up, Jest is a popular choice for beginners due to its zero configuration. Install Supertest and Jest as development dependencies using npm:
      
      npm install --save-dev supertest jest
      
      

      This will add Supertest and Jest to your project’s node_modules. (If you prefer Mocha or another framework, you can install those instead of Jest.)

    • Project Structure: Organize your tests in a dedicated directory. A common convention is to create a folder called tests or to put test files alongside your source files with a .test.js extension. For example:
      
      my-project/
      ├── app.js            # Your Express app or server
      └── tests/
          └── users.test.js # Your Supertest test file
      
      

      In this example, app.js exports an Express application (or Node HTTP server) which the tests will import. The test file users.test.js will contain our Supertest test cases.

    • Configure the Test Script: If you’re using Jest, add a test script to your package.json (if not already present):
      
      "scripts": {
        "test": "jest"
      }
      
      

      This allows you to run all tests with the command npm test. (For Mocha, you might use “test”: “mocha” accordingly.)

    With Supertest installed and your project structured for tests, you’re ready to write your first API test.

    Writing Your First Supertest API Test

    Let’s create a simple test to make sure everything is set up correctly. In your test file (e.g., users.test.js), you’ll require your app and the Supertest library, then define test cases. For example:

    
    const request = require('supertest');    // import Supertest
    const app = require('../app');           // import the Express app
    
    
    describe('GET /api/users', () => {
      it('should return HTTP 200 and a list of users', async () => {
        const res = await request(app).get('/api/users');  // simulate GET request
        expect(res.statusCode).toBe(200);                  // assert status code is 200
        expect(res.body).toBeInstanceOf(Array);            // assert response body is an array
      });
    });
    
    
    

    In this test, request(app) creates a Supertest client for the Express app. We then call .get(‘/api/users’) and await the response. Finally, we use Jest’s expect to check that the status code is 200 (OK) and that the response body is an array (indicating a list of users).

    Now, let’s dive deeper into testing various scenarios and features of an API using Supertest.

    Testing Different HTTP Methods (GET, POST, PUT, DELETE)

    Real-world APIs use multiple HTTP methods. Supertest makes it easy to test any request method by providing corresponding functions (.get(), .post(), .put(), .delete(), etc.) after calling request(app). Here’s how you can use Supertest for common HTTP methods:

    
    // Examples of testing different HTTP methods with Supertest:
    
    // GET request (fetch list of users)
    await request(app)
      .get('/users')
      .expect(200);
    
    // POST request (create a new user with JSON payload)
    await request(app)
      .post('/users')
      .send({ name: 'John' })
      .expect(201);
    
    // PUT request (update user with id 1)
    await request(app)
      .put('/users/1')
      .send({ name: 'John Updated' })
      .expect(200);
    
    // DELETE request (remove user with id 1)
    await request(app)
      .delete('/users/1')
      .expect(204);
    
    

    In the above snippet, each request is crafted for a specific endpoint and method:

    • GET /users should return 200 OK (perhaps with a list of users).
    • POST /users sends a JSON body ({ name: ‘John’ }) to create a new user. We expect a 201 Created status in response.
    • PUT /users/1 sends an updated name for the user with ID 1 and expects a 200 OK for a successful update.
    • DELETE /users/1 attempts to delete user 1 and expects a 204 No Content (a common response for successful deletions).

    Notice the use of .send() for POST and PUT requests – this method attaches a request body. Supertest (via Superagent) automatically sets the Content-Type: application/json header when you pass an object to .send(). You can also chain an .expect(statusCode) to quickly assert the HTTP status.

    Sending Data, Headers, and Query Parameters

    When testing APIs, you often need to send data or custom headers, or verify endpoints with query parameters. Supertest provides ways to handle all of these:

    • Query Parameters and URL Path Params: Include them in the URL string. For example:
      
      // GET /users?role=admin (query string)
      await request(app).get('/users?role=admin').expect(200);
      
      // GET /users/123 (path parameter)
      await request(app).get('/users/123').expect(200);
      
      

      If your route uses query parameters or dynamic URL segments, constructing the URL in the request call is straightforward.

    • Request Body (JSON or form data): Use .send() for JSON payloads (as shown above). If you need to send form-url-encoded data or file uploads, Supertest (through Superagent) supports methods like .field() and .attach(). However, for most API tests sending JSON via .send({…}) is sufficient. Just ensure your server is configured (e.g., with body-parsing middleware) to handle the content type you send.
    • Custom Headers: Use .set() to set any HTTP header on the request. Common examples include setting an Accept header or authorization tokens. For instance:
      
      await request(app)
        .post('/users')
        .send({ name: 'Alice' })
        .set('Accept', 'application/json')
        .expect('Content-Type', /json/)
        .expect(201);
      
      

      Here we set Accept: application/json to tell the server we expect a JSON response, and then we chain an expectation that the Content-Type of the response matches json. You can use .set() for any header your API might require (such as X-API-Key or custom headers).

    Setting headers is also how you handle authentication in Supertest, which we’ll cover next.

    Related Blogs

    API Monitoring Guide: Optimize Performance & Ensure Reliability

    Bruno Tutorial for API Testing

    Handling Authentication and Protected Routes

    APIs often have protected endpoints that require authentication, such as a JSON Web Token (JWT) or an API key. To test these, you’ll need to include the appropriate auth credentials in your Supertest requests.

    For example, if your API uses a Bearer token in the Authorization header (common with JWT-based auth), you can do:

    
    const token = 'your-jwt-token-here';  // Typically you'd generate or retrieve this in your test setup
    await request(app)
      .get('/dashboard')
      .set('Authorization', `Bearer ${token}`)
      .expect(200);
    
    

    In this snippet, we set the Authorization header before making a GET request to a protected /dashboard route. We then expect a 200 OK if the token is valid and the user is authorized. If the token is missing or incorrect, you could test for a 401 Unauthorized or 403 Forbidden status accordingly.

    Tip: In a real test scenario, you might first call a login endpoint (using Supertest) to retrieve a token, then use that token for subsequent requests. You can utilize Jest’s beforeAll hook to obtain auth tokens or set up any required state before running the secured-route tests, and an afterAll to clean up after tests (for example, invalidating a token or closing database connections).

    Validating Responses: Status Codes, Bodies, and Headers

    Supertest makes it easy to assert various parts of the HTTP response. We’ve already seen using .expect(STATUS) to check status codes, but you can also verify response headers and body content.

    You can chain multiple Supertest .expect calls for convenient assertions. For example:

    
    await request(app)
      .get('/users')
      .expect(200)                              // status code is 200
      .expect('Content-Type', /json/)           // Content-Type header contains "json"
      .expect(res => {
        // Custom assertion on response body
        if (!res.body.length) {
          throw new Error('No users found');
        }
      });
    
    

    Here we chain three expectations:

    • The response status should be 200.
    • The Content-Type header should match a regex /json/ (indicating JSON content).
    • A custom function that throws an error if the res.body array is empty (which would fail the test). This demonstrates how to do more complex assertions on the response body; if the condition inside .expect(res => { … }) is not met, the test will fail with that error.

    Alternatively, you can always await the request and use your test framework’s assertion library on the response object. For example, with Jest you could do:

    
    const res = await request(app).get('/users');
    expect(res.statusCode).toBe(200);
    expect(res.headers['content-type']).toMatch(/json/);
    expect(res.body.length).toBeGreaterThan(0);
    
    

    Both approaches are valid – choose the style you find more readable. Using Supertest’s chaining is concise for simple checks, whereas using your own expect calls on the res object can be more flexible for complex verification.

    Testing Error Responses (Negative Testing)

    It’s important to test not only the “happy path” but also how your API handles invalid input or error conditions. Supertest can help you simulate error scenarios and ensure your API responds correctly with the right status codes and messages.

    For example, if your POST /users endpoint should return a 400 Bad Request when required fields are missing, you can write a test for that case:

    
    it('should return 400 when required fields are missing', async () => {
      const res = await request(app)
        .post('/users')
        .send({});  // sending an empty body, assuming "name" or other fields are required
      expect(res.statusCode).toBe(400);
      // Optionally, check that an error message is returned in the body
      expect(res.body.error).toBeDefined();
    });
    
    

    In this test, we intentionally send an incomplete payload (empty object) to trigger a validation error. We then assert that the response status is 400. You could also assert on the response body (for example, checking that res.body.error or res.body.message contains the expected error info).

    Similarly, you might test a 404 Not Found for a GET with a non-existent ID, or 401 Unauthorized when hitting a protected route without credentials. Covering these negative cases ensures your API fails gracefully and returns expected error codes that clients can handle.

    Mocking External API Calls in Tests

    Sometimes your API endpoints call third-party services (for example, an external REST API). In your tests, you might not want to hit the real external service (to avoid dependencies, flakiness, or side effects). This is where mocking comes in.

    For Node.js, a popular library for mocking HTTP requests is Nock. Nock can intercept outgoing HTTP calls and simulate responses, which pairs nicely with Supertest when your code under test makes HTTP requests itself.

    To use Nock, install it first:

    
    npm install --save-dev nock
    
    

    Then, in your tests, you can set up Nock before making the request with Supertest. For example:

    
    // Mock the external API endpoint
    nock('https://api.example.com')
      .get('/data')
      .reply(200, { result: 'ok' });
    
    
    // Now make a request to your app (which calls the external API internally)
    const res = await request(app).get('/internal-route');
    expect(res.statusCode).toBe(200);
    expect(res.body.result).toBe('ok');
    
    

    In this way, when your application tries to reach api.example.com/data, Nock intercepts the call and returns the fake { result: ‘ok’ }. Our Supertest test then verifies that the app responded as expected without actually calling the real external service.

    Best Practices for API Testing with Supertest

    To get the most out of Supertest and keep your tests maintainable, consider the following best practices:

    • Separate tests from application code: Keep your test files in a dedicated folder (like tests/) or use a naming convention like *.test.js. This makes it easier to manage code and ensures you don’t accidentally include test code in production builds. It also helps testing frameworks (like Jest) find your tests automatically.
    • Use test data factories or generators: Instead of hardcoding data in your tests, generate dynamic data for more robust testing. For example, use libraries like Faker.js to create random user names, emails, etc. This can reveal issues that only occur with certain inputs and prevents all tests from using the exact same data. It keeps your tests closer to real-world scenarios.
    • Test both success and failure paths: For each API endpoint, write tests for expected successful outcomes (200-range responses) and also for error conditions (4xx/5xx responses). Ensuring you have coverage for edge cases, bad inputs, and unauthorized access will make your API more reliable and bug-resistant.
    • Clean up after tests: Tests should not leave the system in a dirty state. If your tests create or modify data (e.g., adding a user in the database), tear down that data at the end of the test or use setup/teardown hooks (beforeEach, afterEach) to reset state. This prevents tests from interfering with each other. Many testing frameworks allow you to reset database or app state between tests; use those features to isolate test cases.
    • Use environment variables for configuration: Don’t hardcode sensitive values (like API keys, tokens, or database URLs) in your tests. Instead, use environment variables and perhaps a dedicated .env file for your test configuration. By using a package like dotenv, you can load test-specific environment variables (for example, pointing to a test database instead of production). This protects sensitive information and makes it easy to configure tests in different environments (local vs CI, etc.).

    By following these practices, you’ll write tests that are cleaner, more reliable, and easier to maintain as your project grows.

    Related Blogs

    How to Test WebSockets?

    Postbot AI Tutorial: Expert Tips

    Supertest vs Postman vs Rest Assured: Tool Comparison

    While Supertest is a great tool for Node.js API testing, you might wonder how it stacks up against other popular API testing solutions like Postman or Rest Assured. Here’s a quick comparison:

    S. NoFeatureSupertest (Node.js)Postman (GUI Tool)Rest Assured (Java)
    1Language/InterfaceJavaScript (code)GUI + JavaScript (for tests via Newman)Java (code)
    2Testing StyleCode-driven; integrated with Jest/MochaManual + some automation (collections, Newman CLI)Code-driven (uses JUnit/TestNG)
    3SpeedFast (no UI overhead)Medium (runs through an app or CLI)Fast (runs in JVM)
    4CI/CD IntegrationYes (run with npm test)Yes (using Newman CLI in pipelines)Yes (part of build process)
    5Learning CurveLow (if you know JS)Low (easy GUI, scripting possibleMedium (requires Java and testing frameworks)
    6Ideal Use CaseNode.js projects – embed tests in codebase for TDD/CIExploratory testing, sharing API collections, quick manual checksJava projects – write integration tests in Java code

    In summary, Supertest shines for developers in the Node.js ecosystem who want to write programmatic tests alongside their application code. Postman is excellent for exploring and manually testing APIs (and it can do automation via Newman), but those tests live outside your codebase. Rest Assured is a powerful option for Java developers, but it isn’t applicable for Node.js apps. If you’re working with Node and want seamless integration with your development workflow and CI pipelines, Supertest is likely your best bet for API testing.

    Conclusion

    Automated API testing is a vital part of modern software development, and Supertest provides Node.js developers and testers with a robust, fast, and intuitive tool to achieve it. By integrating Supertest API tests into your development cycle, you can catch regressions early, ensure each endpoint behaves as intended, and refactor with confidence. We covered how to set up Supertest, write tests for various HTTP methods, handle things like headers, authentication, and external APIs, and even how to incorporate these tests into continuous integration pipelines.

    Now it’s time to put this knowledge into practice. Set up Supertest in your Node.js project and start writing some tests for your own APIs. You’ll likely find that the effort pays off with more reliable code and faster debugging when things go wrong. Happy testing!

    Frequently Asked Questions

    • What is Supertest API?

      Supertest API (or simply Supertest) is a Node.js library for testing HTTP APIs. It provides a high-level way to send requests to your web server (such as an Express app) and assert the responses. With Supertest, you can simulate GET, POST, PUT, DELETE, and other requests in your test code and verify that your server returns the expected status codes, headers, and data. It’s widely used for integration and end-to-end testing of RESTful APIs in Node.js.

    • Can Supertest be used with Jest?

      Yes – Supertest works seamlessly with Jest. In fact, Jest is one of the most popular test runners to use with Supertest. You can write your Supertest calls inside Jest’s it() blocks and use Jest’s expect function to make assertions on the response (as shown in the examples above). Jest also provides convenient hooks like beforeAll/afterAll which you can use to set up or tear down test conditions (for example, starting a test database or seeding data) before your Supertest tests run. While we’ve used Jest for examples here, Supertest is test-runner agnostic, so you could also use it with Mocha, Jasmine, or other frameworks in a similar way.

    • How do I mock APIs when using Supertest?

      You can mock external API calls by using a library like Nock to intercept them. Set up Nock in your test to fake the external service’s response, then run your Supertest request as usual. This way, when your application tries to call the external API, Nock responds instead, allowing your test to remain fast and isolated from real external dependencies.

    • How does Supertest compare with Postman for API testing?

      Supertest and Postman serve different purposes. Supertest is a code-based solution — you write JavaScript tests and run them, which is perfect for integration into a development workflow and CI/CD. Postman is a GUI tool great for manually exploring endpoints, debugging, and sharing API collections, with the ability to write tests in the Postman app. You can automate Postman tests using its CLI (Newman), but those tests aren’t part of your application’s codebase. In contrast, Supertest tests live alongside your code, which means they can be version-controlled and run automatically on every code change. Postman is easier for quick manual checks or for teams that include non-developers, whereas Supertest is better suited for developers who want an automated testing suite integrated with their Node.js project.

    The post Supertest: The Ultimate Guide to Testing Node.js APIs appeared first on Codoid.

    Source: Read More

    Facebook Twitter Reddit Email Copy Link
    Previous Articlekew v3.2.0 improves internet radio support and more
    Next Article Ming-Lite-Uni: An Open-Source AI Framework Designed to Unify Text and Vision through an Autoregressive Multimodal Structure

    Related Posts

    Security

    Nmap 7.96 Launches with Lightning-Fast DNS and 612 Scripts

    May 9, 2025
    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-4487 – iSourcecode Gym Management System SQL Injection Vulnerability

    May 9, 2025
    Leave A Reply Cancel Reply

    Continue Reading

    CVE-2025-32889 – goTenna Hardcoded Verification Token Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Distribution Release: Ubuntu Budgie 25.04

    News & Updates

    How to Integrate Discord Webhooks with Next.js 15 – Example Project

    Development

    How to use a vertical taskbar on Windows 11

    News & Updates

    Highlights

    How to handle if controller in Jmeter for extracted response

    June 7, 2024

    I have one http request and it extracted the csrf token.But the csrf token attached with attached with html and javascript.

    If the request success the csrf token is attached with HTMl.
    If the request fails the csrf is attached with javaScript.
    I’m able to extract both and
    i need to pass the csrf to next request. based on the condition.
    How can i achieve it ?Any suggestions.

    Build a multi-tenant generative AI environment for your enterprise on AWS

    November 7, 2024

    Apple may have bigger fish to fry with OpenAI’s rumored ChatGPT Screenless phone — beyond President Trump’s stringent tariffs on the iPhone

    April 14, 2025

    My new favorite power station is built by my old favorite drone maker

    January 22, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.