Increase the call stack of a failed test beyond the helper function and up to the test case

As I was writing unit tests for my codebase, I noticed that I kept duplicating the code responsible for making HTTP requests and setting expectations for the response. To avoid this redundancy, I created some helper functions, one of which is called expectedResponseForGET. This function is static and resides within a TestUtils class in a file named utils.ts.

In certain test cases, I utilize the expectedResponseForGET method multiple times to verify different aspects following a POST request. However, when an expectation fails (i.e., the response does not match the expected outcome), the test fails, and the call stack only displays the failed expectation from the expectedResponseForGET function without indicating which test initially triggered the helper function.

The stack trace provided for the failed expectation typically looks like this:

src/tests/sites/add.test.ts
  Add site route
    ✓  User4 - Add site, not company manager (238 ms)
    ✕  User1 - Add site, company manager (269 ms)

  ● Add site route ›  User1 - Add site, company manager

    expect(received).toEqual(expected) // deep equality

    - Expected  -  1
    + Received  +  1

    @@ -1,63 +1,10 @@
    -       "location": "Location2",
    +       "location": "Location",

      92 |       .set('Authorization', user.token);
      93 |     expect(res.status).toBe(200);
    > 94 |     expect(res.body).toEqual(response);
         |                      ^
      95 |     return res;
      96 |   };
      97 |

      at src/tests/utils.ts:94:22
      at fulfilled (src/tests/utils.ts:5:58)

This portion contains details related to the line with the failed expectation and the import of 'request' from Supertest, but it lacks information about the specific test from src/tests/sites/add.test.ts that invoked expectedResponseForGET.

Below is the test scenario in question:

test(' User1 - Add site, company manager', async () => {
    await TestUtils.expectedResponseForPOST(
      server,
      C1.users.U1,
      route,
      C1.sites.S5.requests.addSite,
      C1.sites.S5.responses.fullSite,
    );

    await TestUtils.expectedResponseForGET(
      server,
      C1.users.U1,
      routeSites,
      C1.sites.responses.allAfterS5,
    );

   await TestUtils.expectedResponseForGET(
      server,
      C1.users.U1,
      routeWork,
      C1.work.responses.allAfterS5,
    );
  });

Here are the definitions of the helper functions:

import request from 'supertest';

class TestUtils{
  static expectedResponseForGET = async (
    server: Express,
    user: UserTest,
    route: string,
    response: GenericResponse,
  ) => {
    const res = await request(server)
      .get(route)
      .set('Authorization', user.token);
    expect(res.status).toBe(200);
    expect(res.body).toEqual(response);
    return res;
  };

  static expectedResponseForPOST = async (
    server: Express,
    user: UserTest,
    route: string,
    // eslint-disable-next-line @typescript-eslint/ban-types
    req: Object,
    response: GenericResponse,
  ) => {
    const res = await request(server)
      .post(route)
      .send(req)
      .set('Authorization', user.token);
    expect(res.status).toBe(200);
    expect(res.body).toEqual(response);
    return res;
  };
}

If anyone has encountered similar challenges and found a solution or workaround to display the test line that invoked the helper method, please share your insights.

Answer №1

I successfully resolved this issue by implementing a solution in the utils method. I saved the stack and appended it to the error message that gets thrown when a test fails:

static expectedResponseForPOST = async (
    server: Express,
    user: UserTest,
    route: string,
    // eslint-disable-next-line @typescript-eslint/ban-types
    req: Object,
    response: GenericResponse,
  ) => {
    const originalStack = new Error().stack;

    try {
    const res = await request(server)
      .post(route)
      .send(req)
      .set('Authorization', user.token);
    expect(res.status).toBe(200);
    expect(res.body).toEqual(response);
    return res;
    }catch (err) {
      if (err instanceof Error) {
        err.stack = `${err.stack}\nComplete Stack:\n${originalStack}`;
      }
      throw err;
    }

  };

This implementation will generate logging such as:

at src/tests/utils.ts:140:26
      at fulfilled (src/tests/utils.ts:5:58)
      Complete Stack:
      at src/tests/utils.ts:131:27
      at src/tests/utils.ts:8:71
      at Object.<anonymous>.__awaiter (src/tests/utils.ts:4:12)
      at Function.Object.<anonymous>.TestUtils.expectedResponseForPOST (src/tests/utils.ts:118:7)
      at Function.<anonymous> (src/tests/data/models/WarehouseEventTest.ts:39:21)
      at src/tests/data/models/WarehouseEventTest.ts:8:71
      at Object.<anonymous>.__awaiter (src/tests/data/models/WarehouseEventTest.ts:4:12)
      at Function.checkIncrementalEventsAfterAction (src/tests/data/models/WarehouseEventTest.ts:24:16)
      at Function.<anonymous> (src/tests/data/models/WarehouseEventTest.ts:20:30)
      at src/tests/data/models/WarehouseEventTest.ts:8:71
      at Object.<anonymous>.__awaiter (src/tests/data/models/WarehouseEventTest.ts:4:12)
      at Function.checkIncrementalEventAfterAction (src/tests/data/models/WarehouseEventTest.ts:18:16)
      at src/tests/warehouse/warehouseItem.test.ts:166:30
      at fulfilled (src/tests/warehouse/warehouseItem.test.ts:5:58)

