Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatically focus select component #856

Closed
radar opened this issue Mar 30, 2016 · 29 comments
Closed

Programmatically focus select component #856

radar opened this issue Mar 30, 2016 · 29 comments

Comments

@radar
Copy link

radar commented Mar 30, 2016

I'm looking to write an integration test for a form that uses a react-select component. This is the Ruby code that I have for it now:

find(".Select").click
find(".Select .Select-input input").native.send_key("Text goes here")
find(".Select-option", text: option_value.presentation).click

I would believe this would:

  1. Open the input field
  2. Send the phrase "text goes here" into the field.
  3. Find the option that matches that text, and then click it.

However, I'm getting this error in my tests:

Capybara::Poltergeist::MouseEventFailed:
       Firing a click at co-ordinates [356.5, 384] failed. Poltergeist detected another element with CSS selector 'html.js.touch body#en-AU-be.loggedin div.wrapper div.main div div.form--flat div.AdvertForm div.DisplayPanel div div.row div#option_type_wrapper_1.span6.error span.select div.Select.is-focused.is-open.is-searchable div.Select-control div.Select-placeholder' at this position. It may be overlapping the element you are trying to interact with. If you don't care about overlapping elements, try using node.trigger('click').

I would consider documentation for how to integration test a react-select (even if it is with some jQuery functions) would be something that this library should provide. I am considering this a "bug" with the documentation for this component, which is why I'm filing this issue.

Please add some examples of programatically triggering / filling in this element with jQuery.

@mipearson
Copy link

I've also looked at this, I work with Ryan.

The problem is that the placeholder element sits above the input element.

Sending keys to the placeholder element crashes PhantomJS 2.0 and 2.1, so that won't work.

Setting the value of the input element does not do anything. Using send_keys used to work, but no longer does.

I consider this a bug with react-select and not our testing as react-select is doing strange things to do the DOM that break how input elements are supposed to work.

@mipearson
Copy link

Oh, and we're using 1.0.0-beta5

@rzane
Copy link

rzane commented Apr 27, 2016

Anybody figure this out?

@mipearson
Copy link

Unfortunately, we ended up rolling our own autocomplete instead.

@rzane
Copy link

rzane commented Apr 28, 2016

I think I figured it out. I think it's something like:

$('.Select-input input').trigger('mousedown');
$('div.Select-option').first().trigger('mousedown');

@ilantc
Copy link

ilantc commented May 5, 2016

From what I saw when firing mousedown on the select the input.focus() is called, but the render is not (until I actually click on the screen).
It seems that setState is not being called when programmatically clicking the select.
Is there a way to fix this?

@AlanFoster
Copy link

@radar Can confirm this is awkward using Selenium too -

Selenium::WebDriver::Error::UnknownError: Element is not clickable at point (341, 45). Other element would receive the click: <div class="Select-placeholder" data-reactid=".0.1.1.0:$placeholder"></div>

The overlaying of elements is confusing the web driver it seems.

For what it's worth, this works completely fine with Capybara and the javascript_driver set to webkit, using the rack_test web driver. I'm not sure if you're in a position to switch that configuration though, but it helped unblock me.

@timsheng
Copy link

@ilantc have you found a solution to fix that issue?

@ilantc
Copy link

ilantc commented Apr 18, 2017

@timsheng
What we ended up doing is firing focus on the hidden input before dispatching the click events on the select.
Not ideal, but it works

@liorbentov
Copy link

@ilantc, can you write here that piece of code that worked?

@AlanFoster
Copy link

@liorbentov If you're using the react-addons-test-utils, something similar to:

const input = yourElement.querySelector('input');
TestUtils.Simulate.focus(input);

const selectArrow = yourElement.querySelector('.Select-arrow');
TestUtils.Simulate.mouseDown(selectArrow, { button: 0 });

It is possible to use enzyme etc, the important thing is that you need to focus on the input, then mouse down on the Select-arrow with button 0 set.

@liorbentov
Copy link

@AlanFoster thanks!
But I'm actually trying to do this on selenium (or chrome), and can't seem to get it right

@AlanFoster
Copy link

@liorbentov Unfortunately I was only able to trigger the component to open with selenium/capybara with JavaScript directly, due to the component's DOM structure and how it's styled on the page.

@leimonio
Copy link

leimonio commented Aug 25, 2017

@JedWatson any update on this? is there any way that we can actually trigger programmatically the selection dropdown? I'm currently using NightmareJS and cannot find any working solution.

