Why can I not click on this element in this code? - c#

Actions action = new Actions(driver);
IWebElement we = driver.FindElement(By.XPath(".//*[#class='ms-crm-CommandBar-Button ms-crm-Menu-Label']"));
action.MoveToElement(driver.FindElement(By.XPath(".//*[#class='ms-crm-CommandBar-Button ms-crm-Menu-Label-Hovered']"))).Click().Build().Perform();
expect element as followings:
< span tabindex = "-1" class="ms-crm-CommandBar-Button ms-crm-Menu-Label" style="max-width: 200px;">
<a tabindex = "0" class="ms-crm-Menu-Label" onclick="return false">
<img tabindex = "-1" class="ms-crm-ImageStrip-New_16 ms-crm-commandbar-image16by16" style="vertical-align: top;" src="/_imgs/imagestrips/transparent_spacer.gif">
<span tabindex = "-1" class="ms-crm-CommandBar-Menu" [enter image description here][1]style="max-width: 150px;" command="lead|NoRelationship|HomePageGrid|Mscrm.NewRecordFromGrid">
New
</span>
<div class="ms-crm-div-NotVisible">
Create a new Lead record.
</div>
</a>
</span>
Note that this class "ms-crm-CommandBar-Button ms-crm-Menu-Label" turns to be "ms-crm-CommandBar-Button ms-crm-Menu-Label-Hovered" when mouseover.
Many thanks.

When you search for the hovered element it doesn't exist.
So you need to hover element first, then you'll be able to find and click hovered element.
action.MoveToElement(driver.FindElement(By.XPath("//*[#class='ms-crm-CommandBar-Button ms-crm-Menu-Label']"))).Build().Perform().MoveToElement(driver.FindElement(By.XPath("//*[#class='ms-crm-CommandBar-Button ms-crm-Menu-Label-Hovered']"))).Click().Build().Perform();

In hover case first you need to moveTo That element after that you can click on it.
Actions actions = new Actions(driver);
action.moveToElement(mainMenu).moveToElement(driver.findElement(By.xpath("ur element"))).click().build().perform();

Related

How to SendKeys to input element that is created ad hoc when clicking in div element parent?

