title: How to use Jest/Puppeteer to wait until an element as been removed from the DOM
body: <p><strong>Summary of problem:</strong> I'm writing several test suites (using Jest and Puppeteer) to automate tests of my AngularJS app's home page. One of the tests I would like to automate is a user pressing a button on the page that deletes an element in the DOM. Unforuntealy, this element is used to display a large amount of data, so in order for the element to be deleted, the client first needs to make POST request to my server to delete the data from the db, and only then can the element be deleted from the DOM. All in all, this whole process takes about a second or two. What's more, this element I'm trying to delete was added dynamically to the DOM, so the only way I am able to access the element is by using an XPath which identifies the element by the text it contains, rather than a traditional CSS selector. Now here's my question: how can I employ Jest and Puppeteer's Api's to write some test code that WAITS for this element to no longer exist (i.e. leave the DOM). </p>
  
  <p>Here is a overview of what my HTML looks like so you have an idea of what I'm working with:</p>
  
  <pre><code>&lt;html&gt;
    &lt;body ng-app="myApp" ng-controller="myCtrl"&gt;
      &lt;!-- Dynamically added div --&gt;
      &lt;div&gt;My Data
        &lt;table&gt;&lt;!-- Displays tons of data --&gt;&lt;/table&gt;
      &lt;/div&gt;
      &lt;form&gt;
        &lt;button type="submit"&gt;Delete&lt;/button&gt;
      &lt;/form&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p><strong>Background:</strong> I'm using Jest (v24.8.0) as my testing framework. I'm using Puppeteer (v1.19.0) to spin up and control a headless Chromium browser.</p>
  
  <p><strong>What I've tried so far:</strong></p>
  
  <p>Currently, I have this code </p>
  
  <pre><code>  test('deleted elem no longer exists', async() =&gt; {
      elemXPath = '//div[contains(text(), "My Data")]';
  
      // this is a function to pause the 
      // execution of the test for a given amount of milliseconds
      // in order to wait for elem to be removed
      await delay(2000);
  
      // This fails because Puppeteer timeouts after 3000 
      // ms b/c elemXPath no longer exists
      const elemExists = await page.waitForXPath(elemXPath, {timeout: 3000}) ? true : false;
      expect(elemExists).toBe(false);
    }); 
  </code></pre>
  
  <p>I could do something like this:</p>
  
  <pre><code>  test('deleted elem no longer exists', async() =&gt; {
      elemXPath = '//div[contains(text(), "My Data")]';
  
      // wait for elem to be removed
      await delay(2000);
  
      try {
        var elemExists = await page.waitForXPath(elemXPath, {timeout: 3000}) ? true : false;
      } catch(err) {
        var elemExists = false
      }
      expect(elemExists).toBe(false);
    }); 
  </code></pre>
  
  <p>... but I want to be able to get rid of my <code>await delay</code> line and just have the test wait precisely until the element is gone.
  The problem with <code>await delay</code> is that it's unreliable as depending on how much data the element is displaying it may take more or less time to be deleted than what <code>await delay</code> specifies. </p>
  
  <p><strong>Conclusion:</strong>
  Have any of you Jest/Puppeteer hackers come across an issue like this before and know of any clever solutions?</p>