Developing a record and playback tool using selenium webdriver - java

I am trying to develop a record and playback tool using selenium webdriver like the way Selenium IDE does. I started withCchrome browser, tried different approaches. Few of them are here:
Tried creating a JavaScript with event listeners and tried executing it using JavascriptExecutor. In the JS script I have implicit wait to return some value. Sample code:
var flag = 0;
var elementId;
window.addEventListener("click", function (e) {
elementTagName=e.target.id;
alert(elementTagName);
flag++;
});
var timer = setInterval(function () {
myTimer();
}, 1000);
function myTimer() {
if(flag == 0){
document.getElementById("demo").innerHTML=flag;
} else {
clearInterval(timer);
return elementId; //Returning the element ID which was clicked
}
}
But now the problem is, webdriver code written in java(shown below) is not waiting for the return. Same code works fine when I run it individually.
Object response = ((JavascriptExecutor) driver).executeScript(script);
if (null != response) {
System.out.println((String) response);
}
Any other way I can do it?

Instead of returning the JS value, you can store it in a JS variable, by changing this line:
return elementId;
to this:
retVal = elementId;
Then, whenever you would have accessed response in Java, execute JS to access the JS var on the page instead:
// execute JS functions from your question above
((JavascriptExecutor) driver).executeScript(script);
// wait however long needed for those functions to complete
Thread.sleep(1000);
// get result from page
String response = (String)((JavascriptExecutor) driver).executeScript("return retVal");

Related

ChromeDevTools in selenium, waiting for response bodies

I need to work on ajax response, that is one of responses received upon visiting a page. I use selenium dev tools and java. I create a listener, that intercepts a specific request and then I want to work on response it brings. However I need to setup static wait, or else selenium don't have time to save RequestId. I read Chrome Dev Tools documentation, but it's a new thing for me. I wonder if there is a method that would allow me to wait for this call to be completed, other than the static wait.
Here is my code:
#Test(groups = "test")
public void x() throws InterruptedException, JsonProcessingException {
User user = User.builder();
ManageAccountStep manageAccountStep = new ManageAccountStep(getDriver());
DashboardPO dashboardPO = new DashboardPO(getDriver());
manageAccountStep.login(user);
DevTools devTools = ((HasDevTools) getDriver()).maybeGetDevTools().orElseThrow();
devTools.createSessionIfThereIsNotOne();
devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
// end of boilerplate
final RequestId[] id = new RequestId[1];
devTools.addListener(Network.responseReceived(), response -> {
log.info(response.getResponse().getUrl());
if (response.getResponse().getUrl().contains(DESIRED_URL)){
id[0] = response.getRequestId();
}
});
dashboardPO
.clickLink(); // here is when my DESIRED_URL happens
Utils.sleep(5000); // Something like Thread.sleep(5000)
String responseBody = devTools.send(Network.getResponseBody(id[0])).getBody();
// some operations on responseBody
devTools.clearListeners();
devTools.disconnectSession();
}
If I don't use 5 seconds wait id variable gets never assigned and I null pointer exception requestId is required. During these 5 seconds log.info prints all api calls that are happening and it almost always finds my id. I would like to refrain from static wait though. I am thinking about something similiar to maybe jQuery.active()==0, but my page doesn't use jQuery.
You may try custom function Explicit Wait. Something like this:
public String getResponseBody(WebDriver driver, DevTools devTools) {
return new WebDriverWait(driver,5)
.ignoring(NullPointerException.class)
.until(driver ->
devTools.send(Network.getResponseBody(id[0])).getBody());
}
So, it won't wait for all 5 seconds. The moment it got the data, it would come of out of the until method. Also add whichever Exception that was coming up here.
Has put these lines of code as separate method because, devTools object is locally defined. In order to use them inside this anonymous inner function, it has to be final or effectively final.
I seem to run into this issue when running tests in parallel (and headless) and trying to capture the requests and responses, I get:
{"No data found for resource with given identifier"},"sessionId" ...
However, now .until seems to only take ExpectedCondition
So a similar solution (to the accepted answer), but without using "WebDriverWait.until" that I use is:
public static String getResponseBody(DevTools devTools, RequestId id) {
String requestPostData = "";
LocalDateTime then = LocalDateTime.now();
String err = "";
Integer it = 0;
while (true) {
err = "";
try{requestPostData = devTools.send(Network.getResponseBody(id)).getBody();} catch( Exception e){err = e.getMessage();};
if (requestPostData != null && !requestPostData.equals("")) {break;}
if (err.equals("")) {break;} // if we don't have an error message, its quite possible the responseBody really is an empty string
long timeTaken = ChronoUnit.SECONDS.between(then, LocalDateTime.now());
if (timeTaken >= 5) {requestPostData = err + ", timeTaken:" + timeTaken; break;}
if(it > 0) {TimeUnit.SECONDS.sleep(it);} // I prefer waiting longer and longer, avoiding stack overflows
it++;
}
return requestPostData;
}
It just loops until it doesn't error, and returns the string back as soon as it can (but I actually set timeTaken >= 60 due to many parallel requests)