I am stuck in this problem: our webpage has a dynamic table that will load values (students' marks) on a div element. If we click on said div, a new child element input will be appended to the div and we should be able to input a new mark using SendKeys method. However, when I try to SendKeys, a StaleElementReferenceException appears.
Here is the element when the input is added (had to use a breakpoint as the element disappears as soon as the div element loses focus):
<tr>
<td class="indice">1</td>
<td id="accion-1-alumno-0" data-tooltip="" title="Bustos, Guido" class="has-tip titulo">Bustos, Guido</td>
<td data-tooltip="" title="1º ESA" class="has-tip titulo">1º ESA</td>
<td class="nota relative media noeditable k-nivel2_tabla" style="text-align:center; color: #ed1c24!important">
<div id="accion-1-celda-0-0-0" class="elemento comentarios">2,00</div>
</td>
<td class="nota relative " style="text-align:center; color: #ed1c24!important">
<div id="accion-1-celda-1-0-0" class="elemento comentarios">
<input id="editor" type="text" value="2" maxlength="7">
</div>
</td>
<td class="nota relative " style="text-align:center; color: #000000!important">
<div class="elemento comentarios">
<span id="accion-1-editar-2-0" class="block left ellipsis span comentario" title=""></span>
<span id="accion-1-prismaticos-2-0" class="glyphicons glyph_observaciones observacion right"></span>
</div>
</td>
</tr>
And here is the code that I use to click on the div and try to SendKeys:
IWebElement inputNota = SeleniumHelper.FindByXPath("//td[text() = '"+ nombreAlumno +"']/following-sibling::td/div[contains(#id, 'accion-1-celda')]");
SeleniumHelper.Click(inputNota);
SeleniumHelper.SendKeys(inputNota.FindElement(By.Id("editor")), nota);
Thanks for your time
If a new element is appended to the html it means the DOM was refreshed, or at least the <div>, so the driver "lost" the previously located elements. You need to relocate it
string locator = "//td[text() = '"+ nombreAlumno +"']/following-sibling::td/div[contains(#id, 'accion-1-celda')]";
IWebElement inputNota = SeleniumHelper.FindByXPath(locator);
SeleniumHelper.Click(inputNota);
SeleniumHelper.SendKeys(SeleniumHelper.FindByXPath(locator).FindElement(By.Id("editor")), nota);
StaleElement occurs when the Element is removed/changed from the DOM. In any case you will need to regrab the element. A good way to do this is like so...
public static IWebElement HardFindElement(IWebDriver driver, By by)
{
IWebElement elementToReturn = null;
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(drv =>
{
try
{
elementToReturn = driver.FindElement(by);
return true;
}
catch
{
return false;
}
});
return elementToReturn;
}
This will wait up to 30 seconds until it is able to regrab the element from the DOM. You will want to do this after the click to reinitialize the element accordingly

Selenium clicking button hidden by span

I am trying to automate an environment selection screen where there are multiple selectable buttons individually hidden by a span, these display as tiles.
I have managed to navigate to a given tile and pull up the button but I am unable to click it.
Here is the code I have
public static void NavigateToEnvironment(IWebDriver driver, string environment)
{
IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5.00));
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath($"//span[text()='{environment}']")));
var tile = driver.FindElement(By.XPath($"//span[text()='{environment}']"));
Actions action = new Actions(driver);
action.MoveToElement(tile).Perform();
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath($"//*[#span=(text()='{environment}')][#btn=(starts-with(text(), 'Start'))]")));
driver.FindElement(By.XPath($"//*[starts-with(text(), 'Start')]")).Click();
}
The first part successfully moves to the correct tile and opens the span so on screen the button is there.
The wait.until condition is fine too so Selenium can see the element so its the final click command I have an issue with.
It seems only to look for the button hidden within tile one but I am trying tile three. All the buttons have the same HTML tags.
In the current code state I get element not visible.
I have tried to use the xpath as in the wait condition but that returns that the parameters are not elements so again fails.
I am kind of at a loss. Any ideas?
UPDATE:
Some HTML of one of the buttons. This basically repeats with a different application name
<li class="trans tile">
<div class="tileWrap noselect" aria-haspopup="true">
<div class="divNavIcon">
<span class="spnNavIcon primarycolorfont enable" data-bind="css: Code"></span>
</div>
<div class="tilePopup primarycolor">
<span data-bind="text: ApplicationNameAlias ? ApplicationNameAlias : ApplicationName">Enable QA</span>
<span data-bind="text: Description" class="tileSubText">Enable CI Environment</span>
<div class="tilePopupToggle">
<button type="button" data-bind="click: $parent.startApp, css: { disabled: IsRevoked }" class="btn">Start <i class="fa fa-fw fa-desktop"></i></button>
<button type="button" style="display:none;" data-bind="click: $parent.startAppNew, css: { disabled: IsRevoked }" class="btn">Start New <i class="fa fa-fw fa-external-link"></i></button>
<button type="button" style="display:none;" data-bind="attr: { "data-target": "#appPreview_" + ApplicationID }" class="btn" data-toggle="modal" data-target="#appPreview_3043">Preview <i class="fa fa-fw fa-play"></i></button>
</div>
</div>
</div>
Screenshot to help understanding - Each tile acts in the same way with a hidden start button. My code works fine for this first tile but if I want the second or third tiles it cannot find the start button
As per the HTML you have shared to click on the button with text as Start you can use the following code block :
wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath("//div[#class='tilePopup primarycolor']//div[#class='tilePopupToggle']/button[#class='btn' and normalize-space()='Start']/i[#class='fa fa-fw fa-desktop']"))).Click();
Update
Can you try removing the <button> tag as :
wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath("//div[#class='tilePopup primarycolor']//div[#class='tilePopupToggle']//i[#class='fa fa-fw fa-desktop']"))).Click();
Note : As per aurelia/binding/issues/163 disable.bind disables button but inner content is still clickable and we are targeting i[#class='fa fa-fw fa-desktop']
I have managed a pretty elegant work around to this issue. The buttons are contained in li items so i'm just finding the relevant one of those.
public void NavigateToEnvironment(IWebDriver driver, string environment)
{
var tile = driver.FindElement(By.XPath($"//span[text()='{environment}']"),5);
Actions action = new Actions(driver);
action.MoveToElement(tile).Perform();
var tile2 = driver
.FindElement(By.XPath("//*[#id='content']/div/div/div/div/ul"))
.FindElements(By.TagName("li"))
.Where(x => !string.IsNullOrWhiteSpace(x.Text))
.ToList();
var singleTile = tile2.Single(x => x.Text.Contains(environment));
driver.FindElement(By.XPath($"//*[#id='content']/div/div/div/div/ul/li[{tile2.IndexOf(singleTile) + 1}]/div[1]/div[2]/div/button[1]")).Click();
}

Additional html tags with dynamic radio button

I am creating some radio buttons dynamically by:
Regions.ascx
<ul class="form_items" ID="radioList" runat="server" clientidmode="Static">
</ul>
In Regions.ascx.cs
foreach (var region in Config.ConfigString("str_Regions").Split(','))
{
HtmlGenericControl li = new HtmlGenericControl("li");
RadioButton regionRadio = new RadioButton();
regionRadio.Text = region;
regionRadio.ID = "Radio"+(i++).ToString();
regionRadio.Attributes.Add("name", "region");
regionRadio.Attributes.Add("value", region);
regionRadio.TextAlign = TextAlign.Right;
li.Controls.Add(regionRadio);
radioList.Controls.Add(li);
}
A lot of extra HTML tags are appearing which I don't want. I am getting output as:
<ul id="radioList" class="form_items">
<li>
<span name="region"><input id="MainContent_contactUs_Radio1" type="radio" name="ctl00$MainContent$contactUs$Radio1" value="Australia">
<label for="MainContent_contactUs_Radio1">Australia</label>
</span>
</li>
<li>
<span name="region"><input id="MainContent_contactUs_Radio2" type="radio" name="ctl00$MainContent$contactUs$Radio2" value="America">
<label for="MainContent_contactUs_Radio2">America</label>
</span>
</li>
</ul>
The label under which the 'Australia/America' is coming causes the wrong look by inheriting the styles aligned to all labels.
While I just want
<ul id="radioList" class="form_items">
<li><input id="MainContent_contactUs_Radio1" type="radio" name="ctl00$MainContent$contactUs$Radio1" value="Australia">"Australia"</li><li><input id="MainContent_contactUs_Radio2" type="radio" name="ctl00$MainContent$contactUs$Radio2" value="America">"America"</li></ul>
If you are using System.Web.UI.Webcontrols it will render your control with span. You can see why its rendering between span.
Why does ASP.Net RadioButton and CheckBox render inside a Span?
There two ways to overcome this. First you need to add attribute to input controls not span right now when you directly add attribute it will do that way.
See my blog post about it- http://www.dotnetjalps.com/2014/04/aspnet-checkbox-button-attributes-javascript.html
You need to add attribute like below.
myCheckBox.InputAttributes.Add("onblur", "onBlur();");
For text align and other stuff I suggest you use System.Web.UI.HtmlControls where you can use HtmlInputRadioButton instead of System.Web.UI.Webcontrols radio button. Here you can also manage all HTML attribute very easily.
Another thing you can do like adding labels and HTMLInputRadioButton separately and add class to your label as per your requirement.
string[] regions = {"Autralia", "Asia", "US"};
foreach (var region in regions)
{
HtmlGenericControl li = new HtmlGenericControl("li");
HtmlInputRadioButton radioButton=new HtmlInputRadioButton
{Value = region,
Name = region};
li.Controls.Add(radioButton);
Label label=new Label {Text = region, CssClass = "YourCSSClass"};
li.Controls.Add(label);
radioList.Controls.Add(li);
}
Hopefully this have more controls on css style
I think text-align set the horizontal position of your radio button in its container.
so, check if your container does or not wrap to your radio button.

Extract text from a div

I am trying to make a DropDownList using divs and jquery (so that I can style it as I want)...and its working but the problem is I cant get the selected value from the list..
After selection of the option I am copying the selected value into the a div.. and I want to extract this using c# (in .aspx.cs page)... I've tried to do it using string builder and innerHtml(after adding runat="server" to the div).. but it doesn't work ...code is as follows
.aspx Page:
<div class="ddl">
<div id="lowertriangle" class="lowertriangle"></div>
<div id="uppertriangle" class="uppertriangle"></div>
<div id="label" class="labeldiv_dd" runat="server"></div>//***This is the div from which I want to extract value***
<div id="options" class="optionsidv_dd">
<ul id="options_ul">
<li id="0">Select One Option</li>
<li id="1">Option 1</li>
<li id="2">Option 2</li>
<li id="3">Option 3</li>
<li id="4">Option 4</li>
<li id="5">Option 5</li>
</ul>
</div>
</div>
aspx.cs page
Method 1 that I tried:
string sel_text = label.InnerHtml;
display_sel_value.Text = sel_text.ToString();
2nd method:
var sb = new StringBuilder();
label.RenderControl(new HtmlTextWriter(new StringWriter(sb)));
string s = sb.ToString();
Kindly point out my mistakes and help me in this regard(in extracting innerHTML of the div that is).
Thanks
No, putting content in a div won't work.
Your example isn't complete enough to see all that happens, but let's assume that you're in a standard <form>, you're setting the div's inner HTML to a value with Javascript and then you're submitting in the standard way.
Then one way to do what you want is to use a hidden input and setting its value attribute instead of its contents.
<input id="label" class="labeldiv_dd" runat="server" type="hidden">
In the codebehind, the C# can retrieve the value from this control after submitting with the .Value property.
Ok guys thx for your replies..I found a way around the problem...I used HiddenField control to store the selected value using jQuery like so
$("#options_ul li").click(function () {
var text = this.innerHTML;
***$('#<%= selectedvalue.ClientID %>').val(text);***
$("#options_ul li").css("background-color", "#c2c2c2");
$(this).css("background-color", "white");
//var prev = this.id;
//document.getElementById("label").innerHTML = text;
toggleHeight();
});
and then accessed it server side using
selectedvalue.value;
PS: "selectedvalue" is id of the hiddenfield control

How to incrementally reveal div tags

I have collection of div tags in the form tag, like this:
<form ...>
<div id="div1"> ... </div>
<div id="div2"> ... </div>
...
...
</form>
I want to display only div1 in the visible area than when user presses next, the next div tag i.e. div2 is displayed, and so on.
How can I achieve this?
I don't have much knowledge about different approaches available to do this, but I have some knowledge of Javascript, so any idea will be appreciated.
P.S. please provide sample code if possible, also I want client-side scripting.
Here's some javascript and html demonstration that may help. Increment a current integer. You could deincrement with -- for back as well. There are many ways to do this. This is just one I thought of.
<img src="mynextbutton.jpg" onclick="showNext()" />
<form ...>
<div id="Div0" style="display:inherit;"> ... </div>
<div id="Div1" style="display:none;"> ... </div>
<div id="Div2" style="display:none;"> ... </div>
...
...
</form>
//---------------------------------------------------
var currentDiv = 0;
function showNext()
{
document.getElementById("Div"+currentDiv).style.display = "none";
currentDiv ++;
document.getElementById("Div"+currentDiv).style.display = "ihherit";
}
If you put all of the element IDs into an array, and then use that to get the next item you can remove the dependence on the ID numbering determining the order that they rotate in, and also prevent them from needing to follow such a rigid format.
//add all element IDs to this array
var elements = ["firstElementID","div2","someConentsID","lastElementID"];
var currentIndex = 0;
//ensure that the first item is visible at the start.
function next()
{
//hide current item.
document.getElementById(elements[currentIndex]).Style = "display:none";
//move up the current index by one, wrapping so as to stay within array bounds.
currentIndex = (currentIndex + 1) % elements.length;
//show the new current item.
document.getElementById(elements[currentIndex]).Style = "display:inline";
}
You can adjust the show/hide code to use JQuery, or whatever other mechanism you want.

Categories