Unit testing TypeScript code by creating a mock of the third-party library, ioredis

Struggling to mock a third party library in typescript tests is proving to be quite a challenge.

Currently, I am developing a library based on the foundation of the typescript-starter library that utilizes ava for testing.

Specifically, I am attempting to mock the primary class of ioredis to prevent my tests from establishing real database connections.

Various attempts have been made using different mocking libraries such as sinon, testdouble.js, and mockery.

For instance, in sinon, I experimented with the following:

let redisStub = sinon.stub(IORedis)
sinon.assert.called(redisStub.Cluster)

Using testdouble, I tried various strategies, such as:

td.replace('ioredis') // #1
td.replace('./homeMadeIoredisWrapperClass') // #2

Additionally, I explored the use of mockery

mockery.enable()
mockery.registerMock('ioredis', {some: 'object'})

Despite multiple attempts, including always using require('ioredis') in the methods, the challenge persists.

Could it be that I am attempting the impossible? Mocking a database seems to be a common practice, yet the solution eludes me. Perhaps my approach is flawed, and I am targeting the wrong elements for mocking?

Any guidance on this matter would be greatly appreciated!


Ps. For context, I am striving to develop a straightforward ioredis connection wrapper.

Answer №1

If you need to mimic ioredis (version 4.16.2), you can achieve this using sinon. The key is to mock the connect method.

import ioredis from "ioredis";

sinon.stub(ioredis.prototype, "connect").returns(Promise.resolve());
sinon.stub(ioredis.prototype, "get").returns(Promise.resolve({ data: "hello" }));

Answer №2

