Grabbing JavaScript variables as they change using Selenium - selenium

I know I can grab the value of a JavaScript variable using Selenium Java APIs as follows
JavascriptExecutor je = (JavascriptExecutor) driver;
Long JSvar = (Long)je.executeScript("return variable");
But is there a way in Selenium to get every value for that variable as it changes in JS code. For example if my JS code looks as follows
var variable=1;
/* some code */
variable=2;
/* some code */
variable=3;
Is there a way to grab these three values (1,2,3)? Something like putting a breakpoint on the JS code but in an automated way.
I was thinking that I could store these values in an array and then grab the array but is there another way in Selenium to handle this with the minimal changes to the JS code?

You have not specified how or when Selenium should retrieve these values, but here is some JavaScript code that at least makes these values available:
(function(window) {
var values = [];
var someVariable;
Object.defineProperty(window, 'someVariable', {
get: function() {
return someVariable;
},
set: function(value) {
someVariable = value;
values.push(value);
}
});
Object.defineProperty(window, 'someVariableValues', {
get: function() {
return values;
}
});
})(this);
Whether JavaScript code executes window.someVariable = X or simply someVariable = X, the setter will push that value onto the array. Selenium (or JavaScript for that matter) can access window.someVariableValues to return the historical and current values of that variable.
Retrieving this using Selenium could be:
JavascriptExecutor je = (JavascriptExecutor) driver;
// Get current value of variable
Long JSvar = (Long)je.executeScript("return someVariable");
// Get all values assigned to variable (this part I'm not 100% sure about)
Long[] historicalValues = (Long[])je.executeScript("return someVariableValues");

Related

How to verify that urls are redirected its respective page in Selenium?

