I'm trying to find an element where the Id name has changed (and I'm not sure what it's been changed to), so I need to find it dynamically instead. The current code is:
[FindsBy(How = How.Id, Using = "address.surname")]
public IWebElement AddressLastname_Input { get; set; }
public void AddressEnter_function(IWebDriver D, DataRow UserDetail)
{
log.sendkeylog(AddressLastname_Input,
UserDetail["LastName"].ToString(),
"Enter LastName Address Section", drv: D);
}
The corresponding HTML:
<div class="form-group">
<label class="control-label " for="address.surname">
Last name<span> <font color="red">*</font></span>
</label>
<input id="address.surname" name="lastName" class="form-control form-
control" required="required" type="text" value="">
</div>
The error I get is "Cannot find element by Id". Is there a way of finding it without knowing the specific Id name/text?
It's hard to answer without seeing your HTML markup, but if Id and name keep changing, perhaps you can try locating it via CSS or even better, XPath?
XPath has proven to be more reliable for me albeit a bit slower.
WebDriver.FindElement(By.XPath("//input[#class='login']")).Click();
In your code, form-control class should give you a hint so maybe you want to run an xpath that searches for elements of type input, that have the class form-control and optionally checking value as well?
This request is not making sense to me 100%. If the element is not found, is it on an iFrame or modal by chance?
Is the id changing? If so you could try:
//div[#class='form-group']/input[#name='lastName']
or
//label[#for='address.surname']/following-sibling::input
Related
i want to sendkeys "description" within a textarea. I have tried all the possible ways but does not work.
HTML of the element :
<div class="ta-scroll-window ng-scope ta-text ta-editor form-control" ng-hide="showHtml">
<div class="popover fade bottom" style="max-width: none; width: 305px;">
<div class="arrow"></div>
<div class="popover-content"></div>
</div>
<div class="ta-resizer-handle-overlay">
<div class="ta-resizer-handle-background"></div>
<div class="ta-resizer-handle-corner ta-resizer-handle-corner-tl"></div>
<div class="ta-resizer-handle-corner ta-resizer-handle-corner-tr"></div>
<div class="ta-resizer-handle-corner ta-resizer-handle-corner-bl"></div>
<div class="ta-resizer-handle-corner ta-resizer-handle-corner-br"></div>
<div class="ta-resizer-handle-info"></div>
</div>
<div id="taTextElement737852736512107" contenteditable="true" ta-bind="ta-bind" ng-model="html" ta-keep-styles="true" class="ng-pristine ng-valid ta-bind ng-empty ng-touched" an-form-object-name="Açıklama" name="Açıklama">
<p>
<br>
</p>
</div>
</div>
Code trial :
Dim action2 = New Actions(driver)
Dim cekbul2 = driver.FindElement(By.XPath("//*#id=""taHtmlElement737852736512107""]"))
cekbul2.SendKeys("Açıklama")
Console.Write("textarea send description")
or
Dim cekbul2 = driver.FindElement(By.XPath("//textarea[#class='ng-pristine ng-untouched ng-valid ng-scope ta-bind ta-html ta-editor form-control ng-empty ng-hide' and #id='taHtmlElement737852736512107']"))
The error is :
"no such element: Unable to locate element does not work" give error
Your html does not have a text area input field inside it.
When you use an xPath that says
'//textarea' this means that you are looking for an element that has tags of <textarea> </textarea>
It looks like your html is actually div's that are styled up to look like text areas.
That is why your second attempt will never work - because you are looking for a textarea where none exists.
Typically, in the situation where a div is styled up to work like a text area or textbox, you will find that the div has a backing input behind it.
These must be located between the
<form> and </form> tags in the html - otherwise the server would never be able to receive the data. (Html 5 provides new ways of working with this - but that is another story)
Can you examine your full html, and see if you can find the actual text area objects or the input type objects that end up containing the text content.
Type some dummy text, and use an html inspector tool within chrome or firefox to look for your dummy text.
If however, the post is completed by javascript - you may find that the javascript does not use inputs or text areas for containing the text and instead posts it external to any form elements. This is common with richtext emulators such as forum post pages.
If that is the case- you may need to experiment and find the appropriate html element that you need to send keys to in order for the content to work.
Also - could you try
Dim cekbul2 = driver.FindElement(By.XPath("//div[#id='taHtmlElement737852736512107']"))
I couldnt help but notice it had an xPath syntax error - you had no starting [ square bracket ] - also, in programming it is sometimes considered lazy a bad practice to wildcard / work with dynamics. I recommend always using the tag type for your xpaths, as opposed to '//*'
Worse case scenario, I would say that you could probably get around this by using Javascript execution. Eg: Directly setting the text, instead of 'sending the key strokes'.
However, this does not emulate human behavior - but it may be a necessary evil depending on your situation.
To send text to the <p> tag you have to use the ExecuteScript() method from IJavaScriptExecutor Interface and you can use the following code block :
((IJavaScriptExecutor)driver).ExecuteScript("document.getElementsByTagName("p")[0].innerHTML="Hasan Sarıkaya";");
I want to highlight some points here
Most probably your locator which you are using is not correct.
There are three way which I know to enter text using selenium
1)Use driver.findElement(yourLoator).sendKeys("Stringvalue");
2)You can use action class to send keys
3)You can use javascript executor to change innerHtml code
Personally ill not prefer the third solution, because we are testers I believe changing dom attribute is a good practice
Hope this will give you some help. please Let me know in case any query.
Im trying to get field value (having link inside) for future use, so i want to place it under parameter.
the problem is the his class name used if 7 more fields so he isnt unique.
is there a way to get this field value using the label value above this field (called "Get direct link")?
<div class="form-group">
<label>Get direct link:</label>
<input class="form-control" type="text" style="cursor: auto;
value="http://ds2.dev.polebeary.com/api/download/1521723231257836/qa_yaakov_tevel.dmg" readonly="">
</div>"
need the link (who can be change of course..)
What you need here is XPath. Find this element by using following XPath expression.
//div[#class="form-group"][label[text()="Get direct link:"]]/input
Means: Select input field which is in a div. That div has an attribute class = "form-group" and at least have a child with name label, and that label has text "Get direct link:" in it.
For C# syntax
if you are using IWebDriver:
var element = driver.FindElement(By.XPath("//div[#class="form-group"][label[text()="Get direct link:"]]/input"));
if you are using WebDriverWait:
var element = waitDriver.Until(ExpectedConditions.ElementIsVisible(By.XPath("//div[#class="form-group"][label[text()="Get direct link:"]]/input")));
I have a project which contains a simple form for collecting signup info. Recently I have been working to add localization to the project, as all of the text shown to the user was hardcoded. I'm not sure what changed, but for some reason, now when Razor renders an HTML element using the Html.EditorFor method that ends up being a textbox, the Name property of the element has ".textbox" appended to it.
This breaks the bindings, so that when I receive my model all of the text values are null. Here is an example of what I'm seeing, Razor code:
<div class="form-group" ng-class="{ 'has-error': validate && accountForm.FirstName.$invalid }">
#Html.LabelFor(m => m.FirstName, new { #class = #ViewBag.LabelCssRequired })
<div class="#ViewBag.TextboxCss">
#Html.EditorFor(m => m.FirstName, new { htmlAttributes = new { ng_model = "firstName" } })
</div>
</div>
and here is the rendered output:
<input class="text-box single-line form-control ng-valid-maxlength ng-not-empty ng-dirty ng-valid-parse ng-valid ng-valid-required ng-touched" id="FirstName_textbox" maxlength="100" name="FirstName.textbox" ng-model="firstName" required="required" type="text" value="">
It is also adding a "_textbox" to the id, but I'm not as concerned about that at the moment. For some reason, this only seems to be happening to input elements where the type is "text". I have another input generated with.EditorFor which has the type of email and it doesn't have any modifications to the name.
This behavior also seems to be restricted to Html.EditorFor, if I use.TextboxFor, it works fine.
I have been able to make the bindings work by explicitly setting the #Name property in Razor, but this only masks the symptom, and I would like to avoid having to do this for every text input on the site.
Has anyone seen this behavior before, or know of a fix?
By default, the TextBoxFor helper generates HTML using a built-in template. You can override the defaults by creating files in the project root\views\shared\editortemplates folder.
Therefore the problem can be caused by some custom template being present there. Normally, you need to check for files whose name Match either the datatype (such as string) or the control type (such as TextArea). If the corresponding model property has a UIHint attribute on it, a custom file specified in it can also come into play.
I have an Options field in my website where there are two child options. One is Change Password and other is Logout. I want to verify whether this two options are available there in a sequential order. Which mean the first option should be Change Password and the second option should be Logout. Here is the HTML of that portion:
<div class="user-options-container">
<div class="user-options-header">OPTIONS</div>
<div class="user-options">
<div class="user-options-item" action="changepwd">Change Password</div>
<div class="user-options-item" action="logout">Logout</div>
</div>
</div>
How can I achieve that? What I know is I can get them creating a list of IWebElement class and then verify those elements. But, getting confused on how to do that. I am using Selenium Web Driver 2 and C# as my language.
Giving a quick solution on Java. But similar apis should be there in C#.
How about doing like this. For the HTML:
<div class="user-options-item" action="changepwd">Change Password</div>
<div class="user-options-item" action="logout">Logout</div>
get both the WebElement like this:
List<WebElement> elements = driver.findByElements(By.class("user-options-item"))
then you can get the text of element like:
elements.get(0).getText() //Change Password
elements.get(1).getText() //Logout
And check their orders. This should work for the given code, but if the same class is shared for other elements too, then the order will change.
I want to get the A href of that element in span class="floatClear" whose rating is minimum in
span class="star-img stars_4"
How can I use HtmlAgilityPack to achieve this behaviour I have give the html source of my file
<div class="businessresult"> //will repeat
<div class="rightcol">
<div class="rating">
<span class="star-img stars_4">
<img height="325" width="84" src="http://media1.px" alt="4.0 star rating" **title**="4.0 star rating">
</span>
</div>
</div>
<span class="floatClear">
<a class="ybtn btn-y-s" href="/writeareview/biz/KaBw8UEm8u6war_loc%NY">
</span>
</div>
The query I have written
var lowestreview =
from main in htmlDoc.DocumentNode.SelectNodes("//div[#class='rightcol']")
from rating in htmlDoc.DocumentNode.SelectNodes("//div[#class='rating']")
from ratingspan in htmlDoc.DocumentNode.SelectNodes("//span[#class='star-img stars_4']")
from floatClear in htmlDoc.DocumentNode.SelectNodes("//span[#class='floatClear']")
select new { Rate = ratingspan.InnerText, AHref = floatClear.InnerHtml };
But I do not know how to apply condition here at last line of LINQ query!
Don't select "rating" from the entire htmlDoc, select it from the previously found "main".
I guess you need something like:
var lowestreview =
from main in htmlDoc.DocumentNode.SelectNodes("//div[#class='rightcol']")
from rating in main.SelectNodes("//div[#class='rating']")
from ratingspan in rating.SelectNodes("//span[#class='star-img stars_4']")
from floatClear in ratingspan.SelectNodes("//span[#class='floatClear']")
select new { Rate = ratingspan.InnerText, AHref = floatClear.InnerHtml };
I hope it will not crash if some of those divs ans spans are not present: a previous version of the HtmlAgilityPack returned null instead of an empty list when the SelectNodes didn't find anything.
EDIT
You probably also need to change the "xpath query" for the inner selects: change the "//" into ".//" (extra . at the beginning) to signal that you really want a subnode. If the AgilityPack works the same as regular XML-XPath (I'm not 100% sure) then a "//" at the beginning will search from the root of the document, even if you specify it from a subnode. A ".//" will always search from the node you are searching from.
A main.SelectNodes("//div[#class='rating']") will (probably) also find <div class="rating">s outside the <div class="rightcol"> you found in the previous line.
A main.SelectNodes(".//div[#class='rating']") should fix that.