I am trying to select value from the drodown. this is my code.
driver.findElement(By.xpath(".//*[#id='accountSelectContainer']/span/a/span[1]")).click();
driver.findElement(By.xpath("//ul[#id='ui-id-1']/li/a[equals(text(),'60091 - AFCENT')]")).click();
Now here i have hardcoded the value, which works perfect but i am reading my testdata from excel file . so instead of using direct hard code values , i want to declare my testdata in xpath and read it from excel file. so i tried to this:
Efforts
public void combobox(String testData)
{
driver.findElement(By.xpath(".//*[#id='accountSelectContainer']/span/a/span[1]")).click();
driver.findElement(By.xpath("//ul[#id='ui-id-1']/li/a[equals(text(),'"+testData+"')]")).click();
}
But i am getting the exception
org.openqa.selenium.InvalidSelectorException: invalid selector: Unable
to locate an element with the xpath expression
//ul[#id='ui-id-1']/li/a[equals(text(),'60091 - AFCENT')] because of
the following error: SyntaxError: Failed to execute 'evaluate' on
'Document': The string '//ul[#id='ui-id-1']/li/a[equals(text(),'60091
- AFCENT')]' is not a valid XPath expression.
I tried to change it to "+testData+" too instead of using '"+testData+"'
But same exception.
I tried this code too:
driver.findElement(By.xpath(".//*[#id='accountSelectContainer']/span/a/span[1]")).click();
List<WebElement> options = driver.findElements(By.xpath("//ul[#id='ui-id-1']/li"));
for (WebElement option : options) {
if(testData.equals(option.getText()))
option.click();
}
which works perfect but after this code execution , it is making my browser to wait for about 15 secs before executing next step or for quit too. i am not getting Why so ?
Please need suggestion or any ideas..
I doubt your fast attempt works perfect as xpath doesn't have equals. You would have gotten the same exception. To check for text equality use =
"//ul[#id='ui-id-1']/li/a[text()='"+testData+"']"
You can also use contains
"//ul[#id='ui-id-1']/li/a[contains(text(),'"+testData+"')]"
First: the exception you have got is because you xpath: //ul[#id='ui-id-1']/li/a[equals(text(),'60091 - AFCENT')] is not correct syntax.
Second: the code that you can run is not make your browser wait for 15s, it's just because problem about internet connection or you computer is a little slow.
Related
I am working on a test automation for an iOS app.
I use the Appium-desktop-client (1.15.1) on MacOS (10.15) and find an element on Iphone 11 (13.3) via the Inspector with the following attributes:
screenshot from the attributes
The goal is to do the following in java with appium (6.1.0) and selenium (3.13.0):
Find this element via the elementId and get the variable value (in this case 2,6 km).
The problem is reaching the element. In the Inspector, the accessibility-id and the name are always equal to the value, which means that I cannot localize the element with them.
The elementId is not fixed, it varies after the 3rd block of numbers (that means I can only use the 45000000-0000-0000.) I can also reproduce this elementId from the Inspector using the code from the "UID" attribute.
To localize the element I tried the following:
appiumDriver.findElementByXPath("//*[contains(#id,'45000000-0000-0000')]");
appiumDriver.findElementByXPath("//*[contains(#name,'45000000-0000-0000')]");
appiumDriver.findElementByXPath("//*[contains(#uid,'45000000-0000-0000')]");
appiumDriver.findElementByXPath("//*[contains(#elementId,'45000000-0000-0000')]");
appiumDriver.findElementByXPath("//*[contains(#RuntimeId,'45000000-0000-0000')]");
appiumDriver.findElementByXPath("//*[contains(#ProcessId,'45000000-0000-0000')]");
appiumDriver.findElementByXPath("//*[contains(#class,'45000000-0000-0000')]");
However, with all these attempts to locate the element came an org.openqa.selenium.NoSuchElementException.
My question now is, what do I have to write in the xpath to find the element via the part of the elementId from the Inspector (or the attribute UID) and then be able to read out the value.
I would try this secure option :
//*[local-name(#*)="#elementId"][starts-with(normalize-space(string(#*)),"45000000-0000-0000")]
EDIT : contains option doesn't work because the elementId is not the first attribute of the element.
Could you try :
//*[#*="45000000"]
If this doesn't work let's bruteforce this with :
//*[contains(#*[2],'45000000')]
//*[contains(#*[3],'45000000')]
//*[contains(#*[4],'45000000')]
//*[contains(#*[5],'45000000')]
//*[contains(#*[6],'45000000')]
//*[contains(#*[7],'45000000')]
//*[contains(#*[8],'45000000')]
//*[contains(#*[9],'45000000')]
//*[contains(#*[10],'45000000')]
//*[contains(#*[11],'45000000')]
Summary
I want to figure out a way to add a <script> tag into the head of DOM using Selenium's JavascriptExecutor, or any other way of doing this would be nice.
I have tried many ways and also found a few similar topics and none of them solved my problem which is why I felt the need to ask it on here.
For example :
Suggested solutions in this question did not solve my problem. Some people say it worked for them but nope, it didn't for me.
What I've been trying to execute?
Here is the small snippet of the code that I want to execute:
WebDriver driver = new FirefoxDriver();
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("var s = document.createElement('script');");
jse.executeScript("s.type = 'text/javascript';");
jse.executeScript("s.text = 'function foo() {console.log('foo')}';");
jse.executeScript("window.document.head.appendChild(s);");
I just skipped the code above where you navigate to a webpage using driver.get() etc. and then try to execute the scripts.
Also, s.text would contain the actual script that I want to use so I just put there a foo() function just to give the idea.
The above code throws this error when you run it:
Exception in thread "main" org.openqa.selenium.JavascriptException: ReferenceError: s is not defined
So far I've tried every possible solution I could find on the Internet but none of them seems to work.
OP came up with the following solution:
jse.executeScript("var s=window.document.createElement('script');" +
"s.type = 'text/javascript';" + "s.text = function foo() {console.log('foo')};" +
"window.document.head.appendChild(s);");
For one, this line is invalid.
jse.executeScript("s.text = 'function foo() {console.log('foo')}';");
Note how you wrap single-quote text in single quotes. Use one set as "\""
I would personally do this by doing (edited to make it a global function):
using OpenQA.Selenium.Support.Extensions;
driver.ExecuteJavascript("window.foo = function foo() {console.log('foo')}");
It's as simple as that. You are registering foo as a method by doing this. After you execute this javascript, you can manually go in to the browser developer tools and call "foo()" to check. Additionally, you can check this by registering it directly in the console. Just enter "function foo() {console.log('foo')}" into your browser console, and then call "foo()".
No need to add this as a script tag.
EDIT #2: I fixed my above code suggestion so that the method is assigned to the window, and thus accessible globally, and outside of the anonymous script that javascript executor runs the code in. The original issues with this not working are resolved by this, at least in my testing of it.
I am looking for some help as am just getting into a web automation using Selenium with the Java bindings. I am trying to find the total number of text boxes on a web page, I have the code working for checking #type=text. The code is below, however, when I try to find text boxes by:
"//input[#type='text'[#class='dijitReset dijitInputInner']" and it fails. The full code is below.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//Launch browser
driver.get("http://localhost/2010A15/?p=register");
//Create Web element list
java.util.List<WebElement> textboxes = driver.findElements(By.xpath("dijitReset dijitInputInner']"));
System.out.println(textboxes.size());
for(int i=1; i<=textboxes.size(); i=i+1);
{
System.out.println(textboxes.size());
}
driver.close();
}
}
Error Message:
Exception in thread "main"
org.openqa.selenium.InvalidSelectorException: The given selector
dijitReset dijitInputInner'] is either invalid or does not result in a
WebElement. The following error occurred: InvalidSelectorError: Unable
to locate an element with the xpath expression dijitReset
dijitInputInner'] because of the following error: SyntaxError: The
expression is not a legal expression.
I presume the error is telling me that dijitReset dijitInputInner is not valid and that's why it isn't working, however, I am unsure on how to fix this. Any help? As the class of the item in inspect element is: dijitReset dijitInputInner.
if you only want to count the numbers of elements (textboxes) than you can avoid looping each webelement by using size()
int boxes = driver.findElements(By.xpath(".//*[#class='dijitReset dijitInputInner']")).size();
List<WebElements> totalTextboxes = driver.findElements(By.xpath("//input[#type='text']"));
System.out.println(totalTextboxes.size());
List<WebElement> textBoxes=driver.findElements(By.xpath(//input[#type='text']));
i=textBoxes.size();
List<WebElement> textBoxes=driver.findElements(By.xpath(//input));
for(WebElement each:textBoxes){
String local=each.getAttribute("type");
if(local!=null && local.equals("text") i++;
}
What can I do in case if I load the page in Selenium and then I have to do like 100 different parsing requests to this page?
At this moment I use different driver.findElement(By...) and the problem is that every time it is a http (get/post) request from java into selenium. From this case one simple page parsing costs me like 30+ seconds (too much).
I think that I must get source code (driver.getPageSource()) from first request and then parse this string locally (my page does not change while I parse it).
Can I build some kind of HTML object from this string to keep working with WebElement requests?
Do I have to use another lib to build HTML object? (for example - jsoup) In this case I will have to rebuild my parsing requests from webelement's and XPath.
Anything else?
When you call findElement, there is no need for Selenium to parse the page to find the element. The parsing of the HTML happens when the page is loaded. Some further parsing may happen due to JavaScript modifications to the page (like when doing element.innerHTML += ...). What Selenium does is query the DOM with methods like .getElementsByClassName, .querySelector, etc. This being said, if your browser is loaded on a remote machine, things can slow down. Even locally, if you are doing a huge amount of round-trip to between your Selenium script and the browser, it can impact the script's speed quite a bit. What can you do?
What I prefer to do when I have a lot of queries to do on a page is to use .executeScript to do the work on the browser side. This can reduce dozens of queries to a single one. For instance:
List<WebElement> elements = (List<WebElement>) ((JavascriptExecutor) driver)
.executeScript(
"var elements = document.getElementsByClassName('foo');" +
"return Array.prototype.filter.call(elements, function (el) {" +
" return el.attributes.whatever.value === 'something';" +
"});");
(I've not run the code above. Watch out for typos!)
In this example, you'd get a list of all elements of class foo that have an attribute named whatever which has a value equal to something. (The Array.prototype.filter.call rigmarole is because .getElementsByClassName returns something that behaves like an Array but which is not an Array so it does not have a .filter method.)
Parsing locally is an option if you know that the page won't change as you examine it. You should get the page's source by using something like:
String html = (String) ((JavascriptExecutor) driver).executeScript(
"return document.documentElement.outerHTML");
By doing this, you see the page exactly in the way the browser interpreted it. You will have to use something else than Selenium to parse the HTML.
Maybe try evaluating your elements only when you try to use them?
I dont know about the Java equivalent, but in C# you could do something similar to the following, which would only look for the element when it is used:
private static readonly By UsernameSelector = By.Name("username");
private IWebElement UsernameInputElement
{
get { return Driver.FindElement(UsernameSelector); }
}
I have created a test case in Selenium WebDriver using the TestNG framework. I am trying to getText() and print it and also use it in Assert.assertEquals().
The problem I am facing is when I run this test case, it is showing error "java.lang.AssertionError: expected [] but found [Register here]" and also nothing prints in the "ab" variable.
My test case
#Test
public void signinpopup()
{
driver.get("http://uat.tfc.tv/");
driver.findElement(By.id("login_buttoni")).click();
String ab = driver.findElement(By.xpath("html/body/section[1]/div/div[1]/div[7]/div[2]/a")).getText(); // ab variable contains value "Register here"
System.out.println(ab);
System.out.println("hello1");
//Assert.assertEquals("Registe12r here", driver.findElement(By.xpath("html/body/section[1]/div/div[1]/div[7]/div[2]/a")).getText());
Assert.assertEquals(ab,"Regist5434er here");
}
One more thing: When I change the assert condition to Assert.assertEquals(ab,"Register here");, it will print the "ab" variable.
What is going on here?
Your error is pretty clear. The text you are looking for is Register here which is indeed found by Selenium.
The question is why did you write Regist5434er here in your assertEquals.
Just change that line to:
assertEquals(ab, "Register here");
You are getting an assertion failure, because 'ab' has an empty value. This might be because you are not locating the element properly. It is always recommended to use a relative XPath expression rather than an absolute XPath expression to locate the element.