title: How to test key down event on material ui MenuList component using react-testing-library
body: <p>I have the following MenuList component on which I want to test key down event.</p>
  
  <p><strong>Component</strong>:</p>
  
  <pre><code>import MenuItem from '@material-ui/core/MenuItem';
  import MenuList from '@material-ui/core/MenuList';
  import * as React from 'react';
  
  export default function App() {
    return (
      &lt;div&gt;
        &lt;MenuList autoFocusItem={true}&gt;
          &lt;MenuItem&gt;option 1&lt;/MenuItem&gt;
          &lt;MenuItem&gt;option 2&lt;/MenuItem&gt;
          &lt;MenuItem&gt;option 3&lt;/MenuItem&gt;
        &lt;/MenuList&gt;
      &lt;/div&gt;
    );
  }
  
  </code></pre>
  
  <p><strong>Test</strong>:</p>
  
  <pre><code>import {
      fireEvent,
      render,
  } from 'test-utils';
  import React from 'react';
  import TestMenuList from './TestMenuList';
  
  test('that on key down press, the focus on menu list item moves down', async () =&gt; {
      // Render component
      const { getAllByRole, getByRole } = render(&lt;TestMenuList /&gt;, {});
  
      let MenuItem1 = getAllByRole('menuitem')[0];
      expect(MenuItem1.classList.contains('Mui-focusVisible')).toBe(true); // assert 1
  
      const Menu = getByRole('menu');
      fireEvent.keyDown(Menu, { Key: 'ArrowDown', code: 40 });
  
      MenuItem1 = getAllByRole('menuitem')[0];
      const MenuItem2 = getAllByRole('menuitem')[1];
      expect(MenuItem1.classList.contains('Mui-focusVisible')).toBe(false); // assert 2
      expect(MenuItem2.classList.contains('Mui-focusVisible')).toBe(true); // assert 3
  });
  </code></pre>
  
  <p>To make sure that a menu item is in focus, I'm checking if the menu item has class <code>Mui-focusVisible</code>. Since I set <code>autoFocusItem={true}</code> in <code>MenuList</code>, the first menu item should automatically have <code>Mui-focusVisible</code> class added to it. That is assertion statement 1 which is passing.</p>
  
  <pre><code>    let MenuItem1 = getAllByRole('menuitem')[0];
      expect(MenuItem1.classList.contains('Mui-focusVisible')).toBe(true); // assert 1
  </code></pre>
  
  <p>Then I fired a key down event on the menu </p>
  
  <pre><code>    const Menu = getByRole('menu');
      fireEvent.keyDown(Menu, { Key: 'ArrowDown', code: 40 });
  </code></pre>
  
  <p>And checked if the <code>Mui-focusVisible</code> class has been removed from first menu item and added to 2nd menu item. Now, the test is failing at assertion statements 2 and 3. </p>
  
  <pre><code>    MenuItem1 = getAllByRole('menuitem')[0];
      const MenuItem2 = getAllByRole('menuitem')[1];
      expect(MenuItem1.classList.contains('Mui-focusVisible')).toBe(false); // assert 2
      expect(MenuItem2.classList.contains('Mui-focusVisible')).toBe(true); // assert 3
  </code></pre>
  
  <p>I logged <code>classList</code> for <code>MenuItem1</code> and <code>MenuItem2</code> to see if <code>Mui-focusVisible</code> is removed from first menu item and added to 2nd menu item after the key down event. But the <code>Mui-focusVisible</code> class is still in first menu item and not in the 2nd one.</p>
  
  <p>I tried adding <code>await wait()</code>. </p>
  
  <pre><code>fireEvent.keyDown(Menu, { Key: 'ArrowDown', code: 40 });
  await wait();
  </code></pre>
  
  <p>wrapping the fireevent with <code>act(() =&gt; {})</code>, </p>
  
  <pre><code>act(() =&gt; fireEvent.keyDown(Menu, { Key: 'ArrowDown', code: 40 }));
  await wait()
  </code></pre>
  
  <p>firing key down event on first menu list item instead of the menu itself. </p>
  
  <pre><code>act(() =&gt; fireEvent.keyDown(MenuItem1, { Key: 'ArrowDown', code: 40 }));
  await wait()
  </code></pre>
  
  <p>None of them worked. I created a <a href="https://codesandbox.io/s/dawn-cloud-2fus7" rel="nofollow noreferrer">codesandbox</a> for this component and here, it seems to work perfectly in the UI. But the test is failing.</p>