Cookbook

This is a collection of scripts and ideas that aim to solve common situations that are encountered by users. This is by no means an exhaustive list, and we encourage you to contribute your recipes on github.

Creating a web service

Warning

It is worth noting that this is probably not the best of ideas. You should be careful of things like memory leaks, lack of long term stability (due to said leaks), and the overall memory hog that headless JS can be.

With the above caveat in mind, a web service would look something like:

//filename: server.js

//define ip and port to web service
var ip_server = '127.0.0.1:8585';

//includes web server modules
var server = require('webserver').create();

//start web server
var service = server.listen(ip_server, function(request, response) {
  var links = [];
  var casper = require('casper').create();

  function getLinks() {
    var links = document.querySelectorAll('h3.r a');
    return Array.prototype.map.call(links, function(e) {
      return e.getAttribute('href')
    });
  }

  casper.start('http://google.com/', function() {
    // search for 'casperjs' from google form
    this.fill('form[action="/search"]', { q: request.postRaw }, true);
  });

  casper.then(function() {
    // aggregate results for the 'casperjs' search
    links = this.evaluate(getLinks);
  });

  casper.run(function() {
    response.statusCode = 200;

    //sends results as JSON object
    response.write(JSON.stringify(links, null, null));
    response.close();
  });
});
console.log('Server running at http://' + ip_server+'/');

You can start the server by executing:

casperjs server.js

You can then access the results via an HTTP POST request:

curl --data "casperjs" http://127.0.0.1:8585/

The above command would search for “casperjs” on google and return a JSON array of results. This is a trivial example and can be expanded into something more complex.

Script to automatically check a page for 404 and 500 errors

var casper = require("casper").create({
  pageSettings: {
    loadImages: false,
    loadPlugins: false
  }
});
var checked = [];
var currentLink = 0;
var fs = require('fs');
var upTo = ~~casper.cli.get('max-depth') || 100;
var url = casper.cli.get(0);
var baseUrl = url;
var links = [url];
var utils = require('utils');
var f = utils.format;

function absPath(url, base) {
  return new URI(url).resolve(new URI(base)).toString();
}

// Clean links
function cleanLinks(urls, base) {
  return utils.unique(urls).filter(function(url) {
    return url.indexOf(baseUrl) === 0 || !new RegExp('^(#|ftp|javascript|http)').test(url);
  }).map(function(url) {
    return absPath(url, base);
  }).filter(function(url) {
    return checked.indexOf(url) === -1;
  });
}

// Opens the page, perform tests and fetch next links
function crawl(link) {
  this.start().then(function() {
    this.echo(link, 'COMMENT');
      this.open(link);
      checked.push(link);
  });
  this.then(function() {
    if (this.currentHTTPStatus === 404) {
      this.warn(link + ' is missing (HTTP 404)');
    } else if (this.currentHTTPStatus === 500) {
      this.warn(link + ' is broken (HTTP 500)');
    } else {
      this.echo(link + f(' is okay (HTTP %s)', this.currentHTTPStatus));
    }
  });
  this.then(function() {
    var newLinks = searchLinks.call(this);
    links = links.concat(newLinks).filter(function(url) {
      return checked.indexOf(url) === -1;
    });
    this.echo(newLinks.length + " new links found on " + link);
  });
}

// Fetch all <a> elements from the page and return
// the ones which contains a href starting with 'http://'
function searchLinks() {
  return cleanLinks(this.evaluate(function _fetchInternalLinks() {
    return [].map.call(__utils__.findAll('a[href]'), function(node) {
      return node.getAttribute('href');
    });
  }), this.getCurrentUrl());
}

// As long as it has a next link, and is under the maximum limit, will keep running
function check() {
  if (links[currentLink] && currentLink < upTo) {
    crawl.call(this, links[currentLink]);
    currentLink++;
    this.run(check);
  } else {
    this.echo("All done, " + checked.length + " links checked.");
    this.exit();
  }
}

if (!url) {
  casper.warn('No url passed, aborting.').exit();
}


casper.start('https://gist.githubusercontent.com/pieplu/6be55d1d8f27ea9b8dcf4de6b1933547/raw/5e8d996fe1d86edac93825d0050fd359caf74f8e/URI.js', function() {
  var scriptCode = this.getPageContent() + '; return URI;';
  window.URI = new Function(scriptCode)();
  if (typeof window.URI === "function") {
    this.echo('URI.js loaded');
  } else {
    this.warn('Could not setup URI.js').exit();
  }
}).then(function() {
    this.echo("Starting");
}).run(check);

Run it with:

casperjs 404checker.js http://mysite.tld/ [--max-depth=42]

Reference gist.

Test drag&drop

Assuming a page containing a draggable element like that one, we can test drag&drop that way:

casper.test.begin('Test drag&drop', 2, function(test) {
  casper.start('http://localhost:8000/example.html', function() {
    test.assertEval(function() {
      var pos = $('#box').position();
      return (pos.left == 0 && pos.top == 0);
    }, "The box is at the top");
    this.mouse.down(5, 5);
    this.mouse.move(400, 200);
    this.mouse.up(400, 200);
  });
  casper.then(function() {
    test.assertEval(function() {
      var pos = $('#box').position();
      return (pos.left == 395 && pos.top == 195);
    }, "The box has been moved");
  });
  casper.run(function() {
    test.done();
  });
});

Passing parameters into your tests

Let’s say you want to be able to change the Uri your tests visits depending on what you are testing. To do this, you can add custom –parameter=value to your cli.

// casperjs test /foo/bar --url=test.html
var url = 'http://localhost:8000'
var cli = casper.cli

if (cli.has('url')) {
  url = cli.get('url')
}
console.log('\n\tUsing url: ' + url + '\n')

casper.test.begin(...)

You can find the complete documentation for the cli object in http://docs.casperjs.org/en/latest/cli.html