JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.56k stars 4.12k forks source link

Document how to test with selenium #603

Closed ben-manes closed 4 years ago

ben-manes commented 8 years ago

I'm having difficulty selecting an entry using webdriver. I can get as far as clicking on the input, but despite hacks have not yet been able to set the selection. A short guide on how to test this component would be appreciated.

ben-manes commented 8 years ago

A hack, but this seems to work.

self.driver.find_element_by_class_name('Select-control').click()
wait = WebDriverWait(self.driver, timeout=10)
wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'Select-option')))
options = self.driver.find_elements_by_class_name('Select-option')
for option in options:
    if option.text == value:
        option.click()
        break
radar commented 8 years ago

I have some Ruby code for this:

    first("#{element} .Select-input input").set(value)
    first("#{element} .Select-option").click

Setting the input's value will populate the component with the options that match that name. Then it's just a matter of clicking on that first option.

mipearson commented 8 years ago

Here's what we settled on for poltergeist/phantomJS. The trick is the keypresses need to be "sent" for it to work - can't just "set" the value of the hidden field.

    within(select_container_element) do
      find(".Select").click
      find(".Select").native.send_key(desired_option)
      find(".Select-option", text: desired_option).click
    end
DanielSundberg commented 8 years ago

In C#/Seleno I had to do the following to get it to work:

public void SetSelectText(string optionText) {
    var select = Find.Element(By.CssSelector(".Select"));
    select.Click();
    var options = Find.Elements(By.CssSelector(".Select-option")).ToList();
    options.ToList().Single(o => o.Text == optionText).Click();
}

That is with react-select@0.8.2, didn't bother with trying to get any later version to work.

At least some response whether this is prioritized or not would be nice.

etburke commented 8 years ago

I can't seem to get anything working with NightwatchJS.

oren commented 8 years ago

The following works for me:

In the IDE:

Command: sendKeys
Target: css=div.Select-control input
Value: Allergies${KEY_ENTER}

And the Java translation:

driver.findElement(By.cssSelector("div.Select-control input")).sendKeys("Allergies" + Keys.ENTER);

https://groups.google.com/forum/#!topic/selenium-users/FWsu_r7bbr0

ghost commented 7 years ago

Hey,

I faced the same issue, here is my solution for the Nightwatch by creating a custom command.

The DOM I am manipulating in the script might have to be updated.

const util = require('util');
const events = require('events');

function selectOption() {
  events.EventEmitter.call(this);
}

util.inherits(selectOption, events.EventEmitter);

/**
 * Click an option in a select
 * It injects a script which triggers the events expected by the listeners in the core component.
 * @param {String} itemSelector The selector of the section where the select is.
 * @param {String} selectSelector Optional, the selector of the select. Default value: '.dropdow__element'.
 */
selectOption.prototype.command = function command(itemSelector, selectSelector = '.dropdown__element', callback) {
  this.api.execute((itemSel, selectSel) => {
    // eslint-disable no-undef
    var item = document.querySelector(itemSel); // eslint-disable-line no-var
    var select = item.parentNode.querySelector(selectSel); // eslint-disable-line no-var
    var evt = document.createEvent('MouseEvents'); // eslint-disable-line no-var
    evt.initEvent('mousedown', true, true);

    select.children[0].click();

    item.parentNode.getElementsByTagName('li')[1].children[0].dispatchEvent(evt);
    // eslint-enable no-undef
  }, [itemSelector, selectSelector], () => {
    if (typeof callback === 'function') {
      callback.call(this);
    }
    this.emit('complete');
  });

  return this;
};

module.exports = selectOption;

In fact the select is activated on the MouseDown event, here we trigger the event by injecting some code when testing the website.

@etburke I hope it can help you, let me know if it does what you are expecting.

mfpiccolo commented 7 years ago

For those of you trying to work with nightwatch and multiselect, I was able to get this to work with multi select using:

      .click('.custom-class')
      .click('.custom-class .Select-option[id*="-option-1"]')
kgunbin commented 7 years ago

I've came up with a custom command for NightwatchJS which worked for me: commands/setReactSelect.js

