问题
I'd like to check with PhantomJS whether my script correctly opens a new window/tab on click. The open is triggerd by a js event listener and opened through window.open(url, "_blank")
.
How can I listen for the new window with PhantomJS?
回答1:
There seem to be three ways to do this:
onPageCreated
CasperJS solves this by using page.onPageCreated. So when window.open
is called in the page, a new page is created and page.onPageCreated
is triggered with the newly created page.
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit();
} else {
page.onPageCreated = function(newPage){
newPage.onLoadFinished = function(){
console.log(newPage.url);
phantom.exit();
};
};
page.evaluate(function(url){
window.open(url+"?something=other", "_blank");
}, address);
}
})
pages
PhantomJS' page
has a pages property which handles of the child pages. So, when you open
a new page/tab, a new webpage
object is created for that page. You need to try to add an onLoadFinished
event listener to the page before it fires (no promises). It can be hard and when the window.open
is called with an unknown delay from the page context.
This can be fixed by using something like waitFor to wait for the new page to appear and attach the event handler before the page is loaded. Here is the complete code with a small adjustment. The retry interval is reduced to 50ms from 250ms.
var page = require('webpage').create();
var address = "http://example.com/";
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function() {
if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
// If not time-out yet and condition not yet fulfilled
condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 50); //< repeat check every 50ms
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit();
} else {
console.log("p:", page.ownsPages, typeof page.pages, page.pages.length, page.pages);
waitFor(function test(){
return page.pages && page.pages[0];
}, function ready(){
page.pages[0].onLoadFinished = function(){
console.log("p:", page.ownsPages, typeof page.pages, page.pages.length, page.pages);
console.log("inner:", page.pages[0].url);
phantom.exit();
};
});
page.evaluate(function(url){
window.open(url+"?something=other", "_blank");
}, address);
}
})
Proxy solution
The window.open
function can be proxied and after the opening the page in the page context, an event handler can be registered in phantom context signaled through window.callPhantom
and caught in onCallback.
page.onInitialized = function(){
page.evaluate(function(){
var _oldOpen = window.open;
window.open = function(url, type){
_oldOpen.call(window, url, type);
window.callPhantom({type: "open"});
};
});
};
page.onCallback = function(data){
// a little delay might be necessary
if (data.type === "open" && page.pages.length > 0) {
var newPage = page.pages[page.pages.length-1];
newPage.onLoadFinished = function(){
console.log(newPage.url);
phantom.exit();
};
}
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit();
} else {
page.evaluate(function(url){
window.open(url+"?something=other", "_blank");
}, address);
}
})
来源:https://stackoverflow.com/questions/27980178/how-to-catch-new-window-opend-by-window-openurl-blank-in-phantomjs