Click on the Checkbox inside the Label or Div - c#

I want to create the two methods, one for clicking on the specific checkbox and second for de-selecting the same checkbox.
I was trying to using the XPath and ID but unable to do so.
Please tell me how it can be done. Here is the HTML:
IJavaScriptExecutor js = (IJavaScriptExecutor)_driver;
js.ExecuteScript("window.scrollBy(200,document.body.scrollHeight)", "");
var mileageTextbox = driver.FindElement(By.Id("VehicleMileageMax"));
mileageTextbox.SendKeys("9500");
var checkBox = driver.FindElement(By.XPath("//label[text()='financial-check-all-8']::input[#type='checkbox'"));
Thread.Sleep(2000);
checkBox.Click();
Element is not visible
HTML code :
<input id="financial-check-all-8" type="checkbox" selected="filter.isDisabled" ng-model="filter.isDisabled" ng-change="vm.emptyFilterValue(filter);" class="ng-pristine ng-untouched ng-valid ng-empty" aria-invalid="false" tabindex="44"> <label for="financial-check-all-8" id="enabled-8" class="form-checkbox-label"></label>

You can try with this code :
//input[starts-with(#id,'financial-check-all') and #ng-model='filter.isDisabled']
Code :
var checkBox = driver.FindElement(By.XPath("//input[starts-with(#id,'financial-check-all') and #ng-model='filter.isDisabled']"));
checkBox.Click();
EDIT :
As per the Shared HTML you can use this xpath:
try to wait also before clicking on it, Just try with Thread.Sleep(4000); , If that works then we can easily replace that with webdriverwait.
//label[#for='VehicleMileageMax']/../preceding-sibling::div/descendant::input
or with this xpath :
//label[#for='VehicleMileageMax']/../preceding-sibling::div/descendant::label

Related

Selenium - Send keys to input password in a shadow-root (open) and multiple iframes for Norwegian BankId

