Wojtek Zeglin
Wojtek Zeglin

Reputation: 116

How to use casperjs to click a random link and navigate to another page?

I am trying to write a script that will do the following:

  1. load a website and take a screenshot
  2. select a random <a> tag from all <a> tags with the same class name
  3. click the link
  4. wait for the new page to load
  5. capture the second screenshot

I'm stuck at selecting a random <a> element and clicking it. Can anyone help me out please? It's my first day with casperjs. Here's what i have so far:

var casper = require('casper').create({
     verbose: true,
     logLevel: 'debug',
     userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22',
     pageSettings: {}
});
casper.options.viewportSize = {width: 1600, height: 950};


casper.start('http://www.myurl.com/', function() {
    this.echo(this.getTitle());
    this.capture('home.png');
});

casper.then(function() {
        this.echo("Second test");
        var random = Math.floor(Math.random() * document.querySelector(".showall").length);
        var clicker = document.querySelector('.showall').eq(random);
        this.mouseEvent('click', clicker);

        this.wait(5000, function() {
            this.capture('second.png');
       });

});

casper.run();

Upvotes: 1

Views: 2364

Answers (2)

Wojtek Zeglin
Wojtek Zeglin

Reputation: 116

I didn't manage to get Artjom's solution working. I think i'm using querySelectorAll in a wrong way (not sure why). I found a workaround.

function getElem() {
    var arr = document.querySelectorAll('a.showall');
    return Array.prototype.map.call(arr, function(elem) {
        return elem.getAttribute('href');
    });
}

casper.then(function() {

        var elem_arr = this.evaluate(getElem);
        //this.echo(elem_arr);
        this.echo(elem_arr.length);

        for (var index = 0; index < elem_arr.length; index++) {
            this.echo(elem_arr[index]);
        }

        var random = Math.floor(Math.random() * elem_arr.length);
        this.echo(random);

        var clicker = elem_arr[random];
        this.echo("Random link: " + clicker);

        casper.open(clicker).then(function() {
            this.echo('Got it! You navigated to a random link subpage.');
        });


});

The trick is to create an array of links from all a.showall elements and then select a random link and open it.

Upvotes: 1

Artjom B.
Artjom B.

Reputation: 61892

You cannot use the DOM functions outside of the page context. You have to use casper.evaluate for that. Keep in mind that evaluate is sandboxed and you can only pass primitive objects to and from page context. DOM elements are not primitive objects, so you cannot pass them outside into the casper context. document means nothing outside of evaluate.

From the docs:

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

You will have to click the link with DOM methods inside of the page context. If the simple clicker.click() doesn't work, you have to use something like this in the page context.

If the link is actually a link which immediately navigates to the page, you can removed this.wait. CasperJS can sense on its own if a page is navigated to, so you can just use another casper.then step.

By the way eq is jQuery syntax, but the result of querySelector is not a jQuery object, it is a DOM element. If you want to select a random element then you have to use querySelectorAll and then select one of them:

var clicker = document.querySelectorAll('.showall')[random];

instead.

Complete solution:

casper.then(function() {
    this.echo("Second test");
    this.evaluate(function() {
        var elements = document.querySelectorAll(".showall");
        var random = Math.floor(Math.random() * elements.length);
        var clicker = elements[random];

        // either this type of click
        clicker.click();
        // or the following
        var ev = document.createEvent("MouseEvent");
        ev.initMouseEvent(
            "click", true, true, window, null, 0, 0, 0, 0, 
            false, false, false, false, 0, null
        );
        clicker.dispatchEvent(ev);
    });
});
casper.then(function() {
    this.capture('second.png');
});

Upvotes: 2

Related Questions