Array Includes A Primitive Value

📺 Watch these examples explained in the video Array Includes A Primitive Value And Checking Multiple Network Callsopen in new window.

Checking an array

const countries = ['Germany', 'US', 'Denmark', 'China']
// explicit assertion
expect(countries, 'Denmark is a country').to.include('Denmark')

You can check the current subject with automatic retries

const ages = []
// implicit assertion on the current subject
cy.wrap(ages, { log: false })
  // "include" and "contain" are aliases to the same assertion
  .should('include', 30)
  .and('contain', 42)
  // the values are strictly equal, so "42" is not the same as 42
  .and('not.include', '42')
// the array is modified at some point
setTimeout(() => {
  ages.push(10)
}, 500)
setTimeout(() => {
  ages.push(30)
}, 1000)
setTimeout(() => {
  ages.push(42)
}, 1500)

Checking network requests

// application sends a few analytics network requests
setTimeout(() => {
  fetch('https://acme.co/analytics', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ eventId: 'login' }),
  })
}, 500)
setTimeout(() => {
  fetch('https://acme.co/analytics', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      eventId: 'cart_empty',
      userId: '1234',
    }),
  })
}, 800)

The test stubs all /analytics requests and should confirm one of the has eventId: cart_empty in the request body.

cy.intercept('POST', '/analytics', {}).as('analytics')
cy.get('@analytics.all')
  // cy.map query comes from the cypress-map plugin
  .map('request.body.eventId')
  .should('include', 'cart_empty')

Note: cy.map query operator comes from the cypress-mapopen in new window plugin.

Checking network requests with array flattening

Sometimes an application might send a list of requests to save on bandwidth. We need to flatten the collected network request bodies first before checking the eventId values.

if (Math.random() < 0.5) {
  // separate network calls
  setTimeout(() => {
    fetch('https://acme.co/analytics', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ eventId: 'login' }),
    })
  }, 500)
  setTimeout(() => {
    fetch('https://acme.co/analytics', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        eventId: 'cart_empty',
        userId: '1234',
      }),
    })
  }, 800)
} else {
  // combined single network call sending both events
  setTimeout(() => {
    fetch('https://acme.co/analytics', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      // send both analytics events as an array
      body: JSON.stringify([
        { eventId: 'login' },
        {
          eventId: 'cart_empty',
          userId: '1234',
        },
      ]),
    })
  }, 1000)
}

The test stubs all /analytics requests and should confirm one of the has eventId: cart_empty in the request body.

cy.intercept('POST', '/analytics', {}).as('analytics')
cy.get('@analytics.all')
  .map('request.body')
  // the requests might arrive as a single object
  // or an array of objects, so at this point we can have
  // [event1, event2, [event3, event4], event5]
  // by invoking Array.flat() method, we remove nested arrays
  // [event1, event2, event3, event4, event5]
  .invoke('flat')
  .map('eventId')
  .should('include', 'cart_empty')

See also