How to post and receive data in a loop using AJAX to and from a servlet

I am working on a news summarizer and one of its requirements is to display a list of article titles dynamically on a webpage using AJAX called from a database. I have been able to successfully configure the datastore(google app engine) and use the AJAX call to display article title. However, there is one big issue here. I am only able to call and show a single title. I want to run the AJAX call inside a loop so that I can display 10 news articles stored in datastore from 1 to 10 using the variable i of the loop as the unique reference.
The AJAX CODE :
function change(element) {
var xmlhttp;
var i = 1;
var param = "category=" + element + "&no=" + i; // This i is the key to my operation.
alert(param); //testing purpose
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
//alert('function()');
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var div = document.getElementById('content');
div.innerHTML = '';
for (i = 1; i <=10; i++) {
var a = document.createElement('a');
a.href = "#";
a.onclick = rem.bind(null, i);
a.innerHTML = '<h2 id="theading'+i+'">'
+ xmlhttp.responseText + '</h2>'; //the title will go here.
div.appendChild(a);
div.appendChild(document.createElement('br'));
}
}
}
xmlhttp.open("POST", "/display?" + param, true);
xmlhttp.send();
}
I also request to suggest JavaScript code and not jquery, as I am unfamiliar with it. These are my humble beginnings.
UPDATE
MY SERVLET CODE:
public class ArticleHandler extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
String category=req.getParameter("category");
String number=req.getParameter("no");
int i = Integer.parseInt(number);
List<EntityArticles> articles = RegisterClass.ofy().load().type(EntityArticles.class).filter("category ",category).list();
out.write(articles); // Is this the correct way to send this list articles ?
}
}
Is this the correct way to send the list ?
10 articles in responseText, you can render html in server code to responseText(loop in server code). And then in ajax sucess you call
var div = document.getElementById('content');
div.innerHTML = xmlhttp.responseText;
I have created a fiddel for you to understand check it. Ajax Example in fiddle
Are you doing post request or get request? I'm asking this because I saw method as "POST" and parameter passed as "GET" by putting it in url. Please correct that part too in your code.
loadXMLDoc=function()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/ahmadfaizalbh/LaH8F/show/",true);
xmlhttp.send();
}
The best choice is to call the ajax one time and get 10 items.
But, if you have no alternative, you can modify the function a little:
function change(element, i){
var xmlhttp;
//var i=1;
var param = "category=" + element + "&no=" + i;
...
}
Call the function this way (10 times as you need):
for(i=1;int <= 10; i++){
change(element, i);
}
UPDATE
To make one time the ajax call, you can do:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
//append html node
//the object is xmlhttp.responseText. The loop will depend if this is json, html objects, string, etc
}
xmlhttp.open("POST", "/display?" + param, true);
xmlhttp.send();
To obtain 10 results you need (necessarily) to modify the server side script or servlet. If you cannot have access to modify the servlet, is impossible to get 10 items in a single ajax call.

How to let XMLHttpRequest not cach in IE

if(xmlhttp) {
xmlhttp.open("GET","DokterWeek_KlantoverzichtServletAjax?" + $(this).prop("href").split("?")[1],true);//gettime will be the servlet name
xmlhttp.onreadystatechange = handleServerResponse;
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xmlhttp.send(null);
}
});
});
function getXMLObject() //XML OBJECT
{
var xmlHttp = false;
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP") // For Old Microsoft Browsers
}
catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP") // For Microsoft IE 6.0+
}
catch (e2) {
xmlHttp = false // No Browser accepts the XMLHTTP Object then false
}
}
if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
xmlHttp = new XMLHttpRequest(); //For Mozilla, Opera,chrome Browsers
}
return xmlHttp; // Mandatory Statement returning the ajax object created
}
var xmlhttp = new getXMLObject(); //xmlhttp holds the ajax object
function handleServerResponse() {
document.getElementById("pop1").innerHTML = xmlhttp.responseText; //Update the HTML Form element
}
Hello,
I have the following problem (the code works), the xmlhttpRequest(ajax-call) refreches when I use firefox or Chrome (so it works nice). But IE 9.0+ caches the XMLHttprequest, so it never refreches. I read alot about this problem on the internet,but i really cannot find any solution to this problem.
Can anybody tell me the possibilities to fix this?
I think it is fixable with using the jquery ajax, but I don't have the brains to tune this whole script into jquery. Some say you can set the live-time to 0 but I don't find this. (I communicate my Ajax with a servlet)
Somebody knows an clear,easier solution?
Thank you very much
Once of the accepted practice is to add a random parameter to the url like the timestamp.
Add a parameter like _d to the url with the value new Date().getTime()
Ex:
xmlhttp.open("GET","DokterWeek_KlantoverzichtServletAjax?_d=" + (new Date().getTime()) + '&' + $(this).prop("href").split("?")[1], true);//gettime will be the servlet name

