Expect an Array to Contain an Object in Jest

To test if an object appears within an array, the natural first thought is to use toContain as below:

describe('contains test', () => {
  it('should return true', () => {
    const arr = [ { a: 1 }, { b: 2 }, { c: 3 } ]
    expect(arr).toContain( // This will fail.
      { b: 2 }
    )
  })
})

This will actually result in a failure. The matcher is comparing two different instances of the object {b: 2} and expecting two references to the exact same object in memory. Jest will even offer a helpful suggestion with the failure:

Looks like you wanted to test for object/array equality 
with the stricter toContain matcher. 
You probably need to use toContainEqual instead

To make this behave as we want, we need to use toContainEqual, which will compare only the values of the objects, and not their references. The following code works:

describe('contains test', () => {
  it('should return true', () => {
    const arr = [ { a: 1 }, { b: 2 }, { c: 3 } ]
    expect(arr).toContainEqual( // Compare values only.
      { b: 2 }
    )
  })
})

This will now succeed as desired.

 

Expect an Object to Contain Another Object

What if we want to test if an object contains { b: 2 } as one of its key-value pairs, i.e. to contain it as a sub-object?

The following will achieve this:

describe('object contains test', () => {
  it('should return true', () => {
    const myObject = { 
      a: 1, 
      b: 2, 
      c: 3 
    }
    expect(myObject).toEqual(expect.objectContaining(
      { b: 2 }
    ))
  })
})

This will succeed. Note that we used toEqual so that only object values are compared instead of identical object references.

 

Array Reduce Syntax in JavaScript

Reduce provides a clean mechanism to compute a single value from an array, i.e. to reduce the array to a single value.

Very generally, the form is:

result = arr.reduce(callbackFunction)

The idea is to move over each array element and invoke the callback function.

We need to give the callback two arguments to provide a mechanism of reduction for the array elements. We call these accumulator (acc) and element (elem).

The simplest useful reduce example is summing the array:

const arr = [1, 2, 3, 4, 5]
const sum = arr.reduce((acc, elem) => acc + elem) 
console.log(sum)

This outputs:

15

Image a sliding window in which acc stores a value accumulated in any way, and elem points to the 2nd, 3rd, 4th, etc element. The accumulator is updated and passed to the next iteration.

For demonstration, to see how reduce moves through the array:

const arr = [1, 2, 3, 4, 5]

arr.reduce((acc, elem) => {
   console.log(acc);
   console.log(elem);
})

This outputs:

1 // default first value of acc
2 // second element
undefined // acc is not being updated
3 // third element
undefined
4 // fourth element
undefined
5 // fifth element

Note that acc starts at the first element of the array by default.
We usually have to update acc to make reduce useful.

Reduce Starting from an Initial Value

The starting value of acc in reduce can be changed with an extra parameter. Generally:

const result = arr.reduce(callback, initialValue)

An example of an offset sum:

const arr = [1, 2, 3, 4, 5]
const result = arr.reduce((acc, elem) => {
  return acc + elem
}, 10) // *start the accumulator at 10 instead of 1*

console.log(result)

This outputs:

25

That is, 10 + (1+2+3+4+5)

Calling Reduce on an Array With a Single Element

Note that when we call reduce with a single element array without an initial value for acc, the acc value is undefined.
The callback will not be called; the only option reduce has in this case is to return the elem value.

const arr = [5]
const output = arr.reduce((acc, elem) => {
  console.log("Callback called") // will not print
  return acc + elem
})

console.log(output)

This will return 5, without calling the callback function.

However, if we add the initial value for acc, the callback will be called.

const arr = [5]
const output = arr.reduce((acc, obj) => {
  console.log("Callback called") // will print
  return acc + obj
}, 0) // initial value

console.log(output)

Using Reduce with an Object as Accumulator

We can also reduce an array to an object instead of a single scalar value.

This simple example reduces the array to an object with characters as keys, and a boolean true indicating that they appear inside the array.

const arr = ['a', 'c', 'b', 'a', 'c', 'e']
 
const result = arr.reduce((acc, elem) => {
  acc[elem] = true // build up acc
  return acc // send the partially built up acc into the next iteration
}, {} ) // initial value of acc is an empty object

console.log(result)

This will return:

{
   a: true,  
   c: true, 
   b: true, 
   e: true 
}

So we have reduced the array to a single object.

Using Reduce to Accumulate an Array

We can also use reduce to build up a list of values.
This example accumulates an array of names only from an array of objects with names and values.

const arr = [ 
  {name: 'A', val: 1},
  {name: 'B', val: 2},
  {name: 'C', val: 3}
]

const result = arr.reduce((acc, elem) => {
  acc.push(elem.name) // accumulate an array by pushing elements
  return acc
}, [] ) // acc is initially an empty array

console.log(result)

This returns:

[ 'A', 'B', 'C' ]

Index and Entire Array Parameters for Reduce

There are two more parameters available for reduce which can come in handy: the index of the current element and the entire array being reduced.

const arr = [1, 2, 3, 4, 5]

const sum = arr.reduce((acc, elem, index, wholeArray) => {
  console.log(`Index: ${index}`)
  console.log(`Whole array: ${wholeArray}`)
  return acc + elem
}, 0) // starting value of acc

console.log(`Sum: ${sum}`)

This returns:

Index: 0
Whole array: 1,2,3,4,5
Index: 1
Whole array: 1,2,3,4,5
Index: 2
Whole array: 1,2,3,4,5
Index: 3
Whole array: 1,2,3,4,5
Index: 4
Whole array: 1,2,3,4,5
Sum: 15