Ways to simulate a constant that acts as a dependency for the service being examined?

I'm currently experimenting with a file named connect-key.js. It relies on a dependency called keyvault-emulator.

Content of File #1:

// connect-key.js file
const { save, retrieve, init  } = require('./keyvault-emulator')
....
....
....
// SOME TESTS

Content of File #2:

// The keyvault-emulator.js file
const { storageConnectionString } = require('../config')

Now, I'm wondering how to simulate the value of storageConnectionString in my test file connect-key.spec.js?

My idea is something like this:

// The connect-key.spec.js file
const keyvault_emulator = require('../keyvault-emulator');
const spy = jest.spyOn(keyvault_emulator, 'storageConnectionString');
spy.mockReturnValue('');

This is the content of the config file:

// config.js file
module.exports = {
  storageConnectionString: process.env.STORAGE_CONNECTION_STRING || process.env.Storage,
  keyVaultName: process.env.KEY_VAULT
}

Is this the correct approach? What is the optimal way to achieve this?

Answer №1

Exploring Mocking Internal Dependencies

Prior to mocking internal dependencies, it is essential to define the purpose behind it; especially considering Jest's limitations in this regard. This article aims to present some potential scenarios and examples that can shed light on this topic.

Let's delve into a hypothetical scenario where there exists a function named testFunction() that returns the previously mentioned storageConnectionString.

1. Targeting Specific Functions within Test Scope

