Selenium xpath for complex dynamic span - java

For complex site that has a step hierarchical structure (Region-Site-Zone-ZoneID), I'm trying to build a dynamic xpath for counting ZoneID (1..10)
Structure
<div class="aic-tree-branch-content VAD2" ng-click="events.selectZone(site.id, zone.id)">
<span class="new-sprite unimported selected" ng-class="{'imported': zone.zoneImported, 'unimported': !zone.zoneImported, 'selected': zone.zoneName === selecteds.zone}"></span>
<span class="aic-tree-branch-content-name ng-binding" ng-bind-html="zone.zoneName | highlightFilter: model.searchTerm" ng-click="ui.selectTreeNode(zone.zoneName, 'zone')">VAD2</span>
<span class="aic-tree-branch-content-type zone-type ng-binding" ng-bind="'('+zone.designTypeName+')'">(M)</span>
<span class="aic-tree-branch-content-icon new-sprite zone-state in-creation-small" ng-class="ui.getZoneStatusIcon(zone.zoneState, zone.zonePhase)"></span>
</div>
Code
public static void refreshAndOpenMultiZones(WebDriver driver, String SiteName, String zoneName) throws Exception {
driver.navigate().refresh();
for (int num=1; num<3; num++) {
logger.info("Open existing zone: " + SiteName + num + " in North America");
//Select desired zone in site
By ByZoneName = By.xpath("//span[.='"+zoneName+"']");
logger.info("Select Zone: "+ zoneName);
Utils.wait(5);
driver.findElement(ByZoneName).click();
logger.info("Wait for page to be loaded");
GeneralUtils.waitForElevationPage(driver, timeOutSec);
}
}
The problem: How to combine the code line
By ByZoneName = By.xpath("//span[.='"+zoneName+"']");
for dynamic zoneName id (for the same execution VAD1, VAD2, VAD3.... VAD10)
Actual:
This structure is executed correctly for zoneName=VAD1 and after this in the second curcle is failed with Exception
--- Unable to locate element: {"method":"xpath","selector":"//span[.'VAD']"}
Question:
How to create dynamic structure for xpath with zoneName?
i.e.
By ByZoneName = By.xpath("//span[.='"+zoneName.lastIndexOf(num)+"']");
is failed with Exception
Unable to locate element: {"method":"xpath","selector":"//span[.='-1']"}

Inside your loop you need to either initially establish the web page or alternatively, navigate BACK to that original page at the end of the loop before attempting to locate and click another web element.
It cannot locate the next zone because the page is not the same.

Related

Newline in datatable Gherkin/Cucumber

I have this datatable in my cucumber scenario:
| name | value
| Description | one \n two \n three |
I want the values to appear in the textarea like this:
one
two
three
Because I need to make bullet points out of them.
So my actual question is, is it possible to use newline characters in one line or is there a better way to approach this?
EDIT: to clarify, it's not working with the code written above:
WebDriverException: unknown error: Runtime. evaluate threw exception: SyntaxError: Invalid or unexpected token
EDIT 2: I'm using a bit of unusual code to access the value, seeing as it is a p element and this is normally not possible:
js.executeScript("document.getElementsByTagName('p')[0].innerHTML = ' " + row.get("value") + " ' ");
This has been working for other rows tho, maybe because i'm using \n now?
You can try this way:
WebDriver driver = new ChromeDriver();
driver.get("https://stackoverflow.com/questions/51786797/newline-in-datatable-gherkin-cucumber/51787544#51787544");
Thread.sleep(3000); // pause to wait until page loads
String s = "SOME<br>WORDS";
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.getElementsByTagName('div')[0].innerHTML = '" + s + "';");
Output:
SOME
WORDS
So, main idea is to use <br> tag as new line separator.
In your case it would be like this:
| name | value
| Description | one<br>two<br>three |
and code would be:
// make sure, that row.get("value") returns a string
js.executeScript("document.getElementsByTagName('p')[0].innerHTML = ' " + row.get("value") + " ' ");