Selenium webdriver IE9 event not firing

I am using nodejs, Soda with selenium
I am hitting problems trying to get the javascript to fire events like on entry of data. Script can't even get through the creation of client flow on IE. Only worried about IE 9+ btw.
Am I missing anything ? This works fine in latest FF. Below posting sample code using for FF
var soda = require('soda');
var assert = require('assert');
var browser = soda.createClient({
url: 'http://192.168.12.1/', // localhost website
port:5555,
host:'192.168.1.3', //grid ip
browser: 'firefox',
browserTimeout:5
});
var testname = 'Nits' + parseInt(Math.random() * 100000000); //create unique name for new person.
console.log('randome name: ' + testname);
browser
.chain
.session()
.setSpeed(speed)
.setTimeout(20000)
.open('/')
.and(login('dev#dev.com', 'x1212GQtpS'))
.and(killClient(killAtEnd))
.end(function(err){
console.log('done');
if(err){
console.log(err);
}else{
console.log("We're Good");
}
if (closeAtEnd){
browser.testComplete(function() {
console.log('killing browser');
});
}
});
function login(user, pass) {
return function(browser) {
browser
.click('css=a#loginButton')
.type('css=input.input-medium.email',user)
.type('css=input.input.pwd',pass)
.clickAndWait('css=a.btn.login')
.assertTextPresent('Clients',function(){ console.log('logged in ok')})
}
}
Can you be more specific about exactly where the script stops, fails, or throws an error? I suspect that IE can't handle the way you put your css selector together (i.e. the classname combinators such as 'input.input.pwd' ). I would recommend trying a different selector or rewrite/simplify your existing selector until you get it working.

AJAX get data from large HTML page as the large HTML page loads

Not entirely sure whether this has a name but basically I have a large HTML page that is generated from results in a db.
So viewing the HTML page (which is a report) in a browser directly does not display all contents immediately but displays what it has and additional HTML is added as the results from the DB are retrieved...
Is there a way I can make an AJAX request to this HTML page and as opposed to waiting until the whole page (report) is ready, I can start processing the response as the HTML report is loaded? Or is there another way of doing it?
Atm I make my AJAX response it just sits there for a minute or two until the HTML page is complete...
If context is of any use: The HTML report is generated by a Java servlet and the page making the AJAX call is a JSP page. Unfortunately I can't very easily break the report up because it is generated by BIRT (Eclipse reporting extension).
Thanks in advance.
Yep all works, if anyone's interested:
client.open("GET", reportUrl, true);
client.onreadystatechange = responseListener;
client.send();
var reportContents = document.getElementById("reportContents");
// Since this could considerably slow browsers for large reports,
// don't edit report contents for every readystate equal to 3.
// Do it every 10.
var batchUpdate = 10;
var responsesSinceUpdate = 0;
// Don't update the whole contents, just add the new stuff
// since the last update.
var currentLengthOfReportHtml = 0;
// Have max recommended length of report before showing warning.
var maxRecommendedReportLength = 500000;
function responseListener()
{
if (this.status == 200)
{
var readyState = this.readyState;
if (readyState == 3 || readyState == 4)
{
var updatePage = false;
if (readyState == 4)
{
updatePage = true;
var loadingDiv = document.getElementById("reportLoading");
loadingDiv.innerHTML = "";
toggleLargeReportWarning(false);
}
else
{
responsesSinceUpdate++;
if (responsesSinceUpdate > batchUpdate)
{
updatePage = true;
responsesSinceUpdate = 0;
}
}
if (updatePage)
{
var reportLength = this.responseText.length;
reportContents.innerHTML += this.responseText.substring(currentLengthOfReportHtml);
currentLengthOfReportHtml = reportLength;
if (reportLength > maxRecommendedReportLength && readyState == 3)
{
toggleLargeReportWarning(true);
}
}
}
}
}

Categories