My application must be used in IE. I am automating test in which the script will do the following in listed order
select option 'Accounting' in drop-box "Category" to get Accounting-associated options displayed in drop-box "Category"
select option 'Payment" in drop-box "Name" for page 'Accounting Payment Filter' to display
verify that the 'Employee' text-box in this page is visible
HTML source BEFORE option 'Payment' is selected (the page 'Accounting Payment Filter' has not displayed):
<form id="Main">
<span id="Entity">
<div>
<select id="drop_Category">
<option value =""/>
<option value = "Accounting">
<select id="drop_Name"> <-!
<option value =""/>
<option value ="Payment">
HTML source AFTER option 'Payment' is selected (page 'Accounting Payment Filter' displays and there is an iframe)
<form id="Main">
<span id="Entity">
<div class="ig_Control">
<div class ="ig_content">
<iframe title ="javascript:''">
<html>
<body>
<form id="Form1">
<div id="Panel1">
<table id="table1"
<tr>
<td>
<input id="Employee">
<div>
<select id="drop_Category">
<option value =""/>
<option value = "Accounting">
<select id="drop_Name"> <-!
<option value =""/>
<option value ="Payment">
I have the code up to 'Payment' option is selected. Now I call SwitchIframe function, then find and verify the text-box:
public static bool IsTextboxVisible (IWebDriver driver, Dictionary of all needed data )
{
//....
//Call to switch into iframe
SwitchIFrame(driver,stringXPath);
//Verify text-box is visible
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(1));
//Script crashes here- can't find element
var Textbox = wait.Until(d => d.FindElement(By.Id(TexboxID)));
return Textbox.Displayed;
}
public static void SwitchIFrame (IWebDriver driver,string strXPath)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
var iFrame = wait.Until(d => d.FindElement(By.XPath(strXPath)));
driver.SwitchTo().Frame(iFrame);
}
Script can't find the text-box even when I increase the waiting time. Then I tried finding the ID "drop_Name" instead, and the script can find that drop-box. That means it did not switch into the iframe. So I switch that SAME iframe one more time:
public static bool IsTextboxVisible (IWebDriver driver, Dictionary of all needed data )
{
//....
//Call to switch into iframe
SwitchIFrame(driver,stringXPath);
//Call again to switch into the same iframe
SwitchIFrame(driver,stringXPath);
//Verify text-box is visible
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(1));
//Script crashes here- can't find element
var Textbox = wait.Until(d => d.FindElement(By.Id(TexboxID)));
return Textbox.Displayed;
}
Now script can find the text-box though sometimes is still given the exception that the XPath cannot be evaluated or not results in a web element. I update function SwitchIFrame:
public static void SwitchIFrame (IWebDriver driver,string strXPath)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
try
{
var iFrame = wait.Until(d => d.FindElement(By.XPath(strXPath)));
driver.SwitchTo().Frame(iFrame);
}
catch (NoSuchFrameException)
{
var iFrame = wait.Until(d => d.FindElement(By.XPath(strXPath)));
driver.SwitchTo().Frame(iFrame);
}
}
But the same exception still happens sometimes in the 'try...' block. My questions:
Why do I have to switch the same iframe twice to get inside one iframe?
Why didn't 'try...catch...' in SwitchIframe function catch the
exception?
Any help is highly appreciated.
You may need to switch around the order of events a little bit. Based on the code you have I would actually wait on those additional divs that are loaded after the selection to become visible.
public static bool IsTextboxVisible (IWebDriver driver, Dictionary of all needed data )
{
//Verify text-box is visible
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
var Textbox = wait.Until(d => d.FindElement(By.ClassName("ig_content")));
SwitchIFrame(driver,stringXPath);
return Textbox.Displayed;
}
public static void SwitchIFrame (IWebDriver driver,string strXPath)
{
//var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
var iFrame = driver.FindElement(By.XPath(strXPath));
driver.SwitchTo().Frame(iFrame);
}
The reason for the change of order is that those divs are connected to the original html document. Assuming those divs appear when the iFrame is loaded you should be the able to switch to the new iFrame document. If your xPath does not work (IE may or may not play well with it) I would try using the index position of the frame in the switch to. This might be more reliable since the frame does not have an id to find.
driver.SwitchTo().Frame(1);
I removed the wait from the switch statement because in this case if the iFrame is dependent on the divs loading all you should need to do is have the divs there and the frame is loaded a long with it.
Related
I use C# with Selenium and testing the application running on Chrome at the moment but hoping to expand all browsers. So I try couple code below and they're not working on the click action. I use XPath, but it throws an exception saying there is no element found in the form. I don't put submit on the form. I also use the other normal way, but it does not submit anything:
<div id="textAreaSection">
<div class="textArea">
<label><b>TextArea:</b></label><br>
<textarea id="textAreaText" rows="14" cols="40"></textarea>
</div>
<div class="surveyBtn">
<input id="inputSubmit" onClick="inputText()" type="submit" value="Input Text">
</div>
</div>
I try this, but no clicking or submitting anything after it's executed:
IWebElement tagElement = driver.FindElement(By.Id("inputSubmit"));
tagElement.Submit();
I try XPath, but the exception is thrown saying that it cannot find an element in the form:
driver.FindElement(By.XPath("//input[#id='inputSubmit']")).Submit();
Update: 1
I try to use WebDriverWait suggested by LoflinA but still throws an exception about not clickable at point (387,590). Another element would receive the click:
public void WaitUntilClickable(IWebElement elementLocator, int timeout)
{
try
{
WebDriverWait waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
waitForElement.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
And here is the caller block:
IWebElement tag = driver.FindElement(By.XPath("//div[#class='surveyBtn']/input[#id='inputSubmit']"));
WaitUntilClickable(tag, 10);
tag.Click();
Update: 2
Thanks to #chris-crush-code below code works!
public void CallSubmitType(IWebElement tag, IWebDriver driver)
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
string script = tag.GetAttribute("onClick");
js.ExecuteScript(script);
}
[Then(#"SpecFlowTesting")]
public void SpecFlowTesting(string expectedStr)
{
IWebElement tag = driver.FindElement(By.Id("inputSubmit"));
CallSubmitType(tag, driver);
IWebElement tagTextArea = webDriver.FindElement(By.Id("textAreaText"));
string txt = tagTextArea.GetAttribute("value");
Assert.AreEqual(expectedStr, txt);
}
a recent update of chrome requires you to scroll to the clickable object. So:
var js = (IJavascriptExecutor)driver;
IWebElement obj = driver.FindElement(By.XPath("//input[#id='inputSubmit']"));
js.ExecuteScript("arguments[0].scrollIntoView(true);", obj);
obj.Click();
As you have mentioned receiving the error detailing that another element would receive the click, I am thinking that your page has not loaded completely prior to the action being attempted. Try the following to wait for the element to be clickable:
// Wait Until Object is Clickable
public static void WaitUntilClickable(IWebElement elementLocator, int timeout)
{
try
{
WebDriverWait waitForElement = new WebDriverWait(DriverUtil.driver, TimeSpan.FromSeconds(10));
waitForElement.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
Also see: Selenium Web Driver & Java. Element is not clickable at point (36, 72). Other element would receive the click:
As per the HTML you have shared the WebElement clearly have a onClick() attribute so Java click() should work. But we are not sure if the WebElement is within a form or not to guarantee submit() method to work.
To click() on the button with value as Input Text you can try the following line of code :
driver.FindElement(By.XPath("//div[#class='surveyBtn']/input[#id='inputSubmit']")).Click();
I have an issue where between two pages I am sharing a modal, both pages are using the same angularJs version(v1.2.14), and both pages call the exact same directives (ui.select2). The select box inside of the modal works on one page, whilst on the other it simply stay as the default option.
As an fyi I have tried implementing the select box in different styles e.g. ng-repeat on the options, and not using the track by. This however results in the other pages selecting options to break. I can only ever get one page to work and the other to break.
The strange thing is that in the background the bound value is updating correctly:
<div class="col-md-10">
<select ui-select2="{width: '100%'}" class="form-control"
ng-model="Model.DocumentTypeId"
ng-options="documentType.DocumentTypeId as documentType.DocumentTypeDescription for documentType in Model.DocumentTypes track by documentType.DocumentTypeId">
<option value="">Select Document Type</option>
</select>
</div>
If you have any suggestions of why this is occurring it would be great.
Here is a heavily truncated view of the controller:
module Views.TMDocumentUpload {
export class DocumentUpload implements IDocumentUpload {
public static SetupDocumentUploadDialog = "onSetupDocumentUploadDialog";
public Init(model: DocumentUploadViewModel) {
var self = this;
if (self.$scope.Model.HideDocumentType || self.$scope.Model.DocumentTypeId == null) {
if (self.$scope.Model.DocumentTypes.length == 1) {
self.$scope.Model.DocumentTypeId = self.$scope.Model.DocumentTypes[0].DocumentTypeId;
}
}
}
constructor(public $scope: IDocumentUploadScope, $http: ng.IHttpService, $timeout: ng.ITimeoutService) {
$scope.isAllSelected = true;
$scope.ShareConfig = [];
$scope.Model.DisplayShareOptions = false;
$scope.Init = () => {
var self = this;
$scope.$on(DocumentUpload.SetupDocumentUploadDialog,
(e: ng.IAngularEvent, args?: Views.TMDocumentUpload.DocumentUploadViewModel) => {
self.$scope.Model = new DocumentUploadViewModel();
$http.get("/GetInitialModel")
.success(function (data: DocumentUploadViewModel) {
angular.extend(data, args);
self.Init(data);
});
});
};
}
}
DocumentUpload.$inject = ["$scope", "$http","$timeout"];
}
I have resolved the issue by removing ui-select2, it seems that this was causing some sort of conflict with another directive in my second page.
I've been trying, without luck, to use IJavaScriptExecutor to find a specific header string in a page. Here's the html code form the page:
<div class="wrap">
<h2>Edit Page <a href="http://www.webtest.bugrit.net/wordpress/wp-admin/post-
new.php?post_type=page" class="add-new-h2">Add New</a></h2>
<div id...
The text I need to check for is the "Edit Page" string.
This is the closest I've come, which isn't very close:
var element = FFDriver.Instance.FindElements(By.ClassName("add-new-h2"));
IJavaScriptExecutor js = FFDriver.Instance as IJavaScriptExecutor;
if (js != null) {
string innerHtml = (string)js.ExecuteScript("return arguments[0].innerHTML;", element);
//System.Windows.Forms.MessageBox.Show(innerHtml);
if (innerHtml.Equals("Edit Page")) {
return true;
} else {
return false;
}
}
Now, I realize that the text I should expect to get from that code isn't the exact string "Edit Page". But shouldn't it return something? When I enable the MessageBox line, the innerHtml string is empty.
Or, of couse - if someone knows another, possible easier, way to check for the existance of a specific string inside a specific html tag, I'm all ears.
Your element returns you <a> element, not <h2>. Your <a> doesn't contain Edit Page string.
Try find your element like this to the parent element <h2> (only if class name add-new-h2 is unique, otherwise you will get the first matching one):
var element = FFDriver.Instance.FindElement(By.XPath(".//a[#class='add-new-h2']/.."));
var containsText = element.Text.Contains("Edit Page");
Using Selenium / C#
I have an automated test case where a user logs in (jonpark2), once the user has done so their username is stored in the text of a span class, I need to select this element and then verify an assert on it.
I have the below to try and select this:
public static void Userloggedin()
{
var userlogedin = Driver.Instance.FindElement(By.ClassName("username"));
var selectelement = new SelectElement(userlogedin);
selectelement.SelectByText("JonPark2");
}
When I run this i encounter the error OpenQa.Selenium.Support.UI.unexpectedTagNameException:Element should have been select but was div.
The below html shows in more detail what I am trying to select:
<div class="content-wrapper">
<div class="float-left">
<div class="float-right">
<section id="login">
<p>
<a title="Manage your account" class="username" href="Account/Manage">
Text - Empty Text Node
<span class="username">
Text - JonPark2
Can anyone point out where I have gone wrong ?
You are trying to select something that is not part of a <select>.
try this:
public static void Userloggedin()
{
return (
"JonPark2" == Driver.Instance.FindElement(By.cssSelector("section#login span.username")).Text;
)
}
You can select that element by XPath:
var spanElement = Driver.Instance.FindElement(By.XPath("//span[contains(#class, 'username')]"));
And then take text:
var textInSpan = spanElement.Text
I am currently working on a C# project using ASP.NET. And I'd like to implement a list of dropboxes. So a User starts with a dropbox and can select a method and next to the dropbox is a + and - button, which enables a user to add more dropboxes. So I am wondering how can I implement that is it possible to build a List of dropboxes in ASP.NET?
You don't need any server side code for this, client side scripting is ideal solution for your needs.
Having such HTML:
<div id="MainPlaceholder">
<div id="DropDownPlaceholder">
<select name="myDropDown">
<option value="1">First</option>
<option value="2">Second</option>
<option value="3">Third</option>
</select>
<button type="button" onclick="AddDropDown(this);">+</button>
<button type="button" onclick="RemoveDropDown(this);">-</button>
</div>
</div>
You need the following pure JavaScript to make it work:
<script type="text/javascript">
var added_counter = 0;
function AddDropDown(sender) {
var parent = sender.parentNode;
//make fresh clone:
var oClone = parent.cloneNode(true);
//append to main placeholder:
parent.parentNode.appendChild(oClone);
//store change in global variable:
added_counter++;
}
function RemoveDropDown(sender) {
//don't allow to remove when there is only one left
if (added_counter <= 0) {
alert("One drop down must exist");
return;
}
var parent = sender.parentNode;
//disable so value won't be passed when form submitted:
parent.getElementsByTagName("select")[0].disabled = true;
//hide:
parent.style.display = "none";
//store change in global variable:
added_counter--;
}
</script>
The code has comments, but if you need any further explanation please feel free to ask.
Live test case.
Edit: As you need to read the selected values on the server side code, better approach would be to change the name of each cloned drop down:
var totalAddedCounter = 0;
function AddDropDown(sender) {
var parent = sender.parentNode;
//make fresh clone:
var oClone = parent.cloneNode(true);
//assign unique name:
oClone.getElementsByTagName("select")[0].name += "_" + totalAddedCounter;
//append to main placeholder:
parent.parentNode.appendChild(oClone);
//store change in global variable:
added_counter++;
totalAddedCounter++;
}
Now the tricky part is reading those values. Instead of plain dropboxlistID.Text you will have to iterate over all posted values looking for what you need:
foreach (string key in Request.Form.Keys)
{
if (key.StartsWith("dropboxlistID"))
{
string text = Request.Form[key];
//.....
}