Dealing with Class and Instance Problems in Mocha / Sinon Unit Testing for JavaScript

Currently, I am working on unit testing an express middleware that relies on custom classes I have developed.

Middleware.js

const MyClass = require('../../lib/MyClass');

const myClassInstance = new MyClass();

    function someMiddleware(req, res) {
        myClassInstance.get().then(function(resp) {
          res.render('somefile.html');
        });
    };

Test.js

const MyClass = require('../../lib/MyClass');
const sinon = require('sinon');
const chai = require('chai');
const expect = chai.expect;

// The file under test
const someMiddleware = require('path/to/middleware');

MyClassMock = sinon.spy(function() {
    return sinon.createStubInstance(MyClassMock);
});
describe('Testing My Middleware', function() {

    let renderSpy, classStub;
    let res = {
        render: function() {}
    }

    beforeEach(function() {
        renderSpy = sinon.stub(res, 'render');
    })

    afterEach(function() {
        renderSpy.restore();
    })

    it('should invoke the render function', function() {

        someMiddleware.someMiddleware(req, res);
        expect(renderSpy.calledOnce);

    });
});

I have attempted various methods to mock the class and its instances without success. Unfortunately, every time it executes, the actual class along with its dependencies are invoked.

Cheers everyone!

Answer №1

Your Objective: Substitute or provide placeholders for the dependencies of your middleware function.

The Challenge: It is not feasible to achieve this externally from your module. You must somehow intercept and control which code gets utilized.

There are two approaches, both extensively discussed in other sources (1, 2, 3). Here is a shortened version:

Manual Dependency Injection

In your middleware module, include a

__setMyClassInstance(stubbedInstance)
method that is specifically invoked during testing.

  • Advantage: simple implementation without the need for additional frameworks
  • Disadvantage: test-specific code that exposes internal workings of your module

Link Seams

This involves substituting require() calls with an alternative module loader that returns customized objects. In your test script:

const myMiddleware = proxyquire('../../src/middleware', { '../../lib/MyClass': myStubbedInstance })
  • Advantage: achieves the same result as DI but without modifying the original module
  • Disadvantage: can be less clear on the process, requires understanding of a new dependency

If these brief explanations leave you puzzled, I recommend delving into the detailed discussions provided in the links, including tutorials on Link Seam tools like proxyquire and rewire.

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

What is the process for toggling a button using Vue.js?

Important Note: Implemented Vue.js and Vuetify.js for both functionality and styling. Utilizing the :class and @click properties, I managed to alter the background color of a button to a specified color. However, this modification is being applied to all ...

Is there a way to reverse a string in Javascript without using any built-in functions?

I am looking for a way to reverse a string without using built-in functions like split, reverse, and join. I came across this code snippet on Stack Overflow (), but I'm having trouble understanding what the code does on the fourth line. I need more cl ...

Frequent 502 bad gateway issue arising intermittently on server configuration with nginx, nodejs, and mongodb stack

We are currently using nodejs(v 0.10.29), express, nginx(version 1.4.6) with mongodb(v 2.6.3) replicaset and encountering sporadic 502 bad gateway errors. Although pm2 logs fail to capture the error, nginx's error.log is indicating: recv() failed (10 ...

Incorporating a CSS stylesheet into the theme settings of the Stratus 2 Beta platform

I have been attempting to personalize my Stratus 2 Beta by implementing a custom theme. I created a separate CSS file named "stratus.css" and stored it in the CSS directory of my website - with the CSS code being identical to this example. Below is my Jav ...

Angular 6 - Consistently returning a value of -1

I'm facing an issue with updating a record in my service where the changes are not being reflected in the component's data. listData contains all the necessary information. All variables have relevant data stored in them. For example: 1, 1, my ...

Does aoMap function exclusively with THREE.BufferGeometry?

Can you provide guidance on setting up an aoMap for a standard THREE.Geometry object? Is there a demo available to reference? var uvCoordinates = geometry.attributes.uv.array; geometry.addAttribute('uv2', new THREE.BufferAttribute(uvCoordina ...

The function insertAdjacentHTML does not seem to be functioning properly when used with a

I am working with a parent element that contains some child elements. I create a DocumentFragment and clone certain nodes, adding them to the fragment. Then, I attempt to insert the fragment into the DOM using the insertAdjacentHTML method. Here is an ex ...

retrieving request headers using XMLHttpRequest

Is there a way for me to access my requestHeaders within the onload function? Any guidance on how to achieve this would be greatly appreciated. Many thanks! ...

Dynamically change the content of the DataTable by utilizing jQuery

I am facing an issue with updating a DataTable using jQuery when the contents of the table are modified. Initially, I have a HTML table with an empty tbody, which is populated dynamically based on selected filters such as select options. The table uses Dat ...

When using Node.js, the process.exit() function will not terminate if there is an open createReadStream

My program interacts with Asterisk using EAGI, where Asterisk communicates with my Node.js application by sending data via STDIN and receiving commands via STDOUT. When a user ends the call, the Node.js process receives a SIGHUP signal for clean terminatio ...

Automatically formatting text upon entering it in Vue.js

I need assistance with auto-formatting the postal code entered by the user. The rule for the postal code is to use the format A0A 0A0 or 12345. If the user inputs a code like L9V0C7, it should automatically reformat to L9V 0C7. However, if the postal code ...

Why am I unable to attach this to JQuery?

$("input").keydown(function(event){ if(event.keyCode === 13){ return false; } }); I need to prevent the default action when the "enter" key is pressed in any of my text input fie ...

Tips for positioning and resizing images within a changing DIV dimension

My DIV element is adjusting its size based on the browser window. Inside this DIV, there is an image that should fill up the entire browser window without stretching out of proportion when the window dimensions change. In addition, I want the image to be ...

Discovering when the DOM has finished rendering in AngularJS with ng-repeat

I am looking for a way to trigger an alert or message upon completion of rendering in my HTML DOM using AngularJS, specifically when dealing with multiple ng-repeats. HTML Code: <body> <div ng-controller="Ctrl"> <div ng-repeat= ...

Error Loading JQuery: The function $() is not recognized in the Shopify platform

I seem to be overlooking something obvious. I am using Shopify and have included jQuery in the head section of the theme.liquid file: <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> This script is placed rig ...

Encountering a console error: Prop type validation failed for the `Rating` component with the message that the prop `value` is required but is currently `undefined`

I am encountering a proptype error which is causing an issue with the URL display on my Chrome browser. Instead of showing a proper address, I am seeing the URL as undefined like this: http://localhost:3000/order/undefined Instead of undefined, I should h ...

What can be done to ensure that constant and variable values do not reset when the page is refreshed?

In the process of developing a web application similar to Wordle, but for songs, I have successfully implemented the onClick function. Currently, the song/audio changes with each page render, but I am looking to make it change every 24 hours or at a fixed ...

What is the best way to halt Keyframe Animation once users have logged in?

To enhance user engagement, I incorporated keyframe animation into my login icon on the website. The main objective is to capture the attention of visitors who are not registered users. However, once a user logs in, I intend for the keyframe animation to c ...

Is it necessary to create event objects before setting event handlers in Leaflet JS?

I'm currently working on creating event handlers that respond to the success of the location() method in the leaflet JavaScript map class Here is my current implementation: function initializeMap() { var map = L.map('map').locate({setV ...

Creating unique identifiers/primary keys for resources in react-admin: A step-by-step guide

I am working on a nextJS project that utilizes redux for state management and an admin panel called react admin. In my project, I decided to use _id instead of id as the keys. To achieve this, I followed the instructions provided in this custom identifiers ...