I am trying to automate - verification of top nav links of https://www.zillow.com.
For that I am matching actual urls with expected urls. But in page class method this line retruns null. I don't get it why?
String urlp = locator.all_topnav_links.get(i).getAttribute("href");
Method in page class:
public void verify_topnav_links() {
System.out.println("Started");
for (int i = 0; i < locator.all_topnav_links.size(); i++) {
System.out.println(locator.all_topnav_links.size());
if (locator.all_topnav_links.get(i).isDisplayed() == true) {
String link=locator.all_topnav_links.get(i).getText();
System.out.println(link);
String urlp = locator.all_topnav_links.get(i).getAttribute("href");
System.out.println("Links are : " + urlp);
// now click link one by one
locator.all_topnav_links.get(i).click();
driver.navigate().back();
// 2 verify before url with current opened url
//Assert.assertEquals(urlp, driver.getCurrentUrl());
}
Locator in locator class:
#FindAll({#FindBy(xpath = "//ul[#data-zg-section='main']/li")})
public List<WebElement> all_topnav_links;
Test case in test class:
#Test
public void verify_TopNav_links()
{
hpage.verify_topnav_links();
}
Also I am not sure whether this correct approach or not. Can anybody tell me the best approach to verify this scenario.
Note: This zillow.com will starts to display captcha if we open multiple times using selenium. To ignore it manually remove catpcha parameters from the url when test case is getting executed.
It appears you need to use
//ul[#data-zg-section='main']/li/a
here
#FindAll({#FindBy(xpath = "//ul[#data-zg-section='main']/li")})
public List<WebElement> all_topnav_links;
This xpath
//ul[#data-zg-section='main']/li
Seems to contain multiple elements. But you're trying to access the href attribute directly. The li here doesn't have a href attribute.

How to read hidden attributes from a page loaded in SWT Browser

I am working on an Eclipse plugin which loads a URL in the SWT browser. This page rendered in the browser has hidden html attributes. The requirement is to read the values of the hidden attributes.
Browser browser = new Browser(shell, SWT.NONE);
browser.setUrl("www.<my_url>.com");
I tried to execute a query on the DOM using the statusTextListener
browser.addStatusTextListener(new StatusTextListener() {
public void changed(StatusTextEvent event) {
browser.setData("query", event.text);
}
});
browser.addProgressListener(new ProgressListener() {
public void completed(ProgressEvent event) {
boolean result = browser
.execute("window.status=document.getElementById('main').childNodes[0].nodeValue;");
if (!result) {
/* Script may fail or may not be supported on certain platforms. */
System.out.println("Script was not executed.");
return;
}
String value = (String) browser.getData("query");
System.out.println("Node value: " + value);
}
});
However this does not seem to work. It works well if I try to load HTML text in the browser instead of the URL.
Any idea how to read DOM elements from the SWT browser after the page load is complete?
Use Browser::evaluate to execute Javascript in the context of the document and return the result to the caller.
To obtain the value of the first child of the main element in your example, start like this:
String script = "<Javascript to return an array of hidden attribute names>";
Object result = browser.evaluate(script);
The supported result types, however, are limited to string, number, and boolean - and arrays of these types. Javascript that evaluates to null or undefined will return null.
Hence, you will need to adjust your Javascript that queries the DOM to return a supported type.

Plugin: How to insert new method in existing PHP class?

I'm trying to create a IntelliJ plugin (mostly for learning purposes). My aim is that by pressing a keyboard shortcut the plugin will generate a corresponding PHP unit test method stub in the test file.
So let's say Db.php is open, the upon pressing Ctrl+Shift+U the plugin will create a unit test stub in DbTest.php.
So far I've figured out how to get the method name at cursor and how to locate the corresponding Unit test file (i.e. Db => DbTest) as PsiFile.
PsiFile[] search = FilenameIndex.getFilesByName(project, testFileName, scope); //scope is the test directory
PsiFile testFile = search[0];
What I cannot figure out is how to insert the generated new method stub this in testFile and then save the changes?
P.S. I see there exists a createMethodFromText function but how do I get the PsiClass from PsiFile? Also how do I save the changes?
There're just a few simple steps.
Find PhpClass you want to insert a new method in. As you already have PsiFile you can either traverse a tree manually or use PhpElementVisitor.
1.1. To travers a tree manually you can use PsiTreeUtil#findChildOfType method. In your case you'll need to find GroupStatement first, then the class you need.
1.2. Invoke PsiElement#accept method (PsiFile is an instance of PsiElement) provided with PhpElementVisitor with overridden #visitPhpGroupStatement and #visitPhpClass methods.
Use PhpPsiElementFactory#createMethod to create the new method from text. Note that this class isn't a part of the public API, so theoretically it can be easily changed/moved/removed/whatever in the future.
Use PsiElement#add (PhpClass is also an instance of PsiElement) to insert the method into the class.
That's all. You don't need to explicitly save the changes.
Here is what worked for me in the end. Thanks everyone for the help
for (int i = 0; i < found.getTextLength(); i++) {
PsiElement ele = found.findElementAt(i);
PhpClass phpClass = PsiTreeUtil.getParentOfType(ele, PhpClass.class);
if (phpClass != null) {
Method methodExists = findMethod(phpClass, methodName);
if (methodExists == null) {
new WriteCommandAction.Simple(phpClass.getProject(), phpClass.getContainingFile()) {
#Override
protected void run() throws Throwable {
PsiElement brace = phpClass.getLastChild();
if (brace != null) {
Method method = PhpPsiElementFactory.createMethod(phpClass.getProject(), "public function " + methodName + "() {\n\n}");
CodeStyleManager styleManager = CodeStyleManager.getInstance(getProject());
styleManager.reformat(method);
PsiElement newMethod = phpClass.addBefore(method, brace);
PsiNavigateUtil.navigate(newMethod);
}
}
}.execute();
} else {
PsiNavigateUtil.navigate(methodExists);
}
break;
}
}

Best way to find the type of the object locator by passing the object locator alone in Selenium Webdriver

Is their any way to find the object locator type, by passing the object locator alone.
for e.g. i need to click on a login button, where its id=login, classname=loginbutton or xpath=//input[#name='login']. I need to build method where i will be just passing the objectlocator (either id or name) as the input and its type(either id or name) should be decided in the method like if it contains // then type should be of xpath etc.
I need to pass the objectLocator() which returns type to the findElement()
WebElement element = driver.findElement(objectLocator());
I do not think it is available off the shelf, you would have to implement your own logic.
The only thing is, let's say you want to search by linktext. As per your usecase, you would, in your object repo specify, "this is my linktext".
Now how do you know it is an id or a name or a linktext?
For xpath you can check if it starts with /, then its an xpath. If its only id or name then you can use ByIdorName, but i think it would become tricky with css and linktext.
The one thing I can think is you can establish some sort of conventions like if it is linktext precede your lcoator definition with linktext=blah blah and then you split and consume it.
I find it very useful to store all my locators as By objects and either use the By directly or pass the By into methods as I need them. For example:
By passwordField= By.id("login");
By userNameField = By.name("username");
By submitButton = By.xpath("\\myxpath\div[2]");
public void clickLogin() {
driver.findElement(submitButton).click();
}
I also use static Bys from other classes as well:
public void clickLogin() {
driver.findElement(LoginPage.SUBMIT_BUTTON).click();
}
The modern way to do this is using PageFactory and PageObjects
The following is a quick and dirty which will adapt selenium locators strings to WebDriver locators.
public enum LocatorType {
CLASSNAME, CSS, ID, LINK, NAME, TAGNAME, XPATH ;
}
public WebElement objectLocator(LocatorType type, String ref) {
switch(type) {
case ID:
return this.webDriver.findElement(By.id(ref));
case CLASSNAME:
return this.webDriver.findElement(By.className(ref));
case XPATH:
return this.webDriver.findElement(By.xpath(ref));
case CSS:
return this.webDriver.findElement(By.cssSelector(ref));
case LINK:
return this.webDriver.findElement(By.linkText(ref));
case NAME:
return this.webDriver.findElement(By.name(ref));
case TAGNAME:
return this.webDriver.findElement(By.tagName(ref));
}
return null;
}
public WebElement objectLocator(String identifier) {
String typeString = identifier.substring(0, identifier.indexOf('='));
String ref = identifier.substring(identifier.indexOf('=')+1, identifier.length());
if (typeString.toLowerCase().contains("classname")) {
return objectLocator(LocatorType.CLASSNAME, ref);
} else if (typeString.toLowerCase().contains("css")) {
return objectLocator(LocatorType.CSS, ref);
} else if (typeString.toLowerCase().contains("id")) {
return objectLocator(LocatorType.ID, ref);
} else if (typeString.toLowerCase().contains("link")) {
return objectLocator(LocatorType.LINK, ref);
} else if (typeString.toLowerCase().contains("name")) {
return objectLocator(LocatorType.NAME, ref);
} else if (typeString.toLowerCase().contains("tagname")) {
return objectLocator(LocatorType.TAGNAME, ref);
} else if (typeString.toLowerCase().contains("xpath")) {
return objectLocator(LocatorType.XPATH, ref);
} else {
return null;
}
}
It looks like you are looking for this solution because you have an object repository maintained somewhere outside of your code in some kind of properties file or xml.
Using gui maps has lot of disadvantages like,
- maintain an external file with a list of locators
- parse locator files to read keys (you can abstract this but still an overhead)
- when writing PageObjects you need to switch back and forth from Page to gui map
- possibility of multiple duplicate locators in gui maps
- object repo grows over time and becomes impossible to maintain
- debugging is far more difficult
What you are looking for is adding one more layer of complexity which is not required in my opinion. Automating browsers is a challenge in itself and writing maintainable test automation code is utmost important.
Use PageFactory in your page objects.
- Natural place for your locators are Page Objects themselves.
- Locators easily accessible in page objects for review or correction
- No need for explicit driver.findElement, with #FindBy you get that for free
- modern Java and awesome annotations make page objects look beautiful & readable
I have used gui maps before and struggled a lot. Switching to page factory made me realize that using object repository was such a bad idea!
This should do for locating element. I have given example till 3 level deep.
public WebElement findElement(String locator){
WebElement w = null;
try{
return (driver.findElement(By.id(locator)));
}catch(Exception e1){
try{
return ( driver.findElement(By.name(locator)));
}catch(Exception e2){
try{
return (driver.findElement(By.xpath(locator)));
}catch(Exception e3){
System.out.println("Cound not find a locator");
e3.printStackTrace();
}
}
}
return(w);
}
public void type(String locator, String value){
try{
WebElement w= findElement(locator);
w.sendKeys(""+value);
Thread.sleep(sleepTime);
}catch(Exception e){
e.printStackTrace();
}
}
-Vinay

Selenium C# Webdriver How to detect if element is visible

Is there a way in the latest version of Selenium DotNet Webdriver (2.22.0) to check to see if an element is visible before clicking/interacting with it?
The only way I've found is to try to handle the ElementNotVisible exception that occurs when you try to send keys, or click on it. Unfortunately this only occurs after an attempt to interact with the element has been made. I'm using a recursive function to find elements with a certain value, and some of these elements are only visible in certain scenarios (but their html is still there no matter what, so they can be found).
It's my understanding that the RenderedWebElement class is deprecated as well other variants. So no casting to that.
Thanks.
For Java there is isDisplayed() on the RemoteWebElement - as well is isEnabled()
In C#, there is a Displayed & Enabled property.
Both must be true for an element to be on the page and visible to a user.
In the case of "html is still there no matter what, so they can be found", simply check BOTH isDisplayed (Java) / Displayed (C#) AND isEnabled (Java) / Enabled (C#).
Example, in C#:
public void Test()
{
IWebDriver driver = new FirefoxDriver();
IWebElement element = null;
if (TryFindElement(By.CssSelector("div.logintextbox"), out element)
{
bool visible = IsElementVisible(element);
if (visible)
{
// do something
}
}
}
public bool TryFindElement(By by, out IWebElement element)
{
try
{
element = driver.FindElement(by);
}
catch (NoSuchElementException ex)
{
return false;
}
return true;
}
public bool IsElementVisible(IWebElement element)
{
return element.Displayed && element.Enabled;
}
It seems the current answer to this question is outdated: With WebDriver 3.13 both the Displayed and Enabled properties will return true as long as the element exists on the page, even if it is outside of the viewport. The following C# code works for WebDriver 3.13 (from this StackOverflow answer):
{
return (bool)((IJavaScriptExecutor)Driver).ExecuteScript(#"
var element = arguments[0];
var boundingBox = element.getBoundingClientRect();
var cx = boundingBox.left + boundingBox.width/2, cy = boundingBox.top + boundingBox.height/2;
return !!document.elementFromPoint(cx, cy);
", element);
}
There is a simple way to do that, follow below:
public bool ElementDisplayed(By locator)
{
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(condition: ExpectedConditions.PresenceOfAllElementsLocatedBy(locator));
return driver.FindElement(locator).Displayed ;
}
You can use the following:
WebDriver web = new FirefoxDriver(;
String visibility = web.findElement(By.xpath("//your xpath")).getCssValue("display");