Reputation: 959
I am trying to capture the browser DOM of an application from my Java code. The target is to render the web application on a web browser. User will populate the fields or do any action to navigate through the application. There will be a stand-alone java code which will capture the browser DOM for each and every page the web application would navigate to. I am using HtmlUnit to capture the DOM and Selenium WebDriver to render the web application, since HtmlUnit is headless.
The problem is I am not able to track whether I am on a new page of the application. The statement, HtmlPage page = webClient.getCurrentWindow().getEnclosedPage(), does not work, as the HtmlPage object does not change.
I have tried implementing the DomChangeListener, but it seems that there is no DomChangeEvent, if the data population is done manually, i.e. outside of the java code. If I populate the contents and submit the page from the code, then the DomChangeListener works. But that's not what I want.
Any suggestion, how to achieve this? Is there any other api useful for this?
Regards
Upvotes: 1
Views: 4539
Reputation: 29739
That's not an easy task with Selenium/Webdriver. I did something very similar and got it to work (i will release it soon). The basics are JavaScript event handlers and polling the data from Java.
The JavaScript:
var events = [];
var eventQueue = [];
var eventHistory = {};
var processing = false;
var nativeEvents = {
'submit': 'HTMLEvents',
'keypress': 'KeyEvents',
'click': 'MouseEvents',
'dblclick': 'MouseEvents',
'dragstart': 'MouseEvents',
'dragend': 'MouseEvents',
}
for(var eventName in nativeEvents) {
document.addEventListener(eventName, processEvent, true);
};
processEvent = function(event) {
if(event.triggeredManually) {
return true;
}
if(event.type in nativeEvents) {
storeEvent(event);
event.stopPropagation();
event.preventDefault();
return false;
}
}
storeEvent = function(event) {
ev = convertEvent(event);
if(processing) {
eventQueue.push(ev);
} else {
events.push(ev);
}
}
convertEvent = function(event) {
var ev = {};
var id = new Date().getTime() + ":" + Math.random();
ev['id'] = id;
ev['type'] = event.type;
ev['target'] = event.target;
ev['button'] = event.button;
ev['charCode'] = event.charCode;
ev['keyCode'] = event.keyCode;
ev['altKey'] = event.altKey;
ev['ctrlKey'] = event.ctrlKey;
ev['shiftKey'] = event.shiftKey;
ev['clientX'] = event.clientX;
ev['clientY'] = event.clientY;
ev['offsetX'] = event.offsetX;
ev['offsetY'] = event.offsetY;
eventHistory[id] = ev;
return ev;
}
These functions are for detecting and storing user events. The following is needed to retrieve the events in Java and to triffer the events afterwards. This is needed for page unloads, because the unload
event is not safely working in every browser.
getEvents = function() {
processing = true;
events = events.concat(eventQueue);
eventQueue = [];
setTimeout(resetEvents, 10);
return events;
};
resetEvents = function() {
events = [];
processing = false;
};
triggerEvents = function(idsAsJson) {
// trigger pending events
var ids = JSON.parse(idsAsJson);
for (var i = 0; i < ids.length; i++) {
var event = eventHistory[ids[i]];
if(event) {
var evObj = null;
var evObjType = null;
var bubbling = true;
var cancelable = false;
if(event['type'] in nativeEvents) {
evObjType = nativeEvents[event['type']];
evObj = document.createEvent(evObjType);
// more info: http://www.howtocreate.co.uk/tutorials/javascript/domevents
if(evObjType == 'KeyEvents') {
evObj.initKeyEvent(event['type'], bubbling, cancelable, window, event['ctrlKey'], event['altKey'], event['shiftKey'], false, event['keyCode'], event['charCode']);
} else if(evObjType == 'MouseEvents') {
evObj.initMouseEvent(event['type'], bubbling, cancelable, window, 1, event['offsetX'], event['offsetY'], event['clientX'], event['clientY'], event['ctrlKey'], event['altKey'], event['shiftKey'], false, event['button'], null);
} else {
evObj.initEvent(event['type'], bubbling, cancelable);
}
evObj.triggeredManually = true;
event['target'].dispatchEvent(evObj);
}
}
}
};
Then you need Java code that loops over the getEvents()
function and you can store anything you need. After that you need to execute the triggerEvents()
function in order to process the user interactions.
Upvotes: 2
Reputation: 2135
Unfortunately, I am not familiar with HtmlUnit or the Selenium WebDriver, so this answer may not be useful to you. However, in general, this sort of thing is relatively easy to accomplish.
On the browser side, implement event handlers any time there is user input that you need to capture. These event handlers would make Ajax calls to your web server, with whatever data you need to capture on the server. If the data is at all complex, I suggest you use Json to pass the data as an object. There are some standard Javascript stringifiers (see https://github.com/douglascrockford/JSON-js) On the Java side, there are tools to translate json strings to java objects (see http://code.google.com/p/google-gson/). You can also go here for more alternatives: http://www.json.org/
On the server side, your java code simply resides in jsps or servlets. It processes the data. If the data is transient, you can leave it in memory with a session (javax.servlet.http.HttpSession). If it is persistent, you can write it to a database or data file.
In general, I often find it useful to implement this sort of thiing myself, rather than using a software package. My solution is usually much smaller and easier to debug and maintain. Hope this helps.
Upvotes: 0