Cannot get innerHTML from WebElement which is confirmed to be present

I am trying to get the innerHTML value from this HTML, using Selenium WebDriver.
<div class="map-overlay-network">Newham : NSG Designated Streets (Type 1/2)</div>
This piece of code should confirm that the element is present:
public boolean isMapOverlayNetworkPresent() {
By byExpression = By.className(mapOverlayNetworkClassName);
return isWebElementPresent(byExpression);
}
My elements are defined at the top of the class:
private static final String mapOverlayNetworkClassName = "map-overlay-network";
#FindBy(className=mapOverlayNetworkClassName) private WebElement mapOverlayNetwork;
This is the code for function isMapOverlayNetworkPresent:
public boolean isWebElementPresent(By byExpression) {
WebDriverWait wait = new WebDriverWait(driver, 60);
try {
wait.until(ExpectedConditions.presenceOfElementLocated(byExpression));
return true;
} catch (TimeoutException e) {
System.out.println("Timeout waiting for presence of element " + byExpression);
return false;
}
}
Here is where I try to get the innerHTML:
public String returnDefaultNetwork() {
String defaultNetwork = mapOverlayNetwork.getAttribute("innerHTML");
System.out.println("Default network = " + defaultNetwork);
return defaultNetwork;
}
This is the report from my console:
Is default network shown on map: true
Default network =
If I load the page in Firefox and use Developer Tools, I can see the element using the inspector. If I right click on the element in the Inspector & select Copy InnerHTML, I get this value:
Newham : NSG Designated Streets (Type 1/2)
This is the value I want.
This does not work in any of the browsers I am testing, i.e. Firefox, Chrome or Edge.
Any suggestions?
A previous element on the screen works fine. This is how it looks in HTML:
<div class="map-overlay-customer">Newham</div>
This is how it is defined in my PageObject class:
public static final String mapOverlayCustomerClassName = "map-overlay-customer";
#FindBy(className=mapOverlayCustomerClassName) private WebElement mapOverlayCustomer;
This is me returning the InnerHTML:
public String returnDefaultCustomer() {
return mapOverlayCustomer.getAttribute("innerHTML");
}
This is the response from the console:
Default customer: Newham
Update 21/12/2017
Following a suggestion below, I added a wait for visibility after detecting the presence of my element.
private void waitForVisibility(WebElement element) throws Error {
// time out in seconds
try {
new WebDriverWait(driver, 60).until(ExpectedConditions.visibilityOf(element));
} catch (TimeoutException e) {
System.out.println("Timeout waiting for presence of element " + element);
}
}
public boolean isMapOverlayNetworkVisible() {
waitForVisibility(mapOverlayNetwork);
return mapOverlayNetwork.isDisplayed();
}
In my Test class:
reportAssert("Is default network present on map", alloyLoggedInPage.isMapOverlayNetworkPresent());
reportAssert("Is default network visible on map", alloyLoggedInPage.isMapOverlayNetworkVisible());
System.out.println("Default network: " + alloyLoggedInPage.returnDefaultNetwork());
My result:
Is default network present on map: true
Is default network visible on map: true
Get default network.
Default network = Newham : NSG Designated Streets (Type 1/2)
Default network: Newham : NSG Designated Streets (Type 1/2)
Try to use .getAttribute("value") or .getText() for your web element.
PS: But it's really strange that .getAttribute("innerHTML") does not work.
PSS: Also try to check the value of element in Console of browser by running JavaScript:
document.querySelector(".map-overlay-network").innerHTML;
PSSS: Also, I want to recommend to add one more wait with ExpectedConditions.visibilityOfElementLocated(By.id<locator>‌​) after your wait, because after your wait element just in DOM, but not visible.

Error on jade invalid indentation; expecting 0 spaces