// key.spec.js
const keyvault_emulator = require('../keyvault-emulator');
js.mock('../keyvault-emulator', () => ({
  // everything remains untouched except for testFunction
  ...jest.requireActual('../keyvault-emulator'),
  // mock implementation of testFunction
  testFunction: jest.fn(() => 'mocked')
})

// ✅ Success
expect(keyvault_emulator.testFunction()).toEqual('mocked')
// ❌ Failure!
expect(keyvault_emulator.otherFunctionUsingStorageConnectionString())
  .toEqual('mocked')

2. Replacing all Module Content

In Jest, the capability lies in substituting an entire function or module rather than re-evaluating code snippets. In cases like this, decoupling dependencies such as config.js and keyvault-emulator.js from the source proves to be beneficial for testing purposes.

2-1. Implementing Hard Decoupling directly in the Source

// keyvault-emulator.js
class KeyValueEmulator {
  constructor(externalConfig) {
    this.externalConfig = externalConfig;
  }
  testFunction() {
    // process involving this.externalConfig
    return this.externalConfig;
  }
}

// key.spec.js
const mockedExternalConfig = { storageConnectionConfig: 'mocked' }
const keyValueEmulator = new KeyValueEmulator(mockedExternalConfig);
// ✅ Successful execution
expect(keyValueEmulator.testFunction()).toEqual('mocked')

2-2. Employing Soft Decoupling with Jest's Internal Module Mocking

Refer to working codes on GitHub

// key.spec.js
import config from "./config";
jest.mock("./config", () => ({ default: { storageConnectionString: "mocked" } }));
import { storageConnectionString, testFunction } from "./index";

describe("config mocking", () => {
  it("value is mocked", () => {
    // ✅ Works as expected
    expect(config.storageConnectionString).toEqual("mocked");
    expect(testFunction()).toEqual("mocked");
  });
});

3. Mocking a Single Variable

As elaborated in case 2, mocking a single variable poses challenges with Jest's current functionalities. Hence, precise clarification and adjustments are needed when attempting such operations.

// key.spec.js
const keyvault_emulator = require('../keyvault-emulator');
const spy = jest.spyOn(keyvault_emulator, 'storageConnectionString');
spy.mockReturnValue('mocked');
// ✅ Potential success...however
expect(keyvault_emulator.storageConnectionString).toEqual('mocked')
// ❌ Unsuccessful outcome
expect(keyvault_emulator.testFunction()).toEqual('mocked')

Determining the Optimal Approach

Is this method considered effective? What strategy works best for achieving desired outcomes?

Similar to numerous developer dilemmas, the most suitable approach varies depending on the specific context. While opting for hard decoupling, as highlighted in 2-1, serves well in many scenarios, it may not always be the perfect solution. Select the methodology that aligns seamlessly with your unique circumstances.

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

How can we eliminate duplicate objects in a JavaScript array by comparing their object keys?

I am trying to remove duplicate objects from an Array. For example, the object 'bison' appears twice. var beasts = [ {'ant':false}, {'bison':true}, {'camel':true}, {'duck':false}, {'bison':false} ...

How can you determine the class of an element that was clicked within an iframe?

Is it possible to retrieve the class of an element that is clicked within an iframe? Here is the HTML code: <input id="tag" type="text"> <iframe id="framer" src="SameDomainSamePort.html"></iframe> This is the JavaScript code: $(docum ...

Use an Ajax call to "POST" and fetch the Jade layout for rendering

So, I have my own custom AJAX function. export function dynamicURL(obj) { $.ajax({ url: obj.url, type: 'post', data: obj.jade, dataType: 'JSON' }).done(function (ajaxReturn) { console.lo ...

Creating HTML tabs using jQuery with input[type="radio"] tutorial for beginners

I'm having trouble creating a tab with input[type="radio"] using Jquery. The tab works fine on the first click, but it doesn't work on the second click. I can't figure out where the issue is in the Jquery code. Can someone assist m ...

How to unload and remove an object imported with OBJLoader in Three.js

I'm facing a small issue that I can't seem to figure out. I've successfully added an object to my scene using OBJLoader, but now I need to remove it. I've tried clearing the scene.children with code, but it doesn't delete the "flow ...

What is the procedure for obtaining an Observable for an Event?

How can I obtain an Observable of an Event in Angular 2? For instance, is it possible to subscribe to a click event but only trigger after two clicks? Can we create an Observable of MouseClick event objects? If I want to filter by button or ctrlKey, or h ...

Encountering issues while trying to establish a connection to MongoDB through JavaScript

I have developed a code for seamlessly integrating various social networking logins with nodejs. Below is my server.js file: // include the necessary tools var express = require('express'); var app = express(); var port = process.env ...

Develop a diverse range of form types within Django forms

Even though I know how to create a form set based on a given form type, it doesn't completely resolve the issue at hand. Imagine having a fast food portal where users can add items and depending on their selection, additional fields need to be dynami ...

The canvas element automatically removes itself after being resized within an HTML5/JavaScript environment

I created a canvas that is interactive and responsive to screen size. However, I encountered an issue where the canvas clears itself when the browser is resized by just one pixel. Is there a way to prevent this from happening? I have included code in my sc ...

The issue of Ng-Route not functioning properly on a Node/Express static server

I need assistance with my app.js file that currently directs all requests to pages/index.html. Now I am attempting to utilize Angular to route user requests for '/#/media' by adding the following code: academy.config(function($routeProvider) { ...

Determine the total number of arrays present in the JSON data

I'm currently working on a straightforward AngularJS project, and here's the code I have so far: This is my view: <tr ng-repeat="metering in meterings"> <td>1</td> <td>{{metering.d.SerialNumber}}</td> ...

What is the best approach to managing a Symfony form that contains TWO CollectionType child forms?

I have been referring to the Symfony guide here which explains how to generate and save a collection of associated entities within a form. Following the example provided in the guide, I have successfully implemented the functionality for adding and removi ...

Securing a JWT token post login

I am new to NodeJS and despite trying numerous solutions, I am facing a challenge. My project involves NodeJS, MongoDB, Express, and Vanilla JS rendered through Pug with an MVC structure. Issue Current Status: I can successfully log in a user and recei ...

Implementing the 'keepAlive' feature in Axios with NodeJS

I've scoured through numerous sources of documentation, Stack Overflow threads, and various blog posts but I'm still unable to make the 'keepAlive' functionality work. What could I be overlooking? Here's my server setup: import ex ...

When using `res.send()`, an error of Type Error may be encountered stating that the callback is not a function. However, despite this error,

I am currently working on a function for my Node.js server, using Express as the framework and MongoDB as the database. This function involves calling two mongoose queries: (1) Retrieving filtered data from one collection (2) Aggregating data from anothe ...

problems with hovering over radio buttons in Internet Explorer 9

Encountering a curious issue in IE9: When hovering over my top level wrapper div, the first radio button seems to be triggered as though it's being hovered over. This means that even if the last radio input is selected, clicking anywhere within the wr ...

An issue is preventing the Angular 2+ http service from making the requested call to the server

I am looking to create a model class that can access services in Angular. Let's say I have the following endpoints: /book/:id /book/:id/author I want to use a service called BooksService to retrieve a list of Book instances. These instances should ...

Swapping out the main view for the partial view

Recently, I wrote some jQuery code to fetch data from an action by passing in a dashID. The expected result was to receive HTML containing the relevant information. Unfortunately, my jQuery script is not returning the desired data. Below is the JavaScript ...

Add a JavaScript library to the header directly from the body of a webpage, ensuring it is exclusive to a single

I am using the Google Charts JS library on a single page within my project, with external and global headers and footers. The head tags are located in a head.php file, where all required JS libraries are included. The structure of my pages is as follows: ...

Java REST service remains out of reach for JavaScript fetch call

Currently, I am in the process of learning about REST API. My goal is to make a call to a POST service implemented in Java from Javascript using fetch. However, I have encountered an issue where the request fails to reach the service whenever the @Produces ...