/ #jest #node 

Jest Array/Object partial match with objectContaining and arrayContaining

It’s possible to do partial matches on Arrays and Objects in Jest using expect.objectContaining and expect.arrayContaining.

expect has some powerful matcher methods to do things like the above partial matches.

Using Jest at an advanced level means using tools like these to write tests that are better isolated and less brittle (this is what I’m tryin to achieve with the Jest Handbook).

This post starts with an explanation to give context to partial matches followed by sample use-cases in a recipe/cookbook format.

We finish off by mentioning further resources that cover this topic.

Table of Contents

Why use Object/Array partial matching in Jest?

For example if we wanted to test that the following object had the right id but didn’t care about the other fields. We could write

test('id should match', () => {
  const obj = {
    id: '111',
    productName: 'Jest Handbook',
    url: 'https://jesthandbook.com'
  };
  expect(obj.id).toEqual('111');
});

Now what if we wanted to match 2 fields whose generation was tightly coupled? With naive matching, we would do:

test('id and productName should match', () => {
  const obj = {
    id: '111',
    productName: 'Jest Handbook',
    url: 'https://jesthandbook.com'
  };
  expect(obj.id).toEqual('111');
  expect(obj.productName).toEqual('Jest Handbook');
});

With Jest’s Object partial matching we can do:

test('id should match', () => {
  const obj = {
    id: '111',
    productName: 'Jest Handbook',
    url: 'https://jesthandbook.com'
  };
  expect(obj).toEqual(
    expect.objectContaining({
      id: '111'
    })
  );
});

and for multiple fields:

test('id and productName should match', () => {
  const obj = {
    id: '111',
    productName: 'Jest Handbook',
    url: 'https://jesthandbook.com'
  };
  expect(obj).toEqual(
    expect.objectContaining({
      id: '111',
      productName: 'Jest Handbook'
    })
  );
});

The latter example seems better for readability and maintainability of the test. It has 1 assertion tests but makes sure the code is rock solid.

Jest Simple Array partial match with expect.arrayContaining

To match part of an Array in Jest, we can use expect.arrayContaining(partialArray).

For example, if we want to make sure our oddArray has the right odds numbers under 10, we can do:

const oddArray = [1, 3, 5, 7, 9, 11, 13];
test('should start correctly', () => {
  expect(oddArray).toEqual(expect.arrayContaining([1, 3, 5, 7, 9]));
});

The equivalent without expect.arrayContaining would be:

const oddArray = [1, 3, 5, 7, 9, 11, 13];
test('should start correctly', () => {
  expect(oddArray).toContain(1);
  expect(oddArray).toContain(3);
  expect(oddArray).toContain(5);
  expect(oddArray).toContain(7);
  expect(oddArray).toContain(9);
});

Jest Simple Object partial match with expect.objectContaining

To match part of an Array in Jest, we can use expect.objectContaining(partialObject).

For example, if we want to make sure our user has the right id and name, we can do:

const user = {
  id: 1,
  friends: [],
  name: 'Hugo',
  url: 'https://codewithhugo.com'
};
test('should have right id and name', () => {
  expect(user).toEqual(
    expect.objectContaining({
      id: 1,
      name: 'Hugo'
    })
  );
});

The equivalent without expect.objectContaining would be:

const user = {
  id: 1,
  friends: [],
  name: 'Hugo',
  url: 'https://codewithhugo.com'
};
test('should have right id and name', () => {
  expect(user.id).toEqual(1);
  expect(user.name).toEqual('Hugo');
});

Jest Array of objects partial match with arrayContaining and objectContaining

In keeping with the user example, what if we wanted to check that we have the right ids for a list (array) of users.

By combining expect.objectContaining and expect.arrayContaining we can do a partial match on the objects in the array:

const users = [{id: 1, name: 'Hugo'}, {id: 2, name: 'Francesco'}];

test('we should have ids 1 and 2', () => {
  expect(users).toEqual(
    expect.arrayContaining([
      expect.objectContaining({id: 1}),
      expect.objectContaining({id: 2})
    ])
  );
});

Note: the parameter passed to arrayContaining must be an array, even if that array contains expect.objectContaining partial matches

To do the same without expect.objectContaining or expect.arrayContaining, we would have needed to unpack the array or use find/some:

const users = [{id: 1, name: 'Hugo'}, {id: 2, name: 'Francesco'}];
test('example 1 > we should have ids 1 and 2', () => {
  const [first, second] = users;
  expect(first.id).toEqual(1);
  expect(second.id).toEqual(2);
});
test('example 2 > we should have ids 1 and 2', () => {
  expect(users.some(({id}) => id === 1)).toBe(true);
  expect(users.some(({id}) => id === 2)).toBe(true);
});

Jest Object with nested arrays partial match with objectContaining and arrayContaining

In keeping with the user example, what if we wanted to check that we have the right ids for a list (array) of friends for a user?

By combining expect.objectContaining and expect.arrayContaining we can do a partial match on fields that are arrays in the object:

const user = {
  id: 1,
  name: 'Hugo',
  friends: [3, 5, 22]
};
test('user 3 should be a friend of user', () => {
  expect(user).toEqual(
    expect.objectContaining({
      friends: expect.arrayContaining([3])
    })
  );
});

To do the same without expect.objectContaining or expect.arrayContaining, we would have needed to use some:

const user = {
  id: 1,
  name: 'Hugo',
  friends: [3, 5, 22]
};
test('user 3 should be a friend of user', () => {
  expect(user.friends.some(f => f === 3)).toBe(true);
});

Jest array/object negative matches with not.objectContaining and not.arrayContaining

To check that something is not in an array or object, we can use expect.not.arrayContaining and expect.not.objectContaining respectively

const user = {
  id: 1,
  name: 'Hugo',
  friends: [3, 5, 22]
};
test('user 3 should be a friend of user', () => {
  expect(user).toEqual(
    expect.not.objectContaining({
      url: 'https://codewithhugo.com'
    })
  );
  // Can't be your own friend?
  expect(user.friends).toEqual(expect.not.arrayContaining([1]));
});

Further Reading

The examples for this post are at github.com/HugoDF/jest-object-array-partial-match.

Other resources for this are:

unsplash-logoMark Tegethoff

Looking for a new job? Take Triplebyte’s quiz and have top tech companies pitch you!

Author

Hugo Di Francesco

A Software Engineer who is big on Node.js, queues and Vue(s). Co-author of "Professional JavaScript" with Packt. He shares practical JavaScript tips for the developer who wants to get things done on Code with Hugo. University College London (UCL), MEng Mathematical Computation Graduate.

Get Testing Superpowers with these Underused Jest Features

Subscribe for free resources that turbocharge your Jest tests and a discount on the "Advanced Jest Handbook"