I am working in project which most of the code written by JADE technology.I am new bie to jade.I dont get any clue from the Error stack flow, I posted my jade code and error below ,please share your suggestion's what I am wrote wrong and where do I make a change?
.row
.col-md-12
.panel.panel-primary
.panel-heading
h3 {{cc.header.subject}}
ep-editable-date-time(model='cc.header')
.panel-body
.panel.panel-default(ng-repeat='step in cc.checklist.steps',
data-step='{{step.stepPath[step.stepPath.length - 1].name}}')
.panel-heading
span.pull-right.checklist-controls(ng-if='cc.checkupType !== cc.types.DRIVEBY')
button.btn(ng-class="{'active': !step.skip, 'btn-default': step.skip, 'btn-success':!step.skip}",
ng-click='step.skip=!step.skip; step.skip ? step.noSelfCheckNeeded=true : noop')
span Include
=" "
span.fa(ng-class="{'fa-square-o': step.skip, 'fa-check-square-o': !step.skip}")
=" "
span(ng-if='cc.checkupType === cc.types.SUPERVISOR')
button.btn(ng-class="{'active': !step.noSelfCheckNeeded, 'btn-success': !step.noSelfCheckNeeded, 'btn-default':step.noSelfCheckNeeded}",
ng-click='step.noSelfCheckNeeded=!step.noSelfCheckNeeded',
ng-disabled='step.skip')
span Self Check
=" "
span.fa(ng-class="{'fa-check-square-o':!step.noSelfCheckNeeded, 'fa-square-o': step.noSelfCheckNeeded}")
h5.checklist-header(ng-bind='step.process.name')
h6
span(ng-repeat='s in step.stepPath')
span(ng-bind='s.name')
span(ng-show='!$last')
=" > "
table.table
col
col(style='width: 60px')
thead
tr
th(colspan='2', style='text-align: right') In compliance?
th(style='width: 100px') Not-Applicable
tbody
tr(ng-repeat='b in step.behaviors')
td(ng-bind='b.name')
td
span.bigcheck.compliance-checkbox
label.bigcheck
input.bigcheck(type='checkbox', ng-model='b.compliance', ng-disabled='step.skip')
span.bigcheck-target
//I added these lines which started and ended with ** , It makes me a trouble please guided any one what I have missed .,
**td
span.bigcheck.compliance-checkbox
label.bigcheck
input.bigcheck(type='checkbox', ng-model='b.compliance', ng-disabled='step.skip')
span.bigcheck-target**
.panel-footer
div(ng-if='cc.checkupType === cc.types.SUPERVISOR', style='text-align: center')
span(ng-if='!cc.selfCheckupNeeded()')
h6(ng-if='cc.anyStepsSelected()') Save and Return to Subject Dashboard
h6(ng-if='!cc.anyStepsSelected()') Include at least one Step before saving Checkups
button.btn.btn-success(ng-if='!cc.selfCheckupNeeded()',
ng-disabled='!cc.isCheckupDTValid() || !cc.anyStepsSelected()',
ng-click='cc.saveAndDontSelfCheckup()') Save Supervisor Checkup
span(ng-if='cc.selfCheckupNeeded()')
h6 Save and Start Self Checkup
button.btn.btn-primary.self-checkup-now-btn(ng-disabled='!cc.isCheckupDTValid()',
ng-click='cc.saveAndStartSelfCheckup()')
span.fa.fa-check-square-o
| Self Checkup Now
=" "
button.btn.btn-danger.self-checkup-later-btn(ng-disabled='!cc.isCheckupDTValid()', ng-click='cc.saveAndSelfCheckupLater()')
span.fa.fa-check-square-o
| Self Checkup Later
div(ng-if='cc.checkupType === cc.types.SELF', style='text-align: center')
h6 Save and View Results
button.btn.btn-success.save-self-checkup(ng-disabled='!cc.isCheckupDTValid()',
ng-click='cc.saveAndDontSelfCheckup()')
span.fa.fa-check-square-o
| Save Self Checkup
div(ng-if='cc.checkupType === cc.types.DRIVEBY', style='text-align: center')
h6 Save Checkup
button.btn.btn-success(ng-disabled='!cc.isCheckupDTValid()', ng-click='cc.saveAndDontSelfCheckup()')
span.fa.fa-check-square-o
| Save Checkup
Error stack flow
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is class de.neuland.jade4j.exceptions.JadeLexerException checkup/checklist.jade:42
invalid indentation; expecting 0 spaces
Caused by: de.neuland.jade4j.exceptions.JadeLexerException: invalid indentation; expecting 0 spaces
The edited code above works fine with jade node module.
You should doublecheck such issues just by pasting your template at jade-lang.com
(Your template works fine there also)
As robertklep mentioned, it is likely an issue with your lexer

