JumpIntoTheWater
JumpIntoTheWater

Reputation: 1336

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>

Upvotes: 0

Views: 2846

Answers (3)

CodeSmith
CodeSmith

Reputation: 3197

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.

Upvotes: 0

undetected Selenium
undetected Selenium

Reputation: 193078

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");
    

Upvotes: 1

Guy
Guy

Reputation: 50809

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");

Upvotes: 0

Related Questions