0

I have a website written in React (not by me) and I am currently using selenium to select a dropdown and choosing a value from it.

Since is React, I can't just wait for the DOM to be ready (however I do it anyway).

So, I wrote those lines, that actually are working:

  • first 3 lines to click on the dropdown
  • last 3 to select an element from the dropdown
/** Find dropdown and click on it */
await driver.wait(until.elementLocated(By.css('div#discipline')))
const dropdown = await driver.findElement(By.css('div#discipline'))
await dropdown.click()
        
/** Wait the list, find element to select and click on it */
const dropOpts = await driver.wait(until.elementLocated(By.css('div#menu-discipline > div > ul')))
await driver.wait(until.elementLocated(By.xpath('//li[contains(text(),"Infirmary")]')))
const choice = await dropOpts.findElement(By.xpath('//li[contains(text(),"Infirmary")]'))        
await choice.click()
  • first question is about if it is actually correct (it runs but it's not necessarily correct!);
  • second question is: is it right for the first element, to FIRST wait for it THEN find it? or should I do the opposite?
  • third and most important question: what about the last 3 lines of code? is it right to A) wait for the parent element of the dropdown menu B) wait for the dropdown menu to appear with driver.wait C) find the element i want to select with findElement? Or should I have first to findElement then to wait for it to appear?

I have a bit of confusion about this.

Don Diego
  • 1,309
  • 3
  • 23
  • 46
  • not familiar with using JS and Selenium, but for your last question you can't findElement before it appears. Also your expected condition may return the webelement so you can use one line to wait and get the element... see here for "elementToBeClickable": https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#elementToBeClickable(org.openqa.selenium.By) (Not sure about JS versions of things though...) – pcalkins Jan 05 '21 at 19:13
  • Thanks for the tip, I don't think in JS exist `elementToBeClickable`, anyway I could use `await driver.wait(until.elementIsVisible(elem), delay)` and `await driver.wait(until.elementIsEnabled(elem), delay)`, and after that `elem.click`...but I'm not sure this is the right way – Don Diego Jan 07 '21 at 08:56

1 Answers1

0

I ended up creating a functions that

  • uses elementLocated, since this function uses in its own code findElement;
  • uses elementIsVisible, since it checks if element is visible
  • uses elementIsEnabled, since it checks if element is enabled (those last two checks are a standard way to check that an element is definitely present in the DOM, answer by Louis)

here's the code:

async function waitAndClickElement(driver, selectorType, selector) {
  let element
  try {
    element = await driver.wait(until.elementLocated(By[selectorType](selector)), timeout)
    await driver.wait(until.elementIsVisible(element), timeout)
    await driver.wait(until.elementIsEnabled(element), timeout)
    await element.click()
  } catch (error) {
    console.error('Something went wrong!\n', error.stack, '\n')
    throw error
  }

  return element
}

This way you can also use your preferred selector, just inserting selectorType as a string in the params.

Then, I used this function twice: one for selecting the dropdown, the second to choose an element:

  /** Find dropdown 'test' and click on it */
  await waitAndClickElement(driver, 'css', 'div#test')

  /** Wait the list, find element to select and click on it */
  await waitAndClickElement(
    driver,
    'xpath',
    `//li[contains(text(),"myText")]`,
  )
Don Diego
  • 1,309
  • 3
  • 23
  • 46