defining an object property in a compositeData on a custom control

I'm building an application where I have mainDoc which can have one or more related notes Documents. In the mainDoc there is a repeat control that is bound to Payments.getAllItems(WFSMainDoc.getValue("LinkKey")); The java class Payments has methods that manipulate and ArrayList of PaymentItems. The getAllItems method grabs all of the related NotesDocuments and loads them into an ArrayList. If the ArrayList already exists it just returns the previously built ArrayList. The button in the Repeat sets viewScope.vsRIndex = rIndex; and viewScope.vsShowPayment = true; which now displays the panelPaymentDetail and the custom control that has a custom property of type java.lang.Object and load pItem using pItem = Payments.getItem(rIndex); return pItem;
all of the above works and I have a couple sample controls below. I have two issues:
1. The compositeData.pItem is computed over and over again and as far as I can tell keeps returning the original values from the Payments.getAllItems() even though I'm editing them in the payment input 'form' -- the question then is how can I block this repeated calculation?
The save button in the Payment Input custom control does not appear to fire (none of the print statements occur when clicked) I think the reloading of the Object pItem gets in the way.
Test Main Document Control:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument var="WFSMainDoc" formName="frmMainDoc"
computeWithForm="onsave" ignoreRequestParams="false">
<xp:this.documentId><![CDATA[${javascript:var UNID:String = sessionScope.get("ssUNID");
(UNID == null || UNID == "") ? "" : UNID}]]></xp:this.documentId>
<xp:this.action><![CDATA[${javascript:if (sessionScope.containsKey("ssUNID")){
if(sessionScope.get('ssUNID').length){
sessionScope.get('ssAction') == 'edit' ? 'editDocument':'openDocument'
} else {
return 'createDocument'
break;
}
}else{
return "createDocument";
break;
}}]]></xp:this.action>
<xp:this.databaseName><![CDATA[${appProps[sessionScope.ssApplication].appFilePath}]]></xp:this.databaseName>
</xp:dominoDocument>
</xp:this.data>
Main document
<xp:br></xp:br>
<xp:inputText id="inputText1" value="#{WFSMainDoc.LinkKey}"
defaultValue="#{javascript:#Unique}">
</xp:inputText>
<xp:br></xp:br>
Other Fields and controls
<xp:br></xp:br>
<xp:panel id="panelPaymentContainer">
<xp:repeat id="repeatData" rows="10" var="pItem"
indexVar="rIndex">
<xp:this.value><![CDATA[#{javascript:Payments.getAllItems(WFSMainDoc.getValue("LinkKey"));}]]></xp:this.value>
<xp:button id="buttonEditPayment"
rendered="#{javascript:(WFSMainDoc.isEditable())}">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="panelPaymentsContainer">
<xp:this.action><![CDATA[#{javascript:try{
viewScope.vsRIndex = rIndex;
viewScope.vsShowPayment = true;
break;
}catch(e){
WFSUtils.sysOut("Error in calling dialogPayment " + e.tostring)
}}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>
<br />
</xp:repeat>
<xp:panel id="panelPaymentInput">
<xp:this.styleClass><![CDATA[#{javascript:(viewScope.vsShowPayment) ? "" : "display=none";}]]></xp:this.styleClass>
<xc:ccTestPaymentInput rendered="#{javascript:(viewScope.vsShowPayment)}">
<xc:this.pItem><![CDATA[#{javascript:try{
var debug:Boolean = true;
if (debug) WFSUtils.sysOut("Open existing row = " + viewScope.vsRIndex)
rIndex = parseInt(viewScope.vsRIndex.toString());
if (debug) WFSUtils.sysOut("rIndex = " + rIndex);
pItem = Payments.getItem(rIndex);
return pItem;
}catch(e){
WFSUtils.sysOut("Failure in Custom Prop of add item " + e.toString());
return null;
}}]]></xc:this.pItem>
</xc:ccTestPaymentInput>
</xp:panel>
</xp:panel><!-- panelPaymentContainer -->
<xp:br></xp:br>
<xp:br></xp:br>
</xp:view>
payment Input Control
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:br></xp:br>
Actual Pay Date: 
<xp:inputText id="actualPayDate"
value="#{compositeData.pItem.actualPayDate}">
<xp:dateTimeHelper id="dateTimeHelper1"></xp:dateTimeHelper>
<xp:this.converter>
<xp:convertDateTime type="date"></xp:convertDateTime>
</xp:this.converter>
</xp:inputText>
<br /> <br />
<xp:button value="Save" id="button1">
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial" refreshId="panelPayments">
<xp:this.action><![CDATA[#{javascript:try{
var debug:Boolean = true;
if (debug) print("Start Payment save");
var pos:Integer = parseInt(viewScope.vsRIndex.toString());
if (debug) print("Working with pos = " + pos + " Call saveThisItem");
if (Payments.saveThisItem(compositeData.pItem , pos)){
if (debug) print("save Payments Worked ");
}else{
if (debug) print("save Payments FAILED ");
}
}catch(e){
print("payment save Error " + e.tostring);
}finally{
viewScope.vsExpPayDate = "";
viewScope.remove("vsShowPayment");
viewScope.remove("vsRIndex");
viewScope.remove("vsGotItem")
}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
This is all very complicated, and I'm far from understanding what you're trying to achieve here. But at least I found a few oddities in your code:
ad 1: there is a panel with id="panelPaymentContainer" containing a repeat. Inside that repeat is a button doing a partialRefresh on an id="panelPaymentsContainer" >> is this a typo (plural vs. singular forms in "Payment(s))? Should the button be refreshing the panel?
Assuming that this assumption is true: every time you click the button the panel is refreshed together with all its contents, thus also refreshing the repeat's datasource. And so pItem will always be pushed from "outside in" into the content of your repeat. - If the refreshId thing is NOT a typo, then what should it be? I tried hard to read the entire code, but there's a lot of it, so I might have missed something
ad 2: similar thing here: the save button tries to refresh something with an id="panelPayments", but I cannot see anything with this id. So no wonder it doesn't appear to do anything useful.
My recommendation for complicated tasks like these: try to strip everything down to the bare essentials; the more complicated your code is the harder it is to find its mistakes. Start with a panel, a repeat and a few simple controls like a button and a bunch of computed fields to display some test values. Then as soon as this very simple model is working you can start to add to it. - Simplifying also helps others to find mistakes in you concept, btw.

redirect user to login page

I'm running a J2EE application and need to redirect the user to login page if the session is inactive.
I basically want to use the below javascript code to get the session last accessed time and compare with the current time, and if its more than the session timeout I will logout:-
<script>
setInterval(function() {
console.log('MaxInactive Interval == ' + <%=new Date(session.getLastAccessedTime())%> );
}, 10000);
</script>
I get the below error on the console.log line:-
Uncaught SyntaxError: missing ) after argument list
Here is the display from the sources tab:-
console.log('MaxInactive Interval == ' + Sun May 31 20:33:17 EDT 2015 );
You should place the single quote at the end of console.log argument
setInterval(function() {
console.log('MaxInactive Interval == <%=new Date(session.getLastAccessedTime())%>' );
}, 10000);
</script>
And you don't need the + operator, you cannot concatenate javascript string with java expressions.

Categories