简体   繁体   中英

How to find a dynamic element and send text through Selenium and C#

EDIT: Not sure if it really helps to figure it out, but this is Sharepoint based.

I have an element with special character which the Webdriver can't locate.

var element = wait.Until(x => x.FindElement(By.Id("Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte")));
element.SendKeys("foo");

I guess it is the $ that causes the problem.

On the contrary , I found it by using :

var element = wait.Until(x => x.FindElements(By.CssSelector("div[id*='Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592']")));
element[2].FindElement(By.TagName("p")).SendKeys("foo");

The test passes that way(seemingly), but the value isn't really being sent to the field. Unfortunately, there is no input tag on the element's hierarchy, and when inserting the text manually , I can then see that the value was inserted to the <p> tag. But , as shown, when using the <p> tag , it doesn't really help.

The HTML:

 <div class="ms-rtestate-write ms-rteflags-0 ms-rtestate-field" id="Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte" role="textbox" aria-haspopup="true" aria-labelledby="Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte_label" style="min-height: 84px;" contenteditable="true" aria-autocomplete="both" aria-multiline="true" RteDirty="true"> <p> <span id="ms-rterangecursor-start" RteNodeId="1"></span> <span id="ms-rterangecursor-end"></span> ​</p> </div> 

Instead of implementing two FindElement* you can do it in single step as follows:

  • CssSelector :

     wait.Until(x => x.FindElement(By.CssSelector("div.ms-rtestate-write.ms-rteflags-0.ms-rtestate-field[id^='Tasrit_'][aria-labelledby$='_inplacerte_label']>p"))).SendKeys("foo"); 
  • XPath :

     wait.Until(x => x.FindElement(By.XPath("//div[@class='ms-rtestate-write ms-rteflags-0 ms-rtestate-field' and starts-with(@id,'Tasrit_')][contains(@aria-labelledby,'_inplacerte_label')]/p"))).SendKeys("foo"); 

Update

However the element looks dynamic to me so you need to induce WebDriverwait for the desired element to be clickable and you can use either of the following solutions:

  • CssSelector :

     new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("div.ms-rtestate-write.ms-rteflags-0.ms-rtestate-field[id^='Tasrit_'][aria-labelledby$='_inplacerte_label']>p"))).SendKeys("foo"); 
  • XPath :

     new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//div[@class='ms-rtestate-write ms-rteflags-0 ms-rtestate-field' and starts-with(@id,'Tasrit_')][contains(@aria-labelledby,'_inplacerte_label')]/p"))).SendKeys("foo"); 

And I guess there is extra space in that element's id :) Try this:

wait.Until(x => x.FindElement(By.Id("Tasrit_6aecdca9-e3b9-4141-ae36-d537784f9592_$TextField_inplacerte")));
element.Click();

Either that or the Id value of that element in the DOM is different , $TextField_inplacerte being a variable that parses to eg. spaceMonkey, undefined, 5 etc. Open up the dev tools, find the element, right-click, inspect and confirm the actual Id of the element in the DOM.

You can use dev tools API to search for text in DOM of the currently opened page (with that element in it) if it matches the Id matches if not there is a difference in it. It could be any part eg. 6th character in Id being different :)

Just to make sure that space between 1st part of id and 24 you mention is the problem you can either:

  1. look at webdriver's code and see internally what is used to access DOM elements

  2. load jquery before testing this out:

    var element = wait.Until(x => x.FindElements($('#id containing spaces')).SendKeys("foo");

Basically, instead of using webdriver way to find element, you use jQuery to obtain the element reference. If that works it's the space problem due to bad design of the application having space in element's id

Possibly that is why CSS selector route worked.

If SendKeys() doesn't work you can try using JavaScript

IWebElement webElement = element[2].FindElement(By.TagName("p"));
driver.ExecuteJavaScript("arguments[0].setAttribute('value', 'arguments[1]')", webElement, "foo");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM