Selenium WD | Trying to use an 'If' statement with logical 'or' - css

I have a step in my test that goes into several html pages and looks for an element on the screen. That element can have 2 different CSS class names while looking the same in the website (visually speaking) , I have to use an if statement with a logical 'or' to identify them
if (Status == driver.findElement(By.cssSelector(".inlineblock.redClockBigIcon.middle.isOpenExchBig-2")) || Status == driver.findElement(By.cssSelector(".inlineblock.redClockBigIcon.middle.isOpenExchBig-1")));
System.out.println("Stock is closed");)
I expected that if one of the 2 elements would appear, the Eclipse would
recognize it. Well - The second element out of the 2 appeared - and for some reason I've got an exception error. The if statement gave attention only to the first condition in the if, and ignored the second.
org.openqa.selenium.NoSuchElementException: no such element:
locate element: {"method":"css
selector","selector":".inlineblock.redClockBigIcon.middle.isOpenExchBig-2"}Unable to
How can I make the || to work in this 'if' statement?
Thanks
Screenshots of the elements

In your above logic, you have Status which is an already existing WebElement that you're comparing against another Webelement that you're looking up. I don't think this is what your intention was so I'm going to make some assumptions in a solution.
First: Find all of the elements that might exist with your desired selector (Note I'm using findElements instead of findElement)
List<WebElement> clockIconThingies = driver.findElements(By.cssSelector(".inlineblock.redClockBigIcon.middle.isOpenExchBig-2, .inlineblock.redClockBigIcon.middle.isOpenExchBig-1"));
Second: Check if that found anything
if(clockIconThingies.size() > 0)
{
System.out.println("Stock is closed");
}
Alternatively for your css selector, from the image it looks like you might not need to do an or at all and just look for the class redClockBigIcon like this:
List<WebElement> clockIconThingies = driver.findElements(By.cssSelector(".redClockBigIcon"));

You can try using try catch block:
boolean isFirstElemPresent = true;
try{
driver.findElement(By.cssSelector(".inlineblock.redClockBigIcon.middle.isOpenExchBig-1"));
}catch (NoSuchElementException e){
isFirstElemPresent = false;
}
if(isFirstElemPresent == false)
driver.findElement(By.cssSelector(".inlineblock.redClockBigIcon.middle.isOpenExchBig-2"));
OrTo avoid try catch block, use below code snap:
List<WebElement> elements = driver.findElements(By.className("redClockBigIcon"));
if (elements.size() == 0) {
System.out.println("Element is not present");
} else {
System.out.println("Element is present");
}

Related

While select with if statement syntax - what is the purpose of the if statement?

I have come across a strange syntax that I have never seen in x++ before, but it compiles and works (as far as I can tell). I was curious if anybody has seen or used this before and could explain: what is the purpose of the if statement within the context of a while select?
InventBatch inventBatch;
InventTrans inventTrans;
InventTransOrigin inventTransOrigin;
InventDim inventDim;
ttsBegin;
while select Qty, DatePhysical from inventTrans
where inventTrans.StatusReceipt == StatusReceipt::Arrived
join inventTransOrigin
where inventTransOrigin.RecId == inventTrans.InventTransOrigin
&& inventTransOrigin.InventTransId == "SomeIdFromSomewhere"
join inventDim
where inventDim.inventDimId == inventTrans.inventDimId
&& inventDim.inventBatchId
if (inventTrans)
{
inventBatch = InventBatch::find(inventDim.inventBatchId, inventTrans.ItemId, true);
inventBatch.Field1 = inventTrans.Qty;
inventBatch.Field2 = inventTrans.DatePhysical;
inventBatch.update();
}
ttsCommit;
When you do a while select, generally you put {} to wrap your code, but you can also do the same thing as if statements, if you omit the {} and the immediately proceeding line gets executed for each loop.
if (true)
info("Hello World");
if (true)
{
info("Hello World");
}
while select SalesTable
info(SalesTable.SalesId);
while select SalesTable
{
info(SalesTable.SalesId);
}
Regarding the code you have typed above, it's idiotic. In AX, in older versions of the code if (common) would often only evaluate common.RecId != 0, but in later ones, I believe it will evaluate true if the buffer is returned with some data. In a while select however, it will always return true as the select is only returning records when it's true.
You could/should just delete literally only the if (inventTrans) line and leave the brackets and it will be readable/normal code.

Generate Absolute xpath of given webElement in RSelenium [R]

I'm trying to replicate what was done in this answer for java selenium in RSelenium: https://stackoverflow.com/a/27611777/7837376
I'd love to be able to do something like this:
#replicating simple RSelenium process getting all //a elements
library(RSelenium)
#start remDr etc. etc.
all_a <- remDr$findElements(using='xpath','//a')
selected_a <- all_a[[10]]
Ideally then I could generate the xpath of the selected_a element using the made up function below:
#desired function
getElementXPATH(selected_a)
I understand that quite a few different XPATH's could be specified for the same element, I'm just looking for a unique xpath identifier for the element, so any unique xpath to the element will suffice!
Thanks!
Personally, I am not a big fan absolute xpath. However, you can get the absolute xpath using javascript rather having the function in your language, which will ran faster and it's easy to port.
Here is the javascript.
// this function will return the absolute xpath of any given element
jsFunction = """window.getAbsoluteXpath =function(el){
// initialize the variables
aPath ="";
// iterate until the tag name is 'HTML'
while (el.tagName!='HTML'){
// get parent node
pEle=el.parentNode;
// check if there are more than 1 nodes with the same tagname under the parent
if(pEle.querySelectorAll(el.tagName).length>1){
//now findout the index of the current child
cIndex = 0;
pEle.querySelectorAll(el.tagName).forEach(function(cEle){
cIndex= cIndex+1;
// check if iterating ChildNode is equal to current ChildNode
if(cEle === el){
// set the aPath using index
aPath = el.tagName + "[" + cIndex + "]" + "/" +aPath;
}
})
}else{
// simply add the tagName when there is only one child with the tag name
aPath = el.tagName + "/" +aPath;
}
// set parent node as current element
el=el.parentNode;
}
// append HTML to the absolute xpath generated
return "//HTML/"+aPath.substring(0,aPath.length-1);
};"""
Now you can call this method in your javascript and pass element that you are interested in getting the absolute xpath.
Let's try to get the absolute xpath of in stackoverflow.
Note: Did not tested the below code logic due to lack of environment on my machine.
# run the javascript in browser so that you can call the function anytime in your script
remDr %>% executeScript(jsFunction, args = list())
# get stackoverflow `Achievements` link element
webElem <- remDr %>% findElement("css", "a.-link.js-achievements-button")
# # get the absolute xpath of Stackoverflow `Achievements`
remDr %>% executeScript("return getAbsoluteXpath(arguments[0])", args = list(webElem))
Screenshot: Ran the javascript in chrome browser console for evidence
Please try the below logic
function absolutePath(element) {
if (element.tagName.toLowerCase() == 'html')
return '/html[1]';
if (element === document.body)
return '/html[1]/body[1]';
var ix = 0;
var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++) {
var sibling = siblings[i];
if (sibling === element)
return absolutePath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + (ix + 1) + ']';
if (sibling.nodeType === 1 && sibling.tagName.toLowerCase() === element.tagName.toLowerCase())
ix++;
}}
I did try the solution provided by supputuri, but it doesnt work on all cases.
Example: Try the function provided by #suppututri on https://www.amazon.in/ , and try to find the absolute xpath for
var element=document.querySelector('#nav-xshop > a:nth-child(2)');
getAbsoluteXpath(element);
The incorrect xpath shown in the console would be: "//HTML/BODY/DIV[1]/HEADER/DIV[1]/DIV[68]/DIV[9]/DIV[1]/DIV/A[1]"

Best way to trigger a script for any change in one of several properties

When you bind a property it will be reevaluated if one of the proprieties to which is bounded is changed.
Example:
property bool test: prCond1 || prCond2 || ... || prCondN
When a condition is changed test is reevaluated.
Now... I want something similar but for triggering a javascript function:
when one of several conditions prCond1 || prCond2 || ... || prCondN is changed I want a function to be called.
If there was only one condition I could write:
onPrCond1Changed: {
functionCall()
}
But when you take into account more than one condition what is the best way to do it? Is there a standard way?
Basically I need something like this:
functionCall() if one of these changes: prCond1 || prCond2 || ... || prCondN
Where prCond's may be of different types.
A possible solution would be to group the variables into a variant list and look for changes on the list.
property var myObject = {'prop': 'value'}
property variant conditions = [prCond1, prCond2, myObj]
onConditionsChanged: {
console.log("one of the conditions have changed");
}
Note that changes in the properties of myObj will not trigger the changeEvent, unless the object itself is changed (e.g. myObj = new Object({'prop': 'newValue'}) )

How to assign dataGrid to other dataGrid in Flex. a = b doesn't work

in Flex I have something like that:
var dg:DataGrid = new DataGrid();
if (something) dg = dg1 else if (something_2) dg = dg2;
dg.dataProvider.getItemAt(3).id;
and dg is ALWAYS pointing at DataGrid (even if dg1 has name DataGrid_test and dg2 = DataGrid_test2) and finally action is made on my first DataGrid (DataGrid_test).
Why?
How can I pass dg1 or dg2 to dg?
Here is pasted almost full code of this part of application. I edited it to make that more clear.
var dg:DataGrid = null;
if ( currentState == "state1" ) { //if this condition is true then app. go into if and
dg = dataGrid_first; // make dg = DataGrid (1)
test.text = "inco"; // shows "inco" in "test" label
} else if ( currentState == "state2" ) { // if this is true then app. go..
dg = dataGrid_second; //here and set dg as DataGrid (exactly!) (2)
test.text = "outgo"; // and change test label into blank text (earlier text disapears)
}
search(dg);
It is modified with advice of '#splash'
Still not working.
EDIT:
I made this sceond edit to answer for all You who are helping me with that :) I think that it will be the best way. In codeblock above I added comments. (please read now comments and after that come back here :) )
Now I will explain exactly what happens.
I debug it many times and here are results:
dg is pointing at DataGrid (as component in flex, not as my dataGrid_first), I needed to extend DataGrid so now it is ColorColumn component (I don't know if I called it properly), not DataGrid. And dg is pointing at ColorColumn not at dataGrid_first or dataGrid_second. I even tried today the same thing what suggest #splash:
if ( currentState == "state1" ) {
test.text = "inco";
search(dataGrid_first);
} else if ( currentState == "state2" ) {
test.text = "outgo";
search(dataGrid_second);
}
and search still points at ColorColumn :/ My problem is really easy- I just want to pass to search different dataGrid on each state. If You have other ideas how I can do that in right way then I will pleased to hear about it. :)
But still I don't understand why it doesn't work. My search function uses algorhitm Boyer-Moor for searching through dataGrid.dataProvider for some text. If it find something then it is pushed into new array and after passing whole dataProvider I colorize rows with searched word.
If dg is never pointing to dg1 and dg2 then your (something) expressions may be evaluate to false. Check the value of your if-conditions - this should be easy to debug.
This should work:
var dg:DataGrid = null;
if (something)
dg = dg1;
else if (something_2)
dg = dg2;
if (dg)
{
// do something with dg
}
[Update]
I still can't see why your code isn't working, but you could simplify it like this:
if ( currentState == "state1" ) {
test.text = "inco";
search(dataGrid_first);
} else if ( currentState == "state2" ) {
test.text = "outgo";
search(dataGrid_second);
}
I'd propose to write this - since I guess either dg1 or dg2 should be assigned:
if (something) {
dg = dg1;
} else {
dg = dg2;
}
There may be cases, where if () {} else () {} neither executes the first or the second conditional block.
Finally a small hint, which structurally eliminates unwanted assignments in if conditions: Always write the literal left of the comparison operation: if ( "state1" == currentState ). If you accidentally typed = instead of ==, the flex compiler emits an error. The other notation silently assigns a value.
Additionally: Did you single-stepped through your code and watched the variables dg1, dg2 and dg? If not, set a breakpoint a few line before the if-statement and run the code step by step from there on. What do you see?
Here's a another tip: Use assertions to check for inconistencies:
package my.company.utilities {
public function assert(expression:Boolean):void {
// probably conditionally compile this statement
if (!expression) {
throw new Error("Assertion failed!");
}
} // assert
}
Use it e.g. at the beginning of a method like this:
public function doTransaction( fromAccount:int, toAccount:int ) {
assert( 0 < fromAccount );
assert( 0 < toAccount );
}
A typically good use of assert is to check variables regarding their range. As of the above example, fromAccount and toAccount should always be positive. Due to a bug, bad values might get passed to doTransaction(). In this case, the assertion fires an error.