After encountering a few misunderstandings and issues in my code, I stumbled upon some valuable insights that may benefit others facing similar challenges:

  1. One issue I faced was importing "everything" (
    import { MyLibrary } from "myLibrary"
    ) before the td.replace, causing the replacement statement to execute after the module had been required. This was due to the specific design of the example tests in the typescript-starter repository. I have addressed this issue by submitting a PR to resolve the underlying problem.
  2. Another challenge arose from running the ava tests in parallel, leading to td.reset() occurring before some callbacks were triggered, thereby hindering the functionality of replace in certain scenarios. To overcome this, I switched to using test.serial(... in place of test(... in ava. Although this may slow down the test execution, it ensures their proper functioning. Creating separate files for each test enables true parallel runs in ava.

Additionally, I discovered some helpful wiki entries on the testdouble GitHub page: https://github.com/testdouble/contributing-tests/wiki/Don%27t-mock-what-you-don%27t-own https://github.com/testdouble/contributing-tests/wiki/SAFE-test

I trust that these insights will prove beneficial to someone in a similar situation.

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

When viewing a React data table in Chromium browsers, the columns on the right side may flicker when the screen is small or the browser

I recently integrated the React data grid Npm package by adazzle. You can find more information about it here. I encountered an issue which you can see in this example: https://codesandbox.io/s/react-data-grid-example-9sb93?file=/src/App.tsx When using a ...

The implementation of CommonJS modules allows for efficient modularization

While using Nx for my Angular workspace, I noticed something that sparked a question in my mind. Why is it necessary to use CommonJS modules in all tsconfig.spec.json files for libs? Looking at Nx examples, I observed that not all libs include it, only app ...

Creating nested return types: A guide to defining function return types within a Typescript class

My large classes contain functions that return complex objects which I am looking to refactor. class BigClass { ... getReferenceInfo(word: string): { isInReferenceList:boolean, referenceLabels:string[] } { ... } } I am considering somethi ...

What is the best way to connect to a library using a script within a Typescript React application?

I'm a newbie to React and haven't worked on web development in years, so I'm facing a basic issue: Currently, I'm working on implementing a Stripe-based payment flow in a React web app (written in Typescript) and I've hit a roadbl ...

Using Typescript to define property types based on their respective values

Is it possible to set a property type based on the property value? For example, if the command is: If 'set' then the payload must be PayloadSet If 'put' then the payload must be PayloadPut If 'del' then the payload must be ...

Find the calculated values within an Angular Material table

I came across this fantastic example of an Angular Material table with checkboxes that fits perfectly with what I want to implement in my application. However, I am facing a challenge - I need to calculate the total value of the checked rows. Specifically, ...

Lack of MaterialUI Table props causing issues in Storybook

Currently, I am utilizing MaterialUI with some modifications to create a personalized library. My tool of choice for documentation is Storybook, using Typescript. An issue I have encountered is that the storybook table props are not consistently auto-gene ...

Encountering an issue with MUI Props: "Must provide 4 to 5 type arguments."

I'm attempting to use a custom component and pass in AutocompleteProps as a prop, all while utilizing typescript. Here's my current setup: type Props = { autoCompleteProps?: AutocompleteProps<T> label: string loading?: boolean } cons ...

The attribute 'use' is not found within the data type 'typeof...', and the property 'extend' is not present within the data type 'typeof'

As I embark on building my very first Vue app using TypeScript, I find myself facing a frustrating issue: Property 'xxx' does not exist on type 'typeof. Despite my efforts to research similar problems, none of the suggested solutions have pr ...

Exciting Angular feature: Dynamic Titles

I am working with an <i> tag <i class="actionicon icon-star" [ngClass]="{'yellow' : data.isLiked}" (click)="Like(data)" aria-hidden="true" title="Liked"></i> In my current set ...

Tips for implementing Bootstrap dropdown functionality in an Angular2 project

For my latest project, I wanted to incorporate dropdown menus. I found a code snippet on a website and implemented it. However, although the dropdown menu appeared as expected, I encountered an issue where clicking on it did not trigger any actions. & ...

I am having trouble figuring out the issue with the state and how to properly implement it in Typescript

I am having difficulties sending emails using Nodemailer, TypeScript, and NextJS. The contact.tsx file within the state component is causing errors when using setform. As a beginner in TypeScript, I have been unable to find a solution to this issue. Any he ...

Discovering the name of an object property by locating its corresponding id

I am working with a basic JSON data structure where I need to retrieve the name from an object by comparing its ID. For example, if I have the number 2, I need to check if it matches any object's ID. If the ID is equal to 2, then I must fetch the corr ...

Is it possible to regulate the type of a class that has not yet been instantiated?

Is there a method in typescript to restrict the type of an uninstantiated class? I am looking to specify that only classes which inherit from Repository can be accepted by the addRepository method without actually creating an instance of the class (its co ...

The error code TS2345 indicates that the argument type 'Event' cannot be assigned to a parameter type 'string'

Hello, I'm a newcomer to utilizing Angular and I'm struggling to identify where my mistake lies. Below is the TypeScript code in question: import { Component } from '@angular/core'; @Component({ selector: 'app-root' ...

What was the process for implementing the lexer and parser?

My journey into the depths of programming languages led me to explore how TypeScript is implemented, prompting me to venture into its Github repository. Within the language's source code under /src/compiler, I stumbled upon intriguing files like scan ...

Issue with interface result: does not match type

Hey there! I've been working on creating an interface in TypeScript to achieve the desired return as shown below: { "field": "departament_name", "errors": [ "constraint": "O nome do departam ...

What is the best way to generate a dummy ExecutionContext for testing the CanActivate function in unit testing?

In my authGuard service, I have a canActivate function with the following signature: export interface ExecutionContext extends ArgumentsHost { /** * Returns the *type* of the controller class which the current handler belongs to. */ get ...

Using Angular 6 HttpClient to retrieve an object of a specific class

Previously, we were able to validate objects returned from http api calls using the instanceof keyword in Angular. However, with the introduction of the new HttpClient Module, this method no longer works. I have tried various simple methods, but the type c ...

Exploring the capabilities of Angular2 and Jasmine through testing

I have been working on a basic spec for a component and I'm curious about the test's behavior. The test is designed to verify if a component is successfully created. It seems that when the test is executed, it first compiles and runs the Compone ...