Is there a way in Jest to restrict function calls to only those that are expected and disallow any other unauthorized calls

When working with Jest, you have the ability to mock out and spy on function calls within a function using functionalities like jest.spyOn and jest.fn() with .toHaveBeenCalledTimes(1) etc. However, in Spock framework testing, you can conclude your unit test by adding:

0 * _ // don't allow any other interaction

Is there a similar approach in Jest for achieving this restriction?

For example:

export default class Service {

    public startAllWorkers(): void {
        const processClient: ProcessClient = new ProcessClient();
        const processMonitor: ProcessMonitor = new ProcessMonitor();
        const defaultValue: number = 10;

        processClient.runClient(defaultValue);
        processMonitor.runMonitor('pling')
    }

}

describe('Service test', () => {

    let service: Service;

    beforeEach(() => {
        service = new Service();
        ProcessClient.prototype.runClient = jest.fn()
        ProcessMonitor.prototype.runMonitor = jest.fn()
    });

    it('should only call specific methods', () => {
        const spyService = jest.spyOn(service, 'startAllWorkers');

        service.startAllWorkers();

        expect(spyService).toHaveBeenCalledTimes(1);
        expect(ProcessClient.prototype.runClient).toHaveBeenCalledTimes(1);
        expect(ProcessMonitor.prototype.runMonitor).toHaveBeenCalledTimes(1);
        // expect no other interactions inside service method
    });

})

Answer №1

The spy feature in Jest is quite simple. The toBeCalledWith assertion allows you to verify if a specific set of arguments was used during one of the function calls.

If you need to be more precise with your assertions, you can specify them explicitly:

// fn('foo', 1);
// fn('bar', 2);
expect(mockFn).toBeCalledTimes(2); // though it might seem redundant, it makes the output clearer for humans
expect(mockFn.mock.calls).toEqual([
  ['foo', 1]
  ['bar', expect.any(Number)]
]);

If you want to ensure that the function is not called unexpectedly between consecutive calls, you can assert the spy briefly as follows:

// fn('foo', 1);
expect(mockFn).toBeCalledTimes(1);
expect(mockFn).toBeCalledWith('foo', 1);
mockFn.mockClear();
...
// fn('bar', 2);
expect(mockFn).toBeCalledTimes(1);
expect(mockFn).toBeCalledWith('bar', 2);
mockFn.mockClear();
...
expect(mockFn).not.toBeCalled();

As an alternative, a cleverly managed spy can handle both the implementation and expected usage like this:

mockFn.mockImplementation((...args) => {
  // first call
  if (mockFn.mock.calls.length === 1) {
    expect(args).toEqual(...);
    return ...;
  }

  // second call
  if (mockFn.mock.calls.length === 2) {
    expect(args).toEqual(...);
    return ...;
  }

  // no more calls
  expect(mockFn.mock.calls.length).not.toBe(3);
});

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

Battle of the Blobs: Exploring Blob Source in Google Apps Script

I've been exploring clasp, a tool that allows developers to work with Google Apps Script using TypeScript. Currently, I am working on a script that converts a Google Sheet into a PDF Blob and then uploads it to Google Drive. While the code is execut ...

"Exploring the differences between normalization structures and observable entities in ngrx

I'm currently grappling with the concept of "entity arrays" in my ngrx Store. Let's say I have a collection of PlanDTO retrieved from my api server. Based on the research I've done, it seems necessary to set up a kind of "table" to store th ...

Creating unique components with Angular2 and Ionic