Filehelpers ExcelStorage.ExtractRecords fails when first cell is empty

When the first cell of an excel sheet to import using ExcelStorage.ExtractRecords is empty, the process fail. Ie. If the data starts at col 1, row 2, if the cell (2,1) has an empty value, the method fails.
Does anybody know how to work-around this? I've tried adding a FieldNullValue attribute to the mapping class with no luck.
Here is a sample project that show the code with problems
Hope somebody can help me or point in some direction.
Thank you!
It looks like you have stumbled upon an issue in FileHelpers.
What is happening is that the ExcelStorage.ExtractRecords method uses an empty cell check to see if it has reached the end of the sheet. This can be seen in the ExcelStorage.cs source code:
while (CellAsString(cRow, mStartColumn) != String.Empty)
{
try
{
recordNumber++;
Notify(mNotifyHandler, mProgressMode, recordNumber, -1);
colValues = RowValues(cRow, mStartColumn, RecordFieldCount);
object record = ValuesToRecord(colValues);
res.Add(record);
}
catch (Exception ex)
{
// Code removed for this example
}
}
So if the start column of any row is empty then it assumes that the file is done.
Some options to get around this:
Don't put any empty cells in the first column position.
Don't use excel as your file format -- convert to CSV first.
See if you can get a patch from the developer or patch the source yourself.
The first two are workarounds (and not really good ones). The third option might be the best but what is the end of file condition? Probably an entire row that is empty would be a good enough check (but even that might not work in all cases all of the time).
Thanks to the help of Tuzo, I could figure out a way of working this around.
I added a method to ExcelStorage class to change the while end condition. Instead of looking at the first cell for empty value, I look at all cells in the current row to be empty. If that's the case, return false to the while. This is the change to the while part of ExtractRecords:
while (!IsEof(cRow, mStartColumn, RecordFieldCount))
instead of
while (CellAsString(cRow, mStartColumn) != String.Empty)
IsEof is a method to check the whole row to be empty:
private bool IsEof(int row, int startCol, int numberOfCols)
{
bool isEmpty = true;
string cellValue = string.Empty;
for (int i = startCol; i <= numberOfCols; i++)
{
cellValue = CellAsString(row, i);
if (cellValue != string.Empty)
{
isEmpty = false;
break;
}
}
return isEmpty;
}
Of course if the user leaves an empty row between two data rows the rows after that one will not be processed, but I think is a good thing to keep working on this.
Thanks
I needed to be able to skip blank lines, so I've added the following code to the FileHelpers library. I've taken Sebastian's IsEof code and renamed the method to IsRowEmpty and changed the loop in ExtractRecords from ...
while (CellAsString(cRow, mStartColumn) != String.Empty)
to ...
while (!IsRowEmpty(cRow, mStartColumn, RecordFieldCount) || !IsRowEmpty(cRow+1, mStartColumn, RecordFieldCount))
I then changed this ...
colValues = RowValues(cRow, mStartColumn, RecordFieldCount);
object record = ValuesToRecord(colValues);
res.Add(record);
to this ...
bool addRow = true;
if (Attribute.GetCustomAttribute(RecordType, typeof(IgnoreEmptyLinesAttribute)) != null && IsRowEmpty(cRow, mStartColumn, RecordFieldCount))
{
addRow = false;
}
if (addRow)
{
colValues = RowValues(cRow, mStartColumn, RecordFieldCount);
object record = ValuesToRecord(colValues);
res.Add(record);
}
What this gives me is the ability to skip single empty rows. The file will be read until two successive empty rows are found

Resources