Unable to simulate a static method in Vitest - encountering an error stating "is not a function"

I am currently writing unit tests using the Vitest framework for my TypeScript and React application, but I have encountered an issue with mocking static methods.

Below is a snippet of my code:

export class Person {
  private age: number;

  constructor(public name: string) {
    this.age = 20;
  }

  public getAge() {
    return this.age;
  }
}

export class StaticPerson {
  public static getAge() {
    return 20;
  }
}
import { Person, StaticPerson } from "./person";

export class Interviewer {
  public askAge(): number {
    const person = new Person("John");
    return person.getAge();
  }

  public askStaticAge(): number {
    return StaticPerson.getAge();
  }
}

Unit tests:

import { describe, it, expect, vi } from "vitest";
import { Interviewer } from "./interviewer";

// Test that passes
describe("interviewer", () => {
  it("return mocked age", () => {
    vi.mock("./person", () => {
      const Person = vi.fn(() => ({
        getAge: vi.fn(() => 15),
      }));
      return { Person };
    });

    const interviewer = new Interviewer();
    const age: number = interviewer.askAge();

    expect(age).toBe(15);
  });
});

// This test fails
it("return mocked age from static method", () => {
  vi.mock("./person", () => {
    const StaticPerson = vi.fn(() => ({
      getAge: vi.fn(() => 15),
    }));
    return { StaticPerson };
  });

  const interviewer = new Interviewer();
  const age: number = interviewer.askStaticAge();

  expect(age).toBe(15);
});

The first test, where I call the non-static method, works correctly. However, the second test, where I call the static getAge method, throws an error:

TypeError: StaticPerson.getAge is not a function
FAIL  src/interviewer.test.tsx > return mocked age from static method TypeError: StaticPerson.getAge is not a function  ❯ Interviewer.askStaticAge src/interviewer.tsx:10:25       8|        9|   public askStaticAge(): number {      10|     return StaticPerson.getAge();        |                                  ^      11|   }      12| }  ❯ src/interviewer.test.tsx:29:35 

I have searched the documentation but cannot find any information on mocking static methods or examples of how to do so.

Answer №1

If you want to avoid adding it on the prototype chain, here's an alternative approach.

import { describe, expect, it, vi } from 'vitest';
import { Interviewer } from './interview';

vi.mock('./person', () => {
  const Person = vi.fn();
  Person.prototype.getAge = vi.fn(() => 15);

  const StaticPerson = vi.fn();
  StaticPerson['getAge'] = vi.fn(() => 15);

  return { Person, StaticPerson };
});

//this test will now succeed
describe('interviewer', () => {
  it('return mocked age', () => {
    const interviewer = new Interviewer();
    const age: number = interviewer.askAge();
    expect(age).toEqual(15);
  });
});

//this test also passes
it('return mocked age from static method', () => {
  const interviewer = new Interviewer();
  const age: number = interviewer.askStaticAge();
  expect(age).toEqual(15);
});

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

A guide to implementing localStorage in TypeScript

When attempting to assign the object item to Product using this code: localStorage.setItem("Product", JSON.stringify(item)) The JSON string of item is not properly assigned to Product. Is there a solution to this issue? ...

Converting an array of objects to an array of JSON objects in TypeScript

My dilemma lies in the data I have uploaded under the _attachments variable: https://i.sstatic.net/jnFNH.png My aim is to format this data for insertion in the following structure: "_attachments": [ { "container": "string", "fileName": "string" ...

Attempting to grasp the concept of Thennables within the VSCode API. Can these TypeScript code examples be considered equivalent?

I'm looking to perform a series of modifications on a document using the VSCode API. The key function in this process is Workspace.applyEdit, which gives back a Thennable. This is my first encounter with it, and the one returned from this function doe ...

Displaying Modal from a separate component

