Dom-testing-library: <select> doesn't reflect new "select text" in response to change event

Created on 9 Oct 2018  ·  18Comments  ·  Source: testing-library/dom-testing-library

  • dom-testing-library version: 3.8.2
  • react version: N/A
  • node version: v10.11.0 (but it doesn't matter)
  • npm (or yarn) version: yarn 1.10.1 (but it doesn't matter)

Relevant code or config:

See the reproduction section below.

What you did:

  1. Created a <div> containing a <select> with two <option>s.
  2. Fetched the <select> using getBySelectText
  3. Fired a change event on the fetched <select> to select another valid option
  4. Verified that the value was changed
  5. Attempted to fetch the <select> from the <div> again using the newly selected option's label (child element)

What happened:

The <select> cannot be fetched by its new "select text":

 FAIL  ./index.test.js
  ✕ should respond to changes (4520ms)

  ● should respond to changes

    Unable to find a <select> element with the selected option's text: Option 2

    <div>
      <select>


        <option
          value="option-1"
        >
          Option 1
        </option>


        <option
          value="option-2"
        >
          Option 2
        </option>


      </select>
    </div>

      22 |     // but this times out because the text hasn't been updated.
      23 |     // No changes are reflected in the DOM, which is probably why…
    > 24 |     return waitForElement(() => getBySelectText(container, 'Option 2'));
         |                                 ^
      25 | });
      26 |

      at getElementError (node_modules/dom-testing-library/dist/query-helpers.js:29:10)
      at getAllBySelectText (node_modules/dom-testing-library/dist/queries.js:375:45)
      at firstResultOrNull (node_modules/dom-testing-library/dist/query-helpers.js:37:30)
      at getBySelectText (node_modules/dom-testing-library/dist/queries.js:385:42)
      at getBySelectText (index.test.js:24:33)
      at onMutation (node_modules/dom-testing-library/dist/wait-for-element.js:48:22)
      at node_modules/dom-testing-library/dist/wait-for-element.js:66:7
      at waitForElement (node_modules/dom-testing-library/dist/wait-for-element.js:26:10)
      at Object.waitForElement (index.test.js:24:12)

Reproduction:

const { getBySelectText, fireEvent, wait, waitForElement } = require('dom-testing-library');

it('should respond to changes', () => {
    const select = document.createElement('select');
    select.innerHTML = `
        <option value="option-1">Option 1</option>
        <option value="option-2">Option 2</option>
    `;

    const container = document.createElement('div');
    container.appendChild(select);

    const foundSelectBeforeEvent = getBySelectText(container, 'Option 1');
    expect(foundSelectBeforeEvent.value).toBe('option-1');

    fireEvent.change(foundSelectBeforeEvent, { target: { value: 'option-2' }});

    // It has been updated, and this passes
    expect(foundSelectBeforeEvent.value).toBe('option-2');

    // I would then expect to be able to get the <select> again by the new text,
    // but this times out because the text hasn't been updated.
    // No changes are reflected in the DOM, which is probably why…
    return waitForElement(() => getBySelectText(container, 'Option 2'));
});

I've tried (among other things):

  • waiting for a tick to let updates happen
  • Firing events for focus and blur before and after firing the change to force a rerender
  • Not wrapping the fetching in waitForElement (it just fails in the same way, but faster)

Problem description:

The <select> element doesn't seem to update its displayed value, so it behaves differently from what a user experiences in a browser.

Suggested solution:

The <select> should be selectable using the label of the selected option. I don't know how to fix it, though :smile:

jsdom

Most helpful comment

With help from @SimenB I put together a version of jest-environment-jsdom that ships JSDOM version 12:

GitHub: https://github.com/theneva/jest-environment-jsdom-twelve
npm: https://www.npmjs.com/package/jest-environment-jsdom-twelve

Using that solves my issue :smile:

Thanks for looking into this!

All 18 comments

Hmmm... I'm not sure what's going on here. Would anyone care to dig deeper into this?

I created this and I'm unable to reproduce: https://jsbin.com/lukecehisa/edit?html,js,console

Thanks for checking it out

I'm pretty sure the jsbin snippet works because it executes in the browser, and as I mentioned in the OP, this behaviour for the select is different from the browser.

Would be great if someone could take a look! :smile:

I can reproduce the same error in a Jest/JSDOM environment

Hmmm... Maybe it's a bug in JSDOM :-(

Probably this: https://github.com/jsdom/jsdom/issues/2326, fixed Aug 18

https://github.com/kentcdodds/dom-testing-library/blob/master/src/queries.js#L117

The fix went out in JSDOM 12.0.0 https://github.com/jsdom/jsdom/blob/master/Changelog.md#1200

But I'm seeing jsdom 11.5.1 coming in via jest-environment-jsdom

Ah, in that case I'm pretty sure we'll need an updated version of jsdom which I'm guessing is already in the latest version of Jest 🤔

@theneva perhaps you could open a PR on Jest to upgrade JSDOM?

In any case, there's not much we can do in this project, so I'm going to go ahead and close this issue. Sorry! 😬

Try adding this to package.json

  "resolutions": {
    "jsdom": "12.2.0"
  }

Didn't seem to work for me but maybe you can figure something out.

We won't upgrade jsdom in jest (for some time) as they've dropped node 6. See e.g. https://github.com/facebook/jest/pull/7122

Ah, that's unfortunate. Any timeframe on when jest can drop node < 8?

Probably not before it's EOL-ed, although we dropped 4 in December 2017. But I wouldn't bet on a PR dropping 6 landing before Christmas

Ok, thanks!

With help from @SimenB I put together a version of jest-environment-jsdom that ships JSDOM version 12:

GitHub: https://github.com/theneva/jest-environment-jsdom-twelve
npm: https://www.npmjs.com/package/jest-environment-jsdom-twelve

Using that solves my issue :smile:

Thanks for looking into this!

Though HTMLSelectElement.selectedOptions is not reactive in the version of JSDOM bundled with Jest, HTMLSelectElement.selectedIndex is.

I wouldn't mind opening a PR to change it to selectedIndex, but that would drop compatibility with the multiple attribute.

@kentcdodds What would you prefer?

Hmmmm.... What if we get the best of all worlds. If the select has multiple then let's use selectedOptions (hopefully they don't need it to be reactive), if it's not multiple then we can use selectedIndex.

Is there any way we could iterate through the...

Yeah, we can do this:

const selectedOptions = Array.from(selectElement.options).filter(option => option.selected)

:tada: This issue has been resolved in version 3.10.1 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

Was this page helpful?
0 / 5 - 0 ratings