The issue arises when Jest fails to align with a custom error type while utilizing dynamic imports

In my project, I have defined a custom error in a file named 'errors.ts':

export class CustomError extends Error {
    constructor(message?: string) {
        super(message);
        Object.setPrototypeOf(this, Error.prototype);
        this.name = this.constructor.name;
    }
}

Additionally, there is a module that utilizes this custom error in a file called 'main.ts':

import { CustomError } from './errors';

let called = false;
export default {
    throwAfterFirst: (): void => {
        if (called) throw new CustomError();
        called = true;
    },
};

To test this setup with jest and utilize dynamic imports to reset a variable, I created the following test file:

import { CustomError } from './errors';

let main: typeof import('./main').default;
const load = async (): Promise<typeof import('./main').default> => {
    jest.resetModules();
    main = (await import('./main')).default;
};

describe('Main', () => {
    beforeEach(async () => {
        await load();
    });

    it('should throw on second time', () => {
        main.throwAfterFirst();
        expect(() => main.throwAfterFirst()).toThrowError(CustomError);
    });

    it('should still throw on second time', () => {
        main.throwAfterFirst();
        expect(() => main.throwAfterFirst()).toThrowError(CustomError);
    });
});

However, there seems to be an issue where the toThrowError function is not correctly matching the expected and received constructors for the CustomError. This problem does not occur when using regular errors like TypeError. Interestingly, without dynamic importing, the tests pass successfully as shown below:

import { CustomError } from './errors';
import main from './main';

describe('Main', () => {
    it('should throw on second time', () => {
        main.throwAfterFirst();
        expect(() => main.throwAfterFirst()).toThrowError(CustomError);
    });
});

It appears that due to the dynamic import usage, the CustomError may not be recognized correctly or have the same prototype causing the mismatch. What am I overlooking here, and what steps can I take to fix this testing issue? I still aim to specifically check for the CustomError and avoid using toThrow which matches any error. It's worth noting that toThrow works in this scenario.

Answer №1

Here is the workaround I discovered:

let main: typeof import('./main').default;
let Errors: typeof import('./errors');
const load = async (): Promise<void> => {
    jest.resetModules();
    main = (await import('./main')).default;
    Errors = await import('./errors');
};

describe('Main', () => {
    beforeEach(async () => {
        await load();
    });

    it('should throw on second time', () => {
        manager.throwAfterFirst();
        expect(() => manager.throwAfterFirst()).toThrowError(Errors.CustomError);
    });

    it('should still throw on second time', () => {
        manager.throwAfterFirst();
        expect(() => manager.throwAfterFirst()).toThrowError(Errors.CustomError);
    });
});

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 ts-loader is used to import .json files, the declaration files are outputted into a separate

I've encountered a peculiar issue with my ts-loader. When I import a *.json file from node_modules, the declaration files are being generated in a subfolder within dist/ instead of directly in the dist/ folder as expected. Here is the structure of my ...

Error: The function wrapper.find().simulate('keypress', {key: 'Enter', keycode: 13}) is not working as expected

Let's discuss further about this query vue-btn isn't triggering on pressing the enter key I have designed a sign-in page where users can log in by pressing 'Enter' on the keyboard. Now, I aim to perform a unit test that simulates pres ...

Why do referees attempt to access fields directly instead of using getters and setters?