exports.command = function(selector, data) {
  var select = selector + ' .Select .Select-control';
  var item = selector + ' .Select .Select-menu .Select-option';
  var self = this;

  return this
    .waitForElementVisible(select, 1000)
    .click(select)
    .waitForElementVisible(item, 1000, function() {
      self.executeAsync(
        function() {
          var item = arguments[0][0];
          var data = arguments[0][1];
          var parent = arguments[0][2];

          var multi = Array.isArray(data);

          if(!multi) {
            data = [data];
          } else {
            // Close the dropdown after a second when all events are hopefully dispatched
            setTimeout(() => document.querySelector(parent + ' .Select-input input').blur(), 1000);
          }

          data.forEach((label) => {
            var option = Array.prototype.find.call(
              document.querySelectorAll(item),
              (e) => label == e.innerHTML
            );

            option.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}));
          });
        },
        [[item, data, select]] // Pack params into an array, as Selenium works correct with a single parameter only
      );
    }).waitForElementNotPresent(item, 4000);
};

and the respective test

module.exports = {
  'Select Tasmania': function(browser) {
    var states = '#example .section';
    browser
      .url('https://jedwatson.github.io/react-select/')
      .setReactSelect(states, 'Tasmania')
      .waitForElementVisible('div.Select-value.State-Tas',  5000)
      .end();
  },

  'Select Chocolate and Peppermint': function(browser) {
    var root = '#example .section:nth-child(2)';

    browser
      .url('https://jedwatson.github.io/react-select/')
      .setReactSelect(root, ['Peppermint', 'Chocolate'])
      .waitForElementPresent(root + ' span.Select-value-icon', 5000) // Just assume any value is there
      .end();
  }
}

Hope this helps someone.

joechromo commented 7 years ago

This one worked for me:

.click('.Select-value-label') .click('.Select-option[id*="-option-1"]')

RamadhanaRey commented 7 years ago

Hi @oren how to handle next field with your selenium IDE command? i have problem with next field, because the target always input on a first field..

gor181 commented 7 years ago

What @radar proposed also works nicely in nightwatch alike syntax:

const commands = {
  fillSignUpInformation(email) {
    return this
      .setValue('@email', email || chance.email())
      .setValue('@password', 'somepw')
      .setValue('@companyName', 'company')
      .setValue('@phoneNumber', '+11234567890')
      .setValue('.Select-input input', 'United States')
      .click('.Select-option');
  },
  register() {
    return this.click('@submit');
  },
};
PashminaT commented 6 years ago

Has anyone got an example for selenium webdriver in java please?

roscianfrank commented 6 years ago

@PashminaT Java version

driver.findElement(By.className("Select-control")).click(); WebDriverWait wait = new WebDriverWait(driver,10); wait.until(ExpectedConditions.elementToBeClickable((By.className("Select-option")))); List<WebElement> options = driver.findElements(By.className("Select-option")); for(WebElement option: options){ if (option.getText().equalsIgnoreCase(DropDownValue)){ option.click(); break; } }

Olliebaba commented 6 years ago

@Roscian1Frank - your example worked for my team. Thanks!

rocastaneda commented 6 years ago

Command: sendKeys Target: css=div.Select-control input Value: 1 + Command: click Target: id=react-select-2--option-0

This works for me

pietrofxq commented 5 years ago

@Roscian1Frank could you make it work with latest versions? I cannot find a way to trigger click in the select and open the dropdown with webdriver

roscianfrank commented 5 years ago

Hi @pietrofxq,

My above example is still working for me on Selenium V3.14.0. Need more details for investigation. Thanks Roscian

Vyshnavi-N commented 5 years ago

what does (clientName) in the code signify?

if (option.getText().equalsIgnoreCase(clientName)){

roscianfrank commented 5 years ago

@Vyshnavi-N ClientName = Dropdown value Value which you want to select from from drop-down

kfox112 commented 4 years ago

For anyone using nightwatch and the chrome driver, this is what worked for me (custom command):

exports.command = function(selector, data) {

    // Turn any numbers into a string
    keysToSend = "" + data;

    // Split the string on each character into an array of keys
    keysToSend = keysToSend.split("");

    // Hit enter after characters are typed
    keysToSend.push("\n");

    return this
        .waitForElementVisible(selector, 1000)
        .click(selector)
        .keys(keysToSend);
};
jossmac commented 4 years ago

Please reserve the GitHub issue tracker for bugs and feature requests. StackOverflow would be more appropriate for this sort of discussion.

DanielSundberg commented 4 years ago

Why close? This was reported as a documentation bug. Stackoverflow is not really the place for documentation of a custom component. The OP + many others including me wanted the creator of the component to document how it could be tested since automated testing is a first class citizen since many years.

Perhaps testing the component also could be made a bit easier. Take a look at the java example above...