question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

autoFocus prop and react-testing-library

See original GitHub issue

Summary

When testing react-select inputs with @testing-library/react, it’s not possible to programatically open the select. This is with the latest version of react-select.

Reproduction

I created a reproduction repo. I pasted the relevant code below to make it easier to follow

//App.js
import React, { Component } from "react";
import Select from "react-select";
import "./App.css";

const fruits = [
  { label: "Papaya", value: "papaya" },
  { label: "Apple", value: "apple" }
];

class App extends Component {
  render() {
    return (
      <div className="App">
        <label htmlFor="selectInput">Select a fruit</label>

        <Select
          autoFocus={this.props.autoFocus}
          id="selectInput"
          options={fruits}
        />
      </div>
    );
  }
}

App.defaultProps = {
  autoFocus: false
};

export default App;
// App.test.js

import React from "react";
import { render, fireEvent } from "@testing-library/react";
import App from "./App";

describe("select input", () => {
  describe("without autofocus", () => {
    it("should be able to open", () => {
      const { getByLabelText, getByText, debug } = render(<App />);

      const input = getByLabelText("Select a fruit");
      input.focus();
      fireEvent.keyDown(input, { key: "ArrowDown" });
      expect(getByText("Papaya")).toBeInTheDocument();
    });
  });
  describe("with autofocus", () => {
    it("should be able to open", () => {
      const { getByLabelText, getByText, debug } = render(
        <App autoFocus={true} />
      );

      const input = getByLabelText("Select a fruit");
      input.focus();
      fireEvent.keyDown(input, { key: "ArrowDown" });
      expect(getByText("Papaya")).toBeInTheDocument();
    });
  });
});

When I run the test, this is the result

 FAIL  src/App.test.js
  select input
    without autofocus
      ✓ should be able to open (135ms)
    with autofocus
      ✕ should be able to open (59ms)

  ● select input › with autofocus › should be able to open

    Unable to find an element with the text: Papaya. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    <body>
      <div>
        <div
          class="App"
        >
          <label
            for="selectInput"
          >
            Select a fruit
          </label>
          <div
            class=" css-2b097c-container"
            id="selectInput"
          >
            <span
              aria-live="polite"
              class="css-1laao21-a11yText"
            >
              <p
                id="aria-selection-event"
              >


              </p>
              <p
                id="aria-context"
              >

                  0 results available. Select is focused ,type to refine list, press Down to open the menu,
              </p>
            </span>
            <div
              class=" css-1pahdxg-control"
            >
              <div
                class=" css-1hwfws3"
              >
                <div
                  class=" css-1wa3eu0-placeholder"
                >
                  Select...
                </div>
                <div
                  class="css-1g6gooi"
                >
                  <div
                    class=""
                    style="display: inline-block;"
                  >
                    <input
                      aria-autocomplete="list"
                      autocapitalize="none"
                      autocomplete="off"
                      autocorrect="off"
                      id="react-select-3-input"
                      spellcheck="false"
                      style="box-sizing: content-box; width: 2px; border: 0px; font-size: inherit; opacity: 1; outline: 0; padding: 0px;"
                      tabindex="0"
                      type="text"
                      value=""
                    />
                    <div
                      style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-size: inherit; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
                    />
                  </div>
                </div>
              </div>
              <div
                class=" css-1wy0on6"
              >
                <span
                  class=" css-1okebmr-indicatorSeparator"
                />
                <div
                  aria-hidden="true"
                  class=" css-1gtu0rj-indicatorContainer"
                >
                  <svg
                    aria-hidden="true"
                    class="css-19bqh2r"
                    focusable="false"
                    height="20"
                    viewBox="0 0 20 20"
                    width="20"
                  >
                    <path
                      d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
                    />
                  </svg>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </body>

      23 |       input.focus();
      24 |       fireEvent.keyDown(input, { key: "ArrowDown" });
    > 25 |       expect(getByText("Papaya")).toBeInTheDocument();
         |              ^
      26 |     });
      27 |   });
      28 | });

      at getElementError (node_modules/@testing-library/dom/dist/query-helpers.js:46:10)
      at args (node_modules/@testing-library/dom/dist/query-helpers.js:100:13)
      at args (node_modules/@testing-library/dom/dist/query-helpers.js:83:17)
      at Object.getByText (src/App.test.js:25:14)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        1.91s