@nathanielescribano
Copy link

Looking for a similar thing. trying to write integration tests using zombiejs but unable to find the best way to programmatically trigger the dropdown.

@leimonio
Copy link

leimonio commented Sep 4, 2017

@nathanielescribano I finally found out a way to make tests work. I'm testing with NightmareJS, so there is a package https://github.com/Mr0grog/nightmare-real-mouse for triggering real mouse events on the browser. This solution worked fine for me. You may probably need a relative solution with ZombieJS, since it is also testing on headless browser.

@ghost
Copy link

ghost commented Oct 9, 2017

see also #603 Document how to test with selenium

@nakulthebuilder
Copy link

This worked for me using Selenium:

const getSelect = () =>
  driver
  .findElement({
    className: 'Select-placeholder'
  })
  .findElement({'xpath': '//*[@id="react-select-2--value"]/div[2]/input'});

await driver.wait(until.elementLocated(getSelect));
const select = await getSelect();
await select.sendKeys(query);

The xpath there is to the input element

@volkanunsal
Copy link

Does anyone know how to simulate selection on this component using just Javascript? The code samples above did not work for me.

$('.Select-input input').trigger('mousedown');
$('div.Select-option').first().trigger('mousedown');

I need a solution I can use in my integration tests.

I'm using React 15.6.2 and react-select 1.2.1.

@aterreno
Copy link

@volkanunsal after a few failed tentatives, I ended up doing 'brute force' by tabbing, going down with the arrow key and then sending an enter.

    const TAB = '\u0009';
    const ARROW_DOWN = '\uE015';
    const ENTER = '\uE007';
    browser.keys([TAB, ARROW_DOWN, ENTER]);

@nachikethashu
Copy link

I was able to get the menu opened with following code:
this.mouseEvent('mousedown', '.Select .Select-arrow-zone');

Note that this is casperJS syntax. However I feel you can extend this to any other framework.

@sad148
Copy link

sad148 commented May 23, 2018

Was anyone able to find a fix for selenium?

@arhtudormorar
Copy link

arhtudormorar commented May 26, 2018

I'm also not able to solve it - it seems jQuery is not an option: facebook/react#3249

@abidvf
Copy link

abidvf commented Feb 12, 2019

I am also not been able to trigger it with jasmine.

@seclace
Copy link

seclace commented Mar 29, 2019

It seems to changes in library itself, so we need to trigger event touchend on svg icon or its wrapper to open options list to be able to select one.

This link may be helpful to testing in chrome (presumably puppeteer for integration tests): https://stackoverflow.com/a/42447620

@natew
Copy link

natew commented Apr 4, 2019

A forceOpen property would be really nice -- right now I have a z-index issue where the menu is hidden on open, but I can't debug it easily, because it goes away once I try and inspect it.

@bladey
Copy link
Contributor

bladey commented Jun 5, 2020

Hi all,

Thank you everyone who had a part in addressing this question.

In an effort to sustain the react-select project going forward, we're closing issues that appear to have been resolved via community comments.

However, if you feel this issue is still relevant and you'd like us to review it, or have any suggestions regarding this going forward - please leave a comment and we'll do our best to get back to you!

@josias-r
Copy link

josias-r commented Nov 3, 2022

Tried all the options above, nothing worked in plain js for me.
But after a while I figured out, this works:

selectContainer
  .querySelector(".YOUR_CUSTOM_CLASS__dropdown-indicator")
  .dispatchEvent(
    new MouseEvent("mousedown", {
      button: 0,
      bubbles: true, // this is key, otherwise it wont work
    })
  ); // open the menu by "clicking" dropdown indicator

Where selectContainer is just some higher level DOM element wrapping the specific select you are interested in. In my case I simply wrapped it with a new div, but you can of course you can querySelect an existing Select container

@laurentiu-lese-collinson

if we want to do it via react test library I would always recommend to check the actual tests from this library, they are the key to understand what needs to be triggered.
e.g.

  // Re-open Menu
  fireEvent.mouseDown(
    container.querySelector('div.react-select__dropdown-indicator'),
    {
      button: 0,
    }
  );

If we are talking about vanilla js, we can do it like this:
(notice the selector that uses a pattern for class selection, you should replace the value with whatever class you have in your project for dropdown indicator)

const element = document.querySelector('div[class*=dropdown-indicator]')
element.dispatchEvent(new MouseEvent('mousedown', {
  bubbles: true,
  cancelable: true,
  view: window
}));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests