title: Jest / React Testing Library: Is it Possible to Spy on and Wait GraphQL Queries as with Cypress?
body: <p>Most of my testing experience is with Cypress. I'm attempting to test some React components with React Testing Library (henceforth referred to as  "RTL"). I'm wondering if I can apply some of the techniques I use with Cypress.</p>
  
  <p>I have a section of my (web) app which displays a table of search results from a DB. The search API is implemented in GraphQL. We use Apollo on the frontend. Searches can be filtered vis-a-vis a <code>&lt;FilterCheckbox/&gt;</code> component. It includes four checkboxes and a "Clear All" button. The checkbox state is stored in the Apollo cache.</p>
  
  <p>I'm writing a spec for this component. I wish to test that the first two checkboxes are selected by default and that clicking "Clear Filters" deselects them all. I have the following:</p>
  
  <pre><code>import React from 'react'
  import FilterCheckboxes from './FilterCheckboxes'
  import { render, fireEvent } from 'Utils/test-utils'
  
  import {
    getByText,
    getByTestId
  } from '@testing-library/dom'
  
  const props = {
    options: [
      { label: 'new', value: 'FRESH' },
      { label: 'active', value: 'ACTIVE' },
      { label: 'closed', value: 'CLOSED' },
      { label: 'removed', value: 'ARCHIVED' },
    ],
    statusArray: [
      'FRESH',
      'ACTIVE',
    ],
    cacheKey: 'status',
  }
  
  describe('FilterCheckboxes component', () =&gt; {
    const { container } = render(&lt;FilterCheckboxes {...props} /&gt;)
  
    const checkNew = getByTestId(container,'checkbox_new')
      .querySelector('input[type="checkbox"]')
  
    const checkActive = getByTestId(container, 'checkbox_active')
      .querySelector('input[type="checkbox"]')
  
    const checkClosed = getByTestId(container,'checkbox_closed' )
      .querySelector('input[type="checkbox"]')
  
    const checkRemoved = getByTestId(container, 'checkbox_removed')
      .querySelector('input[type="checkbox"]')
  
    const clearButton = getByText(container, 'clear status filters')
  
  
    it('should render the checkboxes with the correct default state', () =&gt; {
      expect(checkNew).toHaveProperty('checked', true)
      expect(checkActive).toHaveProperty('checked', true)
      expect(checkClosed).toHaveProperty('checked', false)
      expect(checkRemoved).toHaveProperty('checked', false)
    })
  
    it('Should clear all checkboxes when clear filters is clicked', () =&gt; {
      fireEvent.click(clearButton)
      setTimeout(() =&gt; {
        expect(checkNew).toHaveProperty('checked', false)
        expect(checkActive).toHaveProperty('checked', false)
        expect(checkClosed).toHaveProperty('checked', false)
        expect(checkRemoved).toHaveProperty('checked', false)
      }, 500)
    })
  })
  </code></pre>
  
  <p>The tests pass, but the second one only passes if I do this arbitrary delay of 500ms. Without it, the checkboxes are still in the default state when the <code>expect()</code> calls fire. </p>
  
  <p>If this were a Cypress test and the onClick called a REST API, I would do something like this:</p>
  
  <pre><code>cy.server()
  cy.route('POST', '/foo/bar/v2', '@someAliasedFixture').as('fooBar')
  
  cy.get('.my-button')
  .click()
  .then(() =&gt; {
      cy.wait('@fooBar')
      // continue test here as we know that the call completed
  })
  </code></pre>
  
  <p>Is it possible to do something like this with Jest / RTL / GraphQL / Apollo?</p>
  
  <p><strong>Update:</strong>
  Took another look this morning. It appears that <code>waitFor()</code> is the function intended to be used in async scenarios. However, if I do </p>
  
  <pre><code>it('should deselect checkboxes when Clear Filters is clicked', async () =&gt; {
    fireEvent.click(clearButton)
    waitFor(expect(checkNew).toHaveProperty('checked', false))
  })
  </code></pre>
  
  <p>It just fails because the checkbox is still selected. Surely there is a way to test this with RTL?</p>
  
  <p>Based on the examples I've looked at, the orthodox approach seems to be to pass the click handler function as a prop and <code>expect()</code> it <code>.toHaveBeenCalled()</code> called. </p>
  
  <p>Is that correct? This seems wrong to me. My component isn't what makes onClick handlers fire in response to click events. React.js makes that happen. Checking that <code>foo()</code> gets called when clicking on <code>&lt;MyComponent onClick={foo}/&gt;</code> isn't testing that <em>my</em> code works. It's testing that React.js works. </p>
  
  <p><strong>SOLVED!</strong>
  Thanks to @flo:</p>
  
  <pre><code>  it('should render the checkboxes with the correct default state', () =&gt; {
      expect(checkNew).toBeChecked()
      expect(checkActive).toBeChecked()
      expect(checkClosed).not.toBeChecked()
      expect(checkRemoved).not.toBeChecked()
    })
  
    it('should deselect checkboxes when Clear Filters is clicked', async () =&gt; {
      fireEvent.click(clearButton)
      waitFor(() =&gt; {
        expect(checkNew).not.toBeChecked()
        expect(checkActive).not.toBeChecked()
        expect(checkClosed).not.toBeChecked()
        expect(checkRemoved).not.toBeChecked()
      })
    })
  </code></pre>