Jest assert over single or specific argument/parameters with .toHaveBeenCalledWith and expect.anything()
Tags: javascript, testing, jest, tdd
Published: 2019-05-18 13:52:38

---
title: Jest assert over single or specific argument/parameters with .toHaveBeenCalledWith and expect.anything()
published: true
tags: JavaScript, testing, jest,tdd
canonical_url: https://codewithhugo.com/jest-specific-argument-parameter-assert/
---

> With Jest it’s possible to assert of single or specific arguments/parameters of a mock function call with `.toHaveBeenCalled`/`.toBeCalled` and `expect.anything()`.

The full example repository is at [github.com/HugoDF/jest-specific-argument-assert](https://github.com/HugoDF/jest-specific-argument-assert), more specifically [lines 17-66 in the src/pinger.test.js file](https://github.com/HugoDF/jest-specific-argument-assert/blob/master/src/pinger.test.js#L17-L66).

You can use `expect.anything()` to ignore certain parameters that a mock Jest function is called with, see the following:

```js
test('calls getPingConfigs with right accountId, searchRegex', async () => {
  await pinger(1);
  expect(mockPingConfig).toHaveBeenCalledWith(
    1,
    expect.anything(),
    expect.anything(),
    new RegExp('.*')
  );
});

```

Read on for more details of the code under test and why one would use such an approach.

The code under test follows module boundaries similar to what is described in [An enterprise-style Node.js REST API setup with Docker Compose, Express and Postgres](https://dev.to/hugo__df/an-enterprise-style-node-js-rest-api-setup-with-docker-compose-express-and-postgres-2hm0-temp-slug-2013945). Specifically a [3-tier (Presentation, Domain, Data) layering](https://codewithhugo.com/node-postgres-express-docker-compose/#architecture-example-user-session-management), where we’ve only implemented the domain and (fake) data layers.

## Code under test that warrants specific parameter/argument assertions

The code under test is the following ([see the full src/pinger.js file on GitHub](https://github.com/HugoDF/jest-specific-argument-assert/blob/master/src/pinger.js)), only relevant code has been included to make it obvious what problem we’ll be tackling with Jest mocks, `.toHaveBeenCalled` and `expect.anything()`.

```js
// Half-baked implementation of an uptime monitor
const { getPingConfigs } = require('./pingConfig');

async function getUrlsForAccount(accountId, offset, limit, searchRegex) {
  const configs = await getPingConfigs(accountId, offset, limit, searchRegex);
  // return configs.map(conf => conf.url);
}

async function pinger(accountId, { offset = 0, limit = 50 } = {}, search) {
  const searchRegex = search
    ? new RegExp(search.split(' ').join('|'))
    : new RegExp('.*');
  const urls = await getUrlsForAccount(accountId, offset, limit, searchRegex);
}

module.exports = pinger;

```

The only call going outside the module’s private context is `getPingConfigs(accountId, offset, limit, searchRegex)`. This is why the assertion is going to be on the `getPingConfigs` mock that we’ve set with `jest.mock('./pingConfig', () => {})` ([see the full src/pinger.test.js code on GitHub](https://github.com/HugoDF/jest-specific-argument-assert/blob/master/src/pinger.test.js)).

### Discovering orthogonality in code under test

We can also see that there’s orthogonal functionality going on. Namely:

- passing of `accountId`
- computing/defaulting/passing of a search regex
- defaulting/passing of offset/limit

### Issues with exhaustive test cases for orthogonal functionality

All our tests will center around the values `getPingConfigs` is called with (using `.toHaveBeenCalledWith` assertions).

Let’s create some tests that don’t leverage `expect.anything()`, in every call, we’ll specify the value each of the parameters to `getPingConfigs`: `accountId`, `offset`, `limit` and `searchRegex`.

Permutations, (`Y` denotes the variable passed to `pinger` is set, `N` that it is not).

| accountId | offset | limit | search | single-word search |
| --- | --- | --- | --- | --- |
| Y | N | N | Y | Y |
| Y | N | N | Y | N |
| Y | N | Y | N | N/A |
| Y | Y | Y | N | N/A |
| Y | N | N | Y | Y |
| Y | N | N | Y | N |
| Y | Y | N | Y | Y |
| Y | Y | N | Y | N |
| Y | Y | Y | Y | Y |
| Y | Y | Y | Y | N |

Each of the above permutations should lead to different test cases if we have to specify each of the parameters/arguments in the assertion on the `getPingConfigs` call.

The enumeration we’ve done above would result in **10 test cases**.

### Creating test cases for orthogonal functionality

It turns out the following cases cover the same logic in a way that _we care about_:

1. on search
  1. if search is **not** set, `pinger` should call with the default searchRegex
  2. if search is set and is single word (no space), `pinger` should call with the correct searchRegex
  3. if search is set and is multi-work (spaces), `pinger` should call with the correct searchRegex
2. on limit/offset
  1. if limit/offset are **not** set, `pinger` should call with default values
  2. if limit/offset are set, `pinger` should call with passed values

Notice how the assertions only concern _part_ of the call, which is where `expect.anything()` is going to come handy as a way to not have to assert over all the parameters/arguments of a mock call at the same time.

## Specific parameter asserts on a mock function call

The following implements the test cases we’ve defined in [“Creating test cases for orthogonal functionality”](https://codewithhugo.com/jest-specific-argument-parameter-assert/#creating-test-cases-for-orthogonal-functionality):

```js
describe('without search', () => {
  test('calls getPingConfigs with right accountId, searchRegex', async () => {
    await pinger(1);
    expect(mockPingConfig).toHaveBeenCalledWith(
      1,
      expect.anything(),
      expect.anything(),
      new RegExp('.*')
    );
  });
});
describe('offset, limit', () => {
  test('calls getPingConfigs with passed offset and limit', async () => {
    await pinger(1, { offset: 20, limit: 100 });
    expect(mockPingConfig).toHaveBeenCalledWith(
      1,
      20,
      100,
      expect.anything()
    );
  });
  test('calls getPingConfigs with default offset and limit if undefined', async () => {
    await pinger(1);
    expect(mockPingConfig).toHaveBeenCalledWith(1, 0, 50, expect.anything());
  });
});
describe('search', () => {
  describe('single-word search', () => {
    test('calls getPingConfigs with right accountId, searchRegex', async () => {
      await pinger(1, {}, 'search');
      expect(mockPingConfig).toHaveBeenCalledWith(
        1,
        expect.anything(),
        expect.anything(),
        new RegExp('search')
      );
    });
  });
  describe('multi-word search', () => {
    test('calls getPingConfigs with right accountId, searchRegex', async () => {
      await pinger(1, {}, 'multi word search');
      expect(mockPingConfig).toHaveBeenCalledWith(
        1,
        expect.anything(),
        expect.anything(),
        new RegExp('multi|word|search')
      );
    });
  });
});

```

## Further reading

Head over to [github.com/HugoDF/jest-specific-argument-assert](https://github.com/HugoDF/jest-specific-argument-assert) to see the full code and test suite. This includes code and tests that aren’t relevant to illustrate the concept of specific argument/parameter assertions with Jest `.toHaveBeenCalledWith`/`.toBeCalled` and `expect.anything()`.

The way the code is written loosely follows what is described in [An enterprise-style Node.js REST API setup with Docker Compose, Express and Postgres](https://dev.to/hugo__df/an-enterprise-style-node-js-rest-api-setup-with-docker-compose-express-and-postgres-2hm0-temp-slug-2013945). Specifically a [3-tier (Presentation, Domain, Data) layering](https://codewithhugo.com/node-postgres-express-docker-compose/#architecture-example-user-session-management), where we’ve only implemented the domain and (fake) data layers.