Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to listen to an event in the phantom context from page context?

For example: I open a page with PhantomJS, evaluate an asynchronous script (e.g. ajax). When it succeeds, I want to let the phantom context (outside of page.evaluate()) know that the asynchronous process is finished.

I don't want to use setTimeout and setInteval to wait and check continously in the phantom context that the process is finished.

like image 921
Soda Avatar asked Mar 07 '15 15:03

Soda


1 Answers

That is exactly what the onCallback and window.callPhantom() pair is for.

So, if you have an asynchronous call in the page context like an AJAX request, you can do this:

page.onCallback = function(data){
    console.log("finished: " + data.text);
    phantom.exit();
};
page.evaluate(function(){
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "/");
    xhr.onreadystatechange = function () {
        var DONE = this.DONE || 4;
        if (this.readyState === DONE){
            window.callPhantom({text: this.responseText});
        }
    };
    xhr.send();
});

The other way to use this is to add the call to your production JavaScript to make testing easier. If you're writing a web application it is sometimes complicated to find a selector which denotes when a page is fully loaded. To make testing such an application easier, you can have something like this in the page JavaScript:

finishOffPage(function callback(){
    if (typeof window.callPhantom === "function") {
        window.callPhantom({type: "loadFinished"});
    }
});

Then you can write tests like this:

page.onCallback = function(data){
    if (data.type === "loadFinished") {
        // do some testing
    }
};
page.open(url);

This is an example where such a thing can be added dynamically: wait for angular app to be fully rendered from phantom script

like image 184
Artjom B. Avatar answered Sep 28 '22 07:09

Artjom B.