Ran all test suites.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:5
  • Comments:8

github_iconTop GitHub Comments

10reactions
montezumecommented, Aug 5, 2019

@iamchanii thanks for your help!

I figured out the source of the problem.

When I did

      const input = getByLabelText('Select a fruit');
      fireEvent.blur(input);

the input that I was grabbing was not actually an input. It’s a div.

Screen Shot 2019-08-05 at 11 08 46 AM

So calling blur on that div doesn’t do what we need.

So instead, I do

  describe("with autofocus", () => {
    it.only("should be able to open", async () => {
      const { getByLabelText, getByText, debug } = render(
        <App autoFocus={true} />
      );

      const input = getByLabelText("Select a fruit");

      fireEvent.blur(document.querySelector("input"));

      fireEvent.keyDown(input, {
        key: "ArrowDown",
        keyCode: 40
      });

      await waitForElement(() => getByText("Papaya"));
      fireEvent.click(getByText("Papaya"));
      expect(getByText("Papaya")).toBeInTheDocument();
    });
  });

and it works, because now the blur is being called on the actual input.

Thanks for your help! 🎉

I was even able to remove the async

  describe("with autofocus", () => {
    it.only("should be able to open", () => {
      const { getByLabelText, getByText } = render(<App autoFocus={true} />);

      const containerDiv = getByLabelText("Select a fruit");
      const input = containerDiv.querySelector("input");

      fireEvent.blur(input);

      fireEvent.keyDown(input, {
        key: "ArrowDown",
        keyCode: 40
      });

      expect(getByText("Papaya")).toBeInTheDocument();
      fireEvent.click(getByText("Papaya"));
      expect(getByText("Papaya")).toBeInTheDocument();
    });
  });
3reactions
iamchaniicommented, Jul 31, 2019

Finally, I resolve this issue. there is two points: 1. You should simulate keydown event for display dropdown. 2. Dropdown renders menu asynchronously.

it('should display dropdown menu and call onSortChange when option clicked', async () => {
    const { getByText, onSortChange, debug } = setup();

    // (1) I tried to simulate mouse event but not working. this only is effective solution.
    fireEvent.keyDown(document.querySelector('.list__control'), { key: 'ArrowDown', keyCode: 40 });

    // (2) Dropdown renders menu asynchronosly. you have to wait for element to find by text
    await waitForElement(() => getByText('Option 1'));
    fireEvent.click(getByText('Option 1'));

    expect(onSortChange).toHaveBeenCalledTimes(1);
    expect(onSortChange).toHaveBeenLastCalledWith(['code', 'ASC']);
});

And don’t forget use classNamePrefix props for write test easy.

    <ReactSelect
        classNamePrefix="list"
        noOptionsMessage={noOptionsMessage}
        isSearchable={false}
        isClearable={false}
        components={selectComponents}
        {...props}
    />

image

Ref: https://stackoverflow.com/a/56183912

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to test which input has the focus when tab button is pressed
I'm building a React autocomplete component and testing it using Jest and React-testing-library. I have two inputs.
Read more >
Testing User Interfaces For Beginners - Joy of Code
This is why Testing Library is framework agnostic with minor differences how you render and pass props to a component because whatever you...
Read more >
Input Event - Testing Library
import React, {useState} from 'react' import {render, fireEvent} from '@testing-library/react' function CostInput() {
Read more >
A Deep Dive on Managing Focus with React, Jest, and Enzyme
In our tests, this property comes from JSDOM, another library that's a dependency of Jest. Using Jest v25+. The update from Jest v24...
Read more >
Error when using autofocus on an input element (Reactjs)
[Solved]-Error when using autofocus on an input element (Reactjs)-Reactjs ... find an element with the text: "myText" error when using react-testing-library ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found