I am facing an issue with my TypeScript class implementation: class FooClass { private _Id:number=0 ; private _PrCode: number =0; public get Id(): number { return this._Id; } public set Id(id: number) { this._Idprod ...

In Typescript ReactJS, how can the useReducer hook be implemented to increment a particular property of an object upon clicking a button?

Is there a better way to increase the property values of an Attribute object (STR, AGI, INT, and CHA) using useReducer actions? I currently have separate actions for each property, but it leads to a lot of redundant code. I'm looking for a more effici ...

Angular 2 implementes a loading spinner for every HTTP request made

My objective is to implement a spinner functionality whenever an HTTP request occurs in my Angular app. Essentially, I want the user to see a loading screen during these requests within my app component. The setup for my spinner component and spinner servi ...

Defining optional parameters in TypeScript

Currently, I am working on implementing strong typing for a flux framework (specifically Vuex). Here is my current code: const actions = { first(context: Context, payload: string) { return doSomething(context, payload); }, second(context: Context) { r ...

Utilize an array of JSON objects to populate an array of interfaces in Angular/Typescript

I am currently facing a dilemma - my code is functioning without any errors when executed, but my text editor is flagging an issue stating that the property 'categories' does not exist on type 'CategoryInterface[]' (specifically on the ...

React and MaterialUI Chrome Extension - Data did not populate in the table

Currently, I am in the process of developing a browser extension. My main challenge lies in displaying data within a table that has been created using MaterialUI and React. Despite not encountering any errors, everything else renders perfectly. The console ...

Is there a glitch in the angular binding mechanism?

I am working with a component that includes a select option and a text input field. The purpose of the "select" is to choose a description of an object, while the input field is used to specify the quantity assigned to the selected object. In my form, I ne ...

Can the detectChanges() method in Angular cause any issues when used with the form control's valueChanges event?

Within my parent Component, I am working with a formGroup and updating its value using patchValue method. ngAfterViewInit() { this.sampleform.controls['a'].patchValue ...} I then pass this form to a child component in the parent component's ...

Choose the object's property name using TypeScript through an interface

Consider a simplified code snippet like the following: interface MyBase { name: string; } interface MyInterface<T extends MyBase> { base: MyBase; age: number; property: "name" // should be: "string" but only p ...

Skipping the created hook in Vue Test Utils is a useful feature that allows

Is there a way to skip all the methods called within the created() hook? Instead of: created() { this.getAllocations(); this.getModels(); this.getTeams(); this.getCustodians(); this.getD ...

Error encountered in Node.js OpenAI wrapper: BadRequestError (400) - The uploaded image must be in PNG format and cannot exceed 4 MB

Attempting to utilize the OpenAI Dall-e 2 to modify one of my images using the official Nodejs SDK. However, encountering an issue: This is the snippet of code: const image = fs.createReadStream(`./dist/lab/${interaction.user.id}.png`) const mask = fs.c ...

Why do Material UI components fail to render in jsdom while using Jest?

During my UI testing using Jest/React Testing Library, I encountered a peculiar issue. In one of my components, the return statement is structured as follows: const sidebarContentUp = ( <Drawer anchor="left" onClose={onMobileC ...

Utilize string variables within TypeScript's enumeration feature

Can string variables be used in enums in TypeScript? Strings can be used in enum like so: enum AllDirections { TOP = 'top', BOTTOM = 'bottom', LEFT = 'left', RIGHT = 'right', } However, trying to use variab ...

Exploring the possibility of integrating direct search functionality into the URL bar within an Angular application

One interesting feature I observed on GitHub is that after typing "github.com" in the URL bar, you can directly search by pressing the spacebar, which activates the "search mode." Here's how it looks like on Chrome: I'm curious, how can I implem ...

The 'Alias[]' type does not share any properties with the 'Alias' type

I encountered an issue: The error message 'Type 'Alias[]' has no properties in common with type 'Alias'' appeared. Here is my Alias setup: alias: Alias = { id: 0, domain_id: 0, source: '', dest ...

What is the process of adding an m4v video to a create-next-app using typescript?

I encountered an issue with the following error: ./components/Hero.tsx:2:0 Module not found: Can't resolve '../media/HeroVideo1-Red-Compressed.m4v' 1 | import React, { useState } from 'react'; > 2 | import Video from '../ ...

Working with Yarn and Webpack: Incorporating a TypeScript .ts file from an external Node directory not controlled by Yarn/Webpack

I am currently working on a k6 project for load testing, utilizing Yarn and Webpack. This project is stored within a sub-folder of a larger repository that primarily uses npm Node modules. My goal is to access a secret from AWS's Secrets Manager in t ...

A guide on passing an ngFor object variable to a function

I am trying to display subcategories for each category in my *ngFor list. The subcategory data is retrieved from Firebase using the category_id, but I am struggling to pass the category_id from the HTML to the function for every member of the category. ho ...