CardComponent: export class Card extends Component<Prop, State> { state = { isCancelModalOpen: false, }; marketService = new MarketService(); deleteMarket = () => { this.marketService .deleteMar( ...

Tips for fixing the error "Module cannot be found" when testing Typescript in a Github Action

Whenever I use the Github Actions Typescript template to create a new repo and then check it out locally, I face a recurring issue: While I can work on the source code in VS Code without any problems and follow the steps mentioned in the template's re ...

Passing values in onPress method of TouchableOpacity without using arrow functions or bind function can be achieved by using JSX props. Remember not to use arrow functions in JSX props

I am working on a React Native project and I have a TouchableOpacity component in my view with an onPress method. I want to avoid using arrow functions and bind functions in the onPress method as it creates a new function every time. My goal is to pass par ...

Does having an excessive amount of variable declarations result in a noticeable decline in performance?

One thing I notice for the sake of readability is that I tend to create new variables for data that I already have on hand. I'm curious, does this impact performance significantly? Here's an example of what I mean: const isAdult = this.data.per ...

Using the function goToPage() within the TabbedHeaderPager component

I am currently working on a project that involves using TabbedHeaderPager, and I need to change tabs programmatically. I have been attempting to use the function goToPage() but have run into difficulties accessing it. I have tried passing it as a prop an ...

What is the process for creating accurate types for my package?

Currently, I am in the process of creating an npm package to be used by other developers within my company. While most aspects are functioning smoothly, I am facing challenges with getting the declarations right. I have experimented with various methods f ...

What causes the string to be treated as an object in React Native?

I am fetching a string value through an API and I need to display it in the View. However, the string value is coming as a Promise. How can I handle this? "Invariant Violation: Objects are not valid as a React child (found: object with keys {_40, _65 ...

What is the best way to execute a function that retrieves data from a MySQL query and then sends it back as a result in Express.js?

How can I refactor my code to efficiently call a function that returns the result of a MySQL query and send it back in an Express.js response? I am attempting to streamline my SQL queries by exporting them into individual functions to eliminate duplicatio ...

Retrieve the value of the specific element I have entered in the ngFor loop

I've hit a wall after trying numerous solutions. Here is the code I'm working with: HTML: import { Component } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styl ...

Tips on verifying the binding of a mat-checkbox in Angular

I am working with an Angular 6 application and want to ensure that the binding of a mat-checkbox is functioning correctly. Here is the template: <div style="text-align:center"> <mat-checkbox id="singleCheckBox" [(ngModel)]="isChecked">Check ...

Specify the return type based on specific parameter value

I'm facing a situation where I have two definitions that are identical, but I need them to behave differently based on the value of the limit parameter. Specifically, I want the first definition to return Promise<Cursor<T>> when limit is g ...

What are the steps to styling a component with CSS Emotion?

I am facing an issue with using a theme with TypeScript in this component const buttonDisabled = css` color: ${({ theme }) => theme.color}; `; Is there a way to correctly type this component? Error: No overload matches this call. Overload 1 of 2, & ...

Customizing the appearance of antd Button using emotion and typescript

I've been attempting to customize an antd Button component using emotion in TypeScript, but I encountered an error when trying to implement the styled Button. The error message I received was: Type '{ children: never[]; }' is not assignab ...

Sharing references in React Native using TypeScript: The (property) React.MutableRefObject<null>.current is potentially null

I'm working on a React Native form with multiple fields, and I want the focus to move from one field to the next when the user validates the input using the virtual keyboard. This is what I have so far: <NamedTextInput name={&apo ...

Error: The property `orderRow` in `_this.Order` is not defined

Currently, I am having some issues while working with classes: The error message displayed is: TypeError: _this.Order.orderRow is undefined The error occurs when attempting to add a new row to the orderRow array. Here is the code snippet: Order Class ...

What is the method to group a TypeScript array based on a key from an object within the array?

I am dealing with an array called products that requires grouping based on the Product._shop_id. export class Product { _id: string; _shop_id: string; } export class Variant { variant_id: string; } export interface ShoppingCart { Variant: ...

Angular displaying a slice of the data array

After following the example mentioned here, and successfully receiving API data, I am facing an issue where only one field from the data array is displayed in the TypeScript component's HTML element. Below is the content of todo.component.ts file im ...