I want to do automatic testing using test data from here with Norwegian BankId. But I can't get hold of the input field using Selenium.
What I try to do:
Go to https://www.banknorwegian.no/
Click on "Logg inn"
Click on "BankID pÄ mobil."
Click on "BankID" under "Alternativer for innlogging"
Enter "02105892090" (test user from above link) and click on "Logg inn"
Enter "02105892090" again in the "Engangskode" and click on the submit button.
HTML:
<iframe frameborder="0" width="100%" height="100%" src="<URL>" title="BankID">
<div>Lots of divs...</div>
<input data-bind=" attr: { maxlength: maxlength, type: type, id: id, 'data-type': dataType, disabled: disabled, 'aria-disabled': disabled, 'pattern': pattern, 'inputmode': 'numeric', 'max': $data.max, 'min': $data.min, 'step': $data.step, 'tabindex': $data.tabIndex, 'aria-invalid': isInvalid, 'aria-label': label }, value: val, valueUpdate: valueUpdate, css: { error: $data.err, hasFocus: hasFocus, hideCaret: $data.hideCaret, hasValue: hasValue }, event: { focus: onFocus, blur: onBlur }" autocomplete="off" autocapitalize="off" autocorrect="off" formnovalidate="" required="" maxlength="255" type="password" id="qxaTy_DZXMJPMnP_rZae_2" tabindex="2000" aria-invalid="true" pattern="[0-9]*" class="">`
</iframe>
I can get to (6.) but then I can't get hold of the <input> with type="password" under "Engangskode". It's in an iframe which makes it harder. This is what I've tried:
public void EnterSsn(string ssn)
{
var driver = WebDriverFacade.GetDriver;
driver.SwitchTo().DefaultContent();
driver.SwitchTo().Frame(0);
Assert.IsTrue(driver.FindElement(By.CssSelector("input[type='password']")).ControlDisplayed());
driver.FindElement(By.CssSelector("input[type='password']")).SendKeysWrapper(ssn, "SSN");
}
But I get the error message:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"css selector","selector":"input[type='password']"}
Does anyone have any idea how to do this?
EDIT:
With the help of all of you this is the code that finally worked:
public void EnterSsn(string ssn)
{
var driver = WebDriverFacade.GetDriver;
driver.SwitchTo().DefaultContent();
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#ifmSingicat")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("#bankid-container iframe")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.querySelector(\".full_width_height\").shadowRoot.querySelector(\"input[type=\'password\']\")"))).SendKeys(ssn);
}
The field associated with the text Engangskode is within a #shadow-root (open) which is with in a child <iframe> which is within the parent <iframe>. So to send a character sequence to the desired field you need to:
Induce WebDriverWait for the parent frame to be available and switch to it.
Induce WebDriverWait for the child frame to be available and switch to it.
Induce WebDriverWait for the desired ElementToBeClickable() which is with in the #shadow-root (open).
You can use the following solution:
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe#ifmSingicat")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.CssSelector("iframe[title='BankID']")));
new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.querySelector('div.full_width_height').shadowRoot.querySelector('input')"))).SendKeys("02105892090");
Browser Snapshot:
Here you have 2 iframes (nested iframes), so that you need to switch twice.
First switch to iframe with id=ifmSingicat then to the first iframe of the switched iframe.
//Main document
driver.SwitchTo().DefaultContent();
//Find the first frame, and use switch to frame
IWebElement containerFrame = driver.FindElement(By.Id("ifmSingicat"));
driver.SwitchTo().Frame(containerFrame);
//You are now in iframe "containerFrame", now find the nested iframe
IWebElement contentFrame = driver.FindElement(By.CssSelector("#bankid-container iframe"));
driver.SwitchTo().Frame(contentFrame);
//Now find the elements you want in the nested frame
IWebElement foo = driver.FindElement(By.CssSelector("input[type='password']"));
Note: I'm not C# developer, hope above syntax is correct.
If you are switched to correct iframe, then it just that you need to add some wait. It will provide some time to iframe elements to get loaded.

Div elements on click fires for the first element only

I am listing my data in an ItemTemplate.Then inside the ItemTemplate, i have two div tags as follows:
<ItemTemplate>
<div id="contentdiv">
<h4 id="titleresult"><%# Server.HtmlEncode(Eval("Name").ToString())%></h4>
</div>
<div id="showclick" class=hideAll>
<p class="brief"><%# Server.HtmlEncode(Eval("LegalName").ToString())%></p>
<p class="brief"><%# Server.HtmlEncode(Eval("FirstName").ToString())%></p>
<p><%# Server.HtmlEncode(Eval("LastName").ToString())%></p>
</div>
</ItemTemplate>
Then i have the css to define the hideAll class so that when the page loads, the data in this div tag is hidden until the user clicks on the contentdiv link.
.hideAll { display:none }
.displayAll { display:block; top:0px}
Then finally i have the javascript part for firing the click event.
<script type="text/javascript">
function showResults(UserID) {
var contentdiv= document.getElementById('contentdiv');
var showclick = document.getElementById('showclick');
<%
long id =0;
DataAccess dataAccess = new DataAccess();
Data = dataAccess.GetCounterParty(id);
%>
var UserID = <%=dataAccess.GetCounterParty(id) %>
contentdiv.style.visibility = "visible";
$(showclick).removeClass('hideAll');
}
</script>
The UserID is the id of every element in the list. The problem is, the click affects only the first element no matter which other element i click on the list.
In html id is used to refer to one element.
If you use it multiple times the browser would default to the first element.
You should use a class selector. Something like:
$(".contentdiv").click(function(){
$(this).next().removeClass('hideAll');
});
Here is a working example. I used toggleClass though, it seems more appropriate to me.
An id is a unique identifier, you cannot have two or more things on the same page with the same identifier and expect things to work properly. Make your identifiers unique, and bind to the click event using a class selector instead.
you should use class instead of id, id are unique, which only exist in 1 page, class can exist in multple div
some idea for u
html
<div class="showclick hideAll">
script
$('.showclick').on('click', function(){
$(this).toggle(); //toggle to show or hide, can be any element u want to toggle instead of this
});

Pass the jqueryui selected list items to the code behind

I am using the jquery ui selectable plugin on my website. I have close to 7 different lists with multi select's on the same page, all using the above plugin.
Once the user selects a particular listitem... how do i pass those selected items back to the code-behind ?
This is how i have displayed my list's on the page...
<div>
<ol class="selectable" id="wlList" runat="server" clientidmode="static">
</ol>
</div>
And this is how I have generated the list items from the database in the code behind...
wl.ToList();
foreach (var w in wl)
{
HtmlGenericControl li = new HtmlGenericControl("li");
li.Attributes.Add("class", "ui-widget-content");
li.Attributes.Add("value", w.UserID.ToString());
li.InnerText = w.FirstName;
wlList.Controls.Add(li);
}
Grateful for the help
One possible approach is storing selected values in a hidden input and then simply reading and parsing its value on the server..
Check this fiddle which is based on jQuery UI Selectable Serialize Demo.
What you need is to add hidden input(s) to your form:
<input type="hidden" id="wlListValue" name="wlListValue" />
Then implement selectable change handler like this:
$('.selectable').selectable({
stop: function(event, ui) {
var result = '';
$(".ui-selected", this).each(function() {
result += $(this).val() + ';';
});
$('#wlListValue').val(result);
}
});
And then just read selected values after postback:
var selectedValues = Request["wlListValue"].Split(";".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);

WebBrowser control: click won't work

I used the DocumentComplete event to AutoComplete a form. Everything is OK except the checkbox. The html code is the following:
<span class="myClass" style="padding-left: 12px; vertical-align: bottom; cursor: pointer;">
<input id="ich_liebe_dich" type="checkbox" name="ich$liebe$dich">
<label for="ich_liebe_dich"> MyLabel</label>
</span>
I tried using:
webbrowser.Document.GetElementById("ich_liebe_dich").InvokeMember("click");
and
webbrowser.Document.GetElementById("ich$liebe$dich").InvokeMember("click");
and also:
foreach (HtmlElement current in webbrowser.Document.GetElementsByTagName(tag))
{
if (current.GetAttribute(attr).Equals(attName))
current.InvokeMember(invoke);
}
where attr="id", tag="input", invoke="click" and attName= either "ich_liebe_dich" or "ich$liebe$dich".
The best I got was a transiently - just for a fraction of a second - checked checkbox. Why would this happen? Any solutions?
leppie's answer made me curious because I've never read anywhere about InvokeMember("check") and I googled it! The first answer I got is this http://social.msdn.microsoft.com/forums/en-US/winforms/thread/750b11dc-08f8-4cb4-bcaf-80c91f0fd425/
I read the article and found a solution...
If I add this line on DocumentCompleted event then everything works ok!
if (webbrowser.ReadyState==WebBrowserReadyState.Complete)
It seems that the page has frames and the DocumentCompleted event fires before the whole page is loaded.
edit: I forgot to mention that the code I used (and works) is the following:
webbrowser.Document.GetElementById("ich_liebe_dich").InvokeMember("click");
I had already answered a similar question
webBrowser.Navigate("http://www.google.com");
if you have id use this:
webBrowser1.Document.GetElementById("id").InvokeMember("click");
if you have tagname use this
webBrowser.Navigate("http://www.google.com");
In Web Browser DocumentCompleted event
HtmlElement textElement = webBrowser.Document.All.GetElementsByName("q")[0];
textElement.SetAttribute("value", "your text to search");
HtmlElement btnElement = webBrowser.Document.All.GetElementsByName("btnG")[0];
btnElement.InvokeMember("click");
if you have name class use this:
HtmlElementCollection classButton = webBrowser1.Document.All;
foreach (HtmlElement element in classButton)
{
if (element.GetAttribute("className") == "button")
{
element.InvokeMember("click");
}
}
for add text in textbox google.com use this:
webBrowser1.Document.GetElementById("gs_tti0").InnerText = "hello world";

Finding ID with Multiple ASP UserControl using JavaScript

I have an ASP usercontrol name ListItem. Each ListItem has 2 ASP controls on it : a label lblIndex and a button btnAction
On my page, I load 10 ListItem into a panel and set lblIndex on each ListPanel an appropriate index.
ListItem 1 : lblIndex.value = '#1'
ListItem 2 : lblIndex.value = '#2'
...
ListItem 10 : lblIndex.value = '#10'
How do I write Javascript that, each time when I click the button on a ListItem, the appropriate lblIndex's value will appear(through an Alert()). I.e. when I click the btnAction on the 2nd ListItem, the text '#2' will come out.
Thank you
to facilitate your life, use jQuery when writing javascript.
in that in mind, let's assume that your ListItem control outputs a ul list with an id... make sure that you had a class, let's imagine that you named list-item so at the end you will have:
<div id="ListItem_1" class="list-item">
...
</div>
Now, you say you some sort of a button inside that list...
<div id="ListItem_1" class="list-item>
<input id="ListItem_1_Button_1" type="button" value="I'm a Button" />
</div>
Once again, explicit give that button a class name, for example: inside-button
I don't know how you have all texts, but I'll again assume that will be a hiiden field with the text to alert ...
some thing like:
<div id="ListItem_1" class="list-item>
<input id="ListItem_1_Button_1" type="button" value="I'm a Button" />
<input id="ListItem_1_Hidden_1" type="hidden" class="text" value="Text to run" />
</div>
and assuming you have 10 lists with several buttons you can simple write:
$(".inside-button").bind("click", function() {
// a button was clicked, let's do something
});
that 1st line says: "Foreach DOM element that has a class name of inside-button attach the click event"
and inside you fire what you want to do
From your question, you only want to perform something on that list:
$(this) // that will be the .inside-button element, so the Button
.closest(".list-item") // get me the closest DOM element with a class name of "list-item"
.find(".text") // find the DOM elemnt with the class name "text"
.val(); // let's see what value that element has
then you can alert() it.
All together:
$(".inside-button").bind("click", function() {
// a button was clicked, let's do something
var txt = $(this).closest(".list-item").find("text").val();
alert( txt );
});

Categories