Reputation: 116
I am trying to write a script that will do the following:
<a>
tag from all <a>
tags with the same class nameI'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
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
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