0

I would like to fiddle a bit with PhantomJS and in particular with the waitFor script that is bundled with its examples. The purpose of my test is to check whether the English and the French version of the website lipsum.com are available. Here is my script :

var page = require('webpage').create(),
    server = 'http://www.lipsum.com',
    languages = ['en', 'fr'];

page.open(server, 'get', '', function (status) {
    if (status !== 'success') {
        console.log('Unable to reach the URL!');
    } else {
        check(languages.shift());
    }
});

function check(currentLanguage) {

    console.log('Checking '+currentLanguage);

    waitFor(function() {
        var classes = page.evaluate(function() {
            // Checks if the current language is selected
            return document.getElementsByClassName('zz')[0].className; 
        });
        console.log("Classes for the selected element : " + classes);
        return classes.indexOf(currentLanguage) === 0;
    }, function() {
        console.log(currentLanguage+' has been looked up.');
        currentLanguage = languages.shift();
        page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
            page.evaluate(function (language) {
                // We click on the link related to the next language of the stack
                $('.'+language).trigger('click'); 
            }, currentLanguage);
        });
        check(currentLanguage);
    });
}

What I would want is that the English, then the French versions of the page are displayed. Instead I get the following log :

Checking en
Classes for the selected element : en zz
'waitFor()' finished in 500ms.
en has been looked up.
Checking fr
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
Classes for the selected element : en zz
'waitFor()' timeout

It looks like the click on the link is not triggered, but I can't figure why.

Bruno Pérel
  • 575
  • 6
  • 21

1 Answers1

0

The problem seems to be that $.click doesn't work. You should use a solution from this question.

The other thing is that you split your control flow. page.includeJs and check are asynchronous functions. They have to be nested and should not come one after another, because you only invite mayhem, if you do this. Since you don't need jQuery anymore, this is only advice for the future.

The other thing that you have to keep in mind is the timeout. The page is relatively slow, so a timeout of 3 seconds is a little slow. You should either increase the timeout of waitFor to something like 10 seconds or even better, register an event handler for when the next page is loaded. In the following code I've done both. I've also added a proper halt criteria.

waitFor(function() {
    var classes = page.evaluate(function() {
        // Checks if the current language is selected
        return document.getElementsByClassName('zz')[0].className;
    });
    console.log("Classes for the selected element : " + classes);
    return classes.indexOf(currentLanguage) === 0;
}, function() {
    console.log(currentLanguage+' has been looked up.');
    if (languages.length === 0) {
        console.log("Done");
        phantom.exit();
    }
    currentLanguage = languages.shift();
    //page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
        page.onLoadFinished = function(){
            check(currentLanguage);
        };
        page.evaluate(function (language) {
            // We click on the link related to the next language of the stack
            var ev = document.createEvent("MouseEvent");
            ev.initMouseEvent(
                "click", true, true, window, null,
                0, 0, 0, 0, false, false, false, false, 0, null
            );
            document.querySelector('.'+language).dispatchEvent(ev);
        }, currentLanguage);
    //});
}, 10000);
Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Thanks a lot ! I had little doubt about the fact that there was some async issue, you made me look at the right place. I also increased the timeout like suggested. There's just a tiny mistake/typo in your code : `check(currentLanguage)` should be in the onLoadFinished callback. – Bruno Pérel Sep 16 '14 at 19:36