This represents the full stack trace.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can regex matching characters be made easier to understand?

I am working on creating an ECMAScript (JavaScript) flavored regex to evaluate the complexity of my password based on specific criteria: Characters Used Password Strength Length ABC abc 123 #$& WEAK ... 1 x ...

Struggling to display the preloader animation while waiting for the render.com server to start up (using the free tier web service)

My choice for deploying dynamic websites is render.com and I am currently using their free tier. The issue with this free service is that Render spins down the web service after 15 minutes of inactivity, resulting in a delay when it needs to spin back up u ...

Is there a more efficient method to tally specific elements in a sparse array?

Review the TypeScript code snippet below: const myArray: Array<string> = new Array(); myArray[5] = 'hello'; myArray[7] = 'world'; const len = myArray.length; let totalLen = 0; myArray.forEach( arr => totalLen++); console.log(& ...

Tips for utilizing document.write() with a document rather than just plain text

Currently, I am utilizing socket.io to develop a party game that shares similarities with cards against humanity. My main concern is how to retain the players' names and scores without needing to transmit all the data to a new page whenever new games ...

Tips for utilizing various broadcast options to trigger Angular controllers according to the user's chosen selection

I'm currently developing an angularjs application that includes multiple date range pickers on a single web page. When a user selects a date range from one of these pickers, I need to send the selected dates to the corresponding angular controller ass ...

Disable page scrolling after making changes to the DOM

When my JavaScript function executes on page load and at set intervals, it cycles through images supplied by another PHP script. However, every time the function manipulates the DOM, the page scrolls back to the top of the containing div, which is quite fr ...

Generate a graphical representation with react-d3

In an attempt to create a histogram using react-d3-components, I have the following code: import React, { Component } from 'react'; import * as d3 from 'd3'; import * as ReactD3 from 'react-d3-components'; import propTypes fr ...

The pop-up window is currently inactive

Utilizing the following example, I successfully created a modal window: jsfiddle The modal window allows me to display data from a table. Here is a snippet of my code: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/c ...

Navigating the Angular Element: A Guide to Clicking Buttons within Modal-Dialogs Using Protractor

I am currently creating an automation test for an angular application using the protractor framework. Test scenario: Click on the "Create PDF Report" button A modal-dialog window will appear Click on the "Run Report Now" button within the modal-d ...

Expanding VS 2013: Effective management of classes through item customization

Trying to accomplish a somewhat complex task, I have dedicated hours to searching for the appropriate documentation with no success. The goal is for Visual Studio to generate some JavaScript code and place it in a specific folder, starting from: Performi ...

Do we really need to use Express-validator's isString() function for Node?

While using Node/Express/Express-Validator, I have noticed that all my request variables are being received as strings by the server. However, this raises questions about the relevance of certain checks like 'isString()' in the code snippet belo ...

Attempting to deploy my initial Google Cloud Function, encountering an error message indicating that Express is not detected

Currently in the process of deploying my first Google Cloud function, the code for which can be found here: https://github.com/rldaulton/GCF-Stripe/blob/master/Charge%20Customer/index.js The code starts with the following line: var app = require('e ...

Exploring methods for obtaining client origin in Vue

I have a variety of domains such as https://www.ilajobs.com and levelcoding.com When attempting to retrieve the client's origin using the following code: getOrigin() { this.origin = window.location.origin; }, The expected result should be: ilajob ...

Is the ID "nodeName" specifically designated as reserved in the HTML5 language specifications?

I have an element with the following id: <span id="nodeName"></span> In my HTML code. Then, when using jQuery to do the following: $("#nodeName").html("someString"); I am getting an error in the console that says: Uncaught TypeError: Objec ...

Receiving JSON information rather than frontend markup code

My express backend organizes its routers in the following order: 1. All the API routes (e.g. /notes) 2. The catch-all route that serves all frontend code from the React build folder. On the client side, I use React Router with routes named differently ...

What is the best way to manage multiple arrays?

There is an array containing multiple arrays within it. I am trying to locate the specific sub-array that contains an object with name: "tax-payer-identification". Once found, I need to set the variable's value from required: true to false. ...

Error message in Mysql connector for NodeJS: Pool has been closed

We have developed a NodeJS application that functions as an API for a frontend Angular project we are currently working on. So far, both components have been operating smoothly. However, occasionally we encounter a strange error with the API stating "Pool ...

In JavaScript, eliminate all characters in a string after the second hyphen using only one line of code

Is it possible to extract the language from a string before the 2nd occurrence of a dash (-) using a single line of Javascript? For example: en-AU-Option-A would become en-AU ...

Updating the language of the months displayed in the popup calendar

I am attempting to change the language of the clickDate function from English (Jan, Dec, etc.) to another language. However, I am struggling to find a way to do so because I only have access to the scripts provided below. The idate is in the format 2015073 ...

The React Router onEnter Function Error: "Maximum call stack size exceeded"

I'm currently checking if a specific configuration value is set, and if it is, I want to redirect to a child route. If not, the page should display as usual. However, when I implement this code, the URL updates as expected but then seems to get stuck ...