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

Looking to develop a dynamic password verification form control?

I am in the process of developing a material password confirmation component that can be seamlessly integrated with Angular Reactive Forms. This will allow the same component to be utilized in both Registration and Password Reset forms. If you would like ...

Come hang out in the user voice channel by reacting with your favorite emojis!

I am currently developing a Discord bot, and I want to implement a feature where the bot joins a voice channel if a user reacts to its message. I am using the awaitReactions function which only returns reaction and user data. Is there a way to retrieve th ...

Utilizing HTML, CSS, and JavaScript to dynamically add and remove a class from

I've been struggling with a specific issue in my 9-button grid. When I click on a button and it changes color to orange, if I click on another button, both buttons remain orange. What I want is for only one button at a time to be orange - when a new b ...

Mastering the Implementation of Timetable.js in Angular with TypeScript

I am currently working on integrating an amazing JavaScript plugin called Timetable.js into my Angular6 project. You can find the plugin here and its repository on Github here. While searching for a way to implement this plugin, I stumbled upon a helpful ...

Exploring the possibilities of integrating Keycloak with the powerful nuxt-auth

I am incorporating this particular authentication module in conjunction with Keycloak. In my nuxt.config.js configuration: keycloak: { _scheme: 'oauth2', client_id: 'client-bo', userinfo_endpoint: 'SERVER/protocol/open ...

Tips for adjusting the animation position in Off-Canvas Menu Effects

I am currently utilizing the wave menu effect from OffCanvasMenuEffects. You can view this menu in action below: ... // CSS code snippets here <link rel="stylesheet" type="text/css" href="https://tympanus.net/Development/OffCanvasMenuEffects/fonts/f ...

Sending a post request to an Express.js API from a different device

I currently have a server running on localhost:3000, with my app.js set up to utilize the angular router. When attempting to access localhost:3000 in my browser (for example: app.use('/', express.static(path.join(__dirname, '/dist/Client&apo ...

Exploring NodeJS and ExpressJS: Unveiling the significance of routes/index.js

Can you explain the function of this particular file? Does this file handle all the GET and POST requests in a project? If so, wouldn't it become excessively long and complex for larger projects? I encountered an issue when trying to call a POST re ...

Shuffling 4 div elements horizontally using Javascript and JQuery

I have a row of 4 div elements (cards) that I want to mix up every time the page is refreshed. How can I achieve this? Currently, I am using the following code: var random = Math.floor(Math.random() * $(".card").length); $(".card") .hide() ...

Utilizing JQuery for retrieving a filename

I have a unique file upload button on my website. To provide the user with visual feedback about their chosen file, I modify the html of a div to display the file name. My jquery code is as follows: $("input[type=file]").change(function() { var filen ...

Having issues with @react-three/drei in next.js environment

Having trouble using drei materials and other features like MeshWobbleMaterial, MeshDistortMaterial, or ContactShadows? You may encounter errors such as: react-three-fiber.esm.js:1383 Uncaught TypeError: Cannot read property 'getState' of null a ...

Is there a way to automatically generate and allocate an identifier to an input field?

I've written the code below, but I'm having trouble figuring out if it's accurate. Specifically, I can't seem to access the text inputs that have been created by their respective id attributes. for (i=0;i<t;i++) { div.innerHTML=div. ...

Unable to locate an element on the webpage due to a JavaScript-based error, which then becomes hidden after a few seconds. (Registration form)

While completing a registration form, I encounter a hidden message after clicking on the register button. Struggling to locate this elusive element has been an ongoing challenge for me. Unfortunately, my attempts to find the element have been unsuccessful ...

Achieving sequential actions in Javascript without the need for state updates

One aspect of jQuery that I find impressive is its ability to chain methods like .animate() and .css(). This is made possible by utilizing the special variable "this" in the backend code. I am interested in implementing a similar method chaining mechanism ...

Despite encountering an error in my terminal, my web application is still functioning properly

My code for the page is showing an error, particularly on the home route where I attempted to link another compose page The error message reads as follows: Server started on port 3000 Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after t at new Node ...

What is the process of importing a JSON data file and utilizing it within a React component?

As a beginner in React, I am struggling with the concepts of importing, exporting, and rendering components. I have a fakeData.json file within the same src/components folder as the component I want to render. Let's take a look at the structure: < ...

Get rid of the folder from the URL using an <a> tag

I have both an English and French version of my website located at: *website.com/fr/index.php *website.com/index.php Currently, I have a direct link to switch between the two versions: -website.com/fr/index.php -website.com/index.php. However, I ...

What is the best approach for addressing null values within my sorting function?

I created a React table with sortable headers for ascending and descending values. It works by converting string values to numbers for sorting. However, my numeric(x) function encounters an issue when it comes across a null value in my dataset. This is th ...

Mapping JSON data from Mongoose to Vue and Quasar: A comprehensive guide

I have set up a Mongoose backend and created some REST APIs to serve data to my Vue/Quasar frontend. The setup is pretty basic at the moment, utilizing Node/Express http for API calls without Axios or similar tools yet. I have successfully implemented simp ...

Having trouble with changing the state within an AngularJS (Ionic Framework) controller?

My goal is to switch views within the Search controller after receiving search results from the server through $http. However, my current approach doesn't seem to be working as intended. I also need to pass the response to the new view for displaying ...