Here is the HTML code for my custom component: <div> {{text}} {{percentLeft}} {{innerColor}} </div> And here is the TypeScript file for my component: import { Component, Input } from '@angular/core'; @Component({ selector: ...

Employing an unchanging Map format for observation

I'm currently working on implementing a synchronization mechanism using observable and Map structures from Immutable.js. However, I'm encountering an issue where the Map is unable to function as an observable or perhaps I might be approaching it ...

JavaScript now has Type Inference assistance

When attempting to utilize the Compiler API for processing JavaScript code and implementing Type inference to predict types of 'object' in a 'object.property' PropertyAccessExpression node, I encountered some issues. Some simple example ...

An Unexpected Token Leads to a SyntaxError in Jest's CSS-Modules

I have successfully configured my jest to allow the usage of static files by following their detailed documentation. However, despite implementing the instructions correctly, I am still encountering an error: What steps can I take to resolve this issue an ...

Steps to create an instance method that only accepts the name of another instance method

I am looking to enhance an object by adding a method that specifically accepts the name of another method within the object. How can I achieve this in a way that dynamically narrows down the accepted names of methods, without hardcoding them? Let's t ...

What is the best way to display the complete text or wrap a menu item in an Angular Material menu?

Is it possible to display the full text of a menu item instead of automatically converting it to ellipses or breaking the word? I've tried various CSS methods without success. Any suggestions? https://i.stack.imgur.com/3l7gE.png #html code <mat-m ...

Using React MUI Select in combination with react-hook-form does not seem to be compatible with Cypress testing

Within my React application, I have implemented a form that includes a dropdown select. Depending on the option selected from the dropdown, different input fields are rendered. const [templateType, setTemplateType] = useState(""); const { regi ...

The seamless union of Vuestic with Typescript

Seeking advice on integrating Typescript into a Vuestic project as a newcomer to Vue and Vuestic. How can I achieve this successfully? Successfully set up a new project using Vuestic CLI with the following commands: vuestic testproj npm install & ...

No slides will be displayed in Ionic 2 once the workout is completed

Here is the result of the JSONOBJ: In my home.html file, I have ion-card containing a method called navigate(), which is structured as follows: navigate(event, exercise, exercise2, exercise3, exercise4){ this.navCtrl.push(exerciseSlides, { ...

Is there a way for my React application to detect changes in an npm package?

I am currently customizing an npm package for my application, but I am facing issues with it not being detected when starting my development server. Previously, I was able to resolve this by removing the library and reinstalling it, followed by replacing t ...

Generate a data type automatically based on an Array

Imagine having an imaginary api that provides color values based on user selections. Consider the following arrays with string values: const Colors1 = ['red', 'blue', 'purple']; const Colors2 = ['blue', 'white& ...

What are the best ways to troubleshoot my Angular 2 project?

I've been searching for my TypeScript files in the console, but they're not showing up. I've tried everything to debug my Angular 2 project, but no luck. I can't move forward without debugging, can anyone lend a hand? ...

There seems to be a lack of information appearing on the table

I decided to challenge myself by creating a simple test project to dive into Angular concepts such as CRUD functions, utilizing ngFor, and understanding HttpClient methods (specifically get and post). After creating a Firebase database with an API key and ...

Accessing files from various directories within my project

I'm working on a project with 2 sources and I need to import a file from MyProject into nest-project-payment. Can you please guide me on how to do this? Here is the current file structure of my project: https://i.stack.imgur.com/KGKnp.png I attempt ...

Stop the node.js process if the Mithril Ospec tests do not pass

When running unit tests through Ospec for Mithril, I am able to easily detect any test failures in the local console. I am in search of a solution that will prevent a subsequent Node.js build script from running if any of the tests fail. I want to ensure ...

Implementation of a recursive stream in fp-ts for paginated API with lazy evaluation

My objective involves making requests to an API for transactions and saving them to a database. The API response is paginated, so I need to read each page and save the transactions in batches. After one request/response cycle, I aim to process the data an ...

tips for converting a single observable item into an observable list

Within my Angular project, there exists an observable object with the following structure: export interface FavoritesResponse { wallet: boolean; deposit: boolean; withdraw: boolean; transfer: boolean; exchange: boolean; ticket: boolean; accou ...

During rendering, the instance attempts to reference the "handleSelect" property or method which is not defined

I've incorporated the Element-UI NavMenu component into my web application to create a navigation bar using Vue.JS with TypeScript. In order to achieve this, I have created a Vue component within a directory called "navBar," which contains the follow ...