Commit 6034ce18 6034ce18de6206892c671bfb148d662039a42de5 by Nicolas Perriault

local docs - fixes #393

1 parent 354aed31
.PHONY: all default
default: all
all: build open
build:
sphinx-build . _build
open:
open _build/index.html
CasperJS Sphinx Documentation
=============================
Sphinx documentation for [CasperJS](http://casperjs.org/) 1.1-DEV and future
versions. Work in progress.
- credits jeremy (logo)
No preview for this file type
<h3>Donate</h3>
<div class="donate">
<div class="paypal">
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYC4JCGS/3BUKEbRk75JLTu8saEZukn/6Zl5RMoVI55A2wpXdaYcILRy3L7CC4Exu9QaUzHTqQY5livIcptZaOM+aJYYr4ltJbyRW1hvFfrp0ZKMEgUuaU3m9+KQl4kzF9mRUIb5fwTd2j0FfEOllIDYLhEs6sCf39iI8yNeHsuTqjELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIHb+LDTLRE8+AgaD85VPtS5//ZnqYKJMBxlWxI6ob8L8Zk71t9NAwDY3YB3phdkyYSQtax1QxSYz1zFdNlaN5+zlFVg3chctbR6W/kC1sf4hI+AVRm9JlwYKdPOE2FOescC7QuqwAiCZlTfdejznoE0B3aVfq4OMx2k0STtVv3Ld9prW57EtMZ7xDXIW5ss62IWpsBY8eW2VPbX/Xy8TncrpDLHzJ67OKmj/KoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTIwNjI0MTUzOTU1WjAjBgkqhkiG9w0BCQQxFgQUCTlRbQ9Lu+bilBvGXOco0qlRC/8wDQYJKoZIhvcNAQEBBQAEgYBVibaMfUxJXJkA636MBqV4iWXc/F070Tsov5/kALg++/rD5qmH5MV6U8X0H8V1bCFZMBpTtLbCQ9xgeMjaK1gaCrvUw0503tBnvuPDz4bS1dspNHE9boiBJdN5vNZGqxXKij8CgKBeHYmcyCKjywHyUfSDADt1vgb7qQ5bOIvbzA==-----END PKCS7-----">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="Donate" title="Donate">
<img alt="" border="0" src="https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif" width="1" height="1">
</form>
<small>(ghosts have bills, you know)</small>
</div>
<div class="flattr">
<a href="http://flattr.com/thing/586241/CasperJS-a-navigation-scripting-and-testing-utility-for-PhantomJS" class="flattr" target="_blank"><img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0"></a>
</div>
</div>
{%- extends "basic/layout.html" %}
{% block extrahead %}
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic&amp;subset=latin,latin-ext">
<link rel="stylesheet" title="Dark theme" href="{{ pathto('_static/casperjs-dark.css', 1) }}">
<link rel="alternate stylesheet" title="Light theme" href="{{ pathto('_static/casperjs-light.css', 1) }}">
<script type="text/javascript" src="{{ pathto('_static/style-switcher.js', 1) }}"></script>
{% endblock extrahead %}
{%- if display_toc %}
<h3><a href="{{ pathto(master_doc) }}">{{ _('Document Outline') }}</a></h3>
{{ toc }}
{%- endif %}
<h3>Index</h3>
<p><a href="{{ pathto('genindex') }}">Thesaurus</a></p>
{%- if show_source and has_source and sourcename %}
<h3>{{ _('This Page') }}</h3>
<ul class="this-page-menu">
<li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
rel="nofollow">{{ _('Show Source') }}</a></li>
{% if display_github %}
<li><a href="https://github.com/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}.rst">
Show on GitHub</a></li>
<li><a href="https://github.com/{{ github_user }}/{{ github_repo }}/edit/{{ github_version }}{{ conf_py_path }}{{ pagename }}.rst">
Edit on GitHub</a></li>
{% endif %}
</ul>
{%- endif %}
/**
* http://www.alistapart.com/articles/alternate/
*
* var cookie = readCookie("style");
* var title = cookie ? cookie : getPreferredStyleSheet();
* setActiveStyleSheet(title);
*/
(function(exports, $) {
function setActiveStyleSheet(title) {
var i, a, main;
for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
if (a.getAttribute("rel").indexOf("style") !== -1 && a.getAttribute("title")) {
a.disabled = true;
if (a.getAttribute("title") === title) {
a.disabled = false;
}
}
}
}
exports.setActiveStyleSheet = setActiveStyleSheet;
function getActiveStyleSheet() {
var i, a;
for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
if (a.getAttribute("rel").indexOf("style") !== -1 && a.getAttribute("title") && !a.disabled) {
return a.getAttribute("title");
}
}
return null;
}
exports.getActiveStyleSheet = getActiveStyleSheet;
function getPreferredStyleSheet() {
var i, a;
for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
if (a.getAttribute("rel").indexOf("style") !== -1 &&
a.getAttribute("rel").indexOf("alt") === -1 &&
a.getAttribute("title")) {
return a.getAttribute("title");
}
}
return null;
}
exports.getPreferredStyleSheet = getPreferredStyleSheet;
function createCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toGMTString();
}
document.cookie = name + "=" + value + expires + "; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) === 0) {
return c.substring(nameEQ.length, c.length);
}
}
return null;
}
function createSwitcher() {
var $nav = $('.related').find('ul');
var styles = $('link').filter(function(i, link){
return $(link).attr('rel').indexOf('style') > -1 && $(link).attr('title');
}).map(function(i, link) {
return $(link).attr('title');
});
$(styles).each(function(i, style) {
var $link = $('<a/>').attr('href', '#')
.attr('title', style)
.addClass('style-switch')
.text(style);
$nav.prepend($('<li/>').addClass('right').append($link));
});
$('.style-switch').bind('click', function(event) {
event.preventDefault();
setActiveStyleSheet($(this).attr('title'));
});
}
exports.onload = function(e) {
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
createSwitcher();
}
exports.onunload = function(e) {
var title = getActiveStyleSheet();
createCookie("style", title, 365);
}
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
})(window, window.jQuery);
[theme]
inherit = basic
Changelog
=========
The CasperJS changelog is `hosted on github <https://github.com/n1k0/casperjs/blob/master/CHANGELOG.md#casperjs-changelog>`_.
.. _cli:
.. index:: Command line, CLI, PhantomJS, Shell, arguments, options
======================
Using the command line
======================
CasperJS ships with a built-in command line parser on top of PhantomJS' one, located in the ``cli`` module; it exposes passed arguments as **positional ones** and **named options**
But no worries for manipulating the ``cli`` module parsing API, a ``Casper`` instance always contains a ready to use ``cli`` property, allowing easy access of all these parameters.
Let's consider this simple casper script::
var casper = require("casper").create();
casper.echo("Casper CLI passed args:");
require("utils").dump(casper.cli.args);
casper.echo("Casper CLI passed options:");
require("utils").dump(casper.cli.options);
casper.exit();
.. note::
Please note the two ``casper-path`` and ``cli`` options; these are passed to the casper script through the ``casperjs`` Python executable.
Execution results::
$ casperjs test.js arg1 arg2 arg3 --foo=bar --plop anotherarg
Casper CLI passed args: [
"arg1",
"arg2",
"arg3",
"anotherarg"
]
Casper CLI passed options: {
"casper-path": "/Users/niko/Sites/casperjs",
"cli": true,
"foo": "bar",
"plop": true
}
Getting, checking or dropping parameters::
var casper = require("casper").create();
casper.echo(casper.cli.has(0));
casper.echo(casper.cli.get(0));
casper.echo(casper.cli.has(3));
casper.echo(casper.cli.get(3));
casper.echo(casper.cli.has("foo"));
casper.echo(casper.cli.get("foo"));
casper.cli.drop("foo");
casper.echo(casper.cli.has("foo"));
casper.echo(casper.cli.get("foo"));
casper.exit();
Execution results:
.. code-block:: text
$ casperjs test.js arg1 arg2 arg3 --foo=bar --plop anotherarg
true
arg1
true
anotherarg
true
bar
false
undefined
.. hint::
What if you want to check if any arg or option has been passed to your script? Here you go::
// removing default options passed by the Python executable
casper.cli.drop("cli");
casper.cli.drop("casper-path");
if (casper.cli.args.length === 0 && Object.keys(casper.cli.options).length === 0) {
casper.echo("No arg nor option passed").exit();
}
`casperjs` native options
-------------------------
.. versionadded:: 1.1
.. index:: Logging, log levels
The `casperjs` command has two available options:
- ``--direct``: to prints out log messages to the console
- ``--log-level=[debug|info|warning|error]`` to set the :ref:`logging level <logging>`
Example:
.. code-block:: text
$ casperjs --direct --log-level=debug myscript.js
Last but not least, you can still use all PhantomJS standard CLI options as you would do with any other phantomjs script:
.. code-block:: text
$ casperjs --web-security=no --cookies-file=/tmp/mycookies.txt myscript.js
.. hint::
To remember what the native phantomjs available cli options are, run the ``phantomjs --help`` command.
.. index:: Raw values
Raw parameter values
--------------------
.. versionadded:: 1.0
By default, the cli object will process every passed argument & cast them to the appropriate detected type; example script::
var casper = require('casper').create();
var utils = require('utils');
utils.dump(casper.cli.get('foo'));
casper.exit();
If you run this script:
.. code-block:: text
$ casperjs c.js --foo=01234567
1234567
As you can see, the ``01234567`` value has been cast to a *Number*.
Sometimes, you just want the original string; then you can use the ``raw`` property of the ``cli`` object, which contains the raw values passed parameters::
var casper = require('casper').create();
var utils = require('utils');
utils.dump(casper.cli.get('foo'));
utils.dump(casper.cli.raw.get('foo'));
casper.exit();
Sample usage:
.. code-block:: text
$ casperjs c.js --foo=01234567
1234567
"01234567"
# -*- coding: utf-8 -*-
#
# CasperJS documentation
#
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
from datetime import date
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.extlinks']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
highlight_language = 'javascript'
# The suffix of source filenames.
source_suffix = '.rst'
# Prolog
rst_prolog = ('.. note:: This is the documentation for the |release| version of'
' CasperJS. Find docs for 1.0 stable'
' `on the official website <http://casperjs.org/>`_.\n')
# The encoding of source files.
source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'CasperJS'
copyright = (u'2011-%d Nicolas Perriault and contributors. CasperJS logo by Jeremy Forveille'
% date.today().year)
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.1'
# The full version, including alpha/beta/rc tags.
release = '1.1.0-DEV'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build', 'README.md']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
#pygments_style = 'default'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'casperjs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['_themes']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = 'casperjs-favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
html_sidebars = {
'*': [
'globaltoc.html',
'relations.html',
'sourcelink.html',
'searchbox.html',
'addon.html'
],
'modules/*': [
'localtoc.html',
'globaltoc.html',
'relations.html',
'sourcelink.html',
'searchbox.html',
'addon.html'
],
}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'casper-docs'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
# latex_documents = [
# (),
# ]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'casperjs', u'casperjs documentation', [u'Nicolas Perriault'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'CasperJS', u'CasperJS Documentation',
u'Nicolas Perriault', 'CasperJS', 'CasperJS docs.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
extlinks = {
'issue': ('https://github.com/n1k0/casperjs/issues/%s', '#'),
'repo': ('https://github.com/n1k0/casperjs/%s', ''),
}
Credits
=======
Author
------
CasperJS is mainly developed by `Nicolas Perriault <https://nicolas.perriault.net/>`_ on its free time.
If you want to thank him and/or sponsor the development of CasperJS, please consider donating (see links in the sidebar).
Contributors
------------
These people have contributed to CasperJS:
- Brikou CARRE
- Thomas Parisot
- Han Yu
- Chris Lorenzo
- Victor Yap
- Rob Barreca
- Tyler Ritchie
- Nick Rabinowitz
- Pascal Borreli
- Dave Lee
- Andrew Childs
- Solomon White
- Reina Sweet
- Jan Schaumann
- Elmar Langholz
- Clochix
- Donovan Hutchinson
- Julien Moulin
- Michael Geers
- Jason Funk
- Vladimir Chizhov
- Jean-Philippe Serafin
- snkashis
- Rafael
- Andrew de Andrade
- Ben Lowery
- Chris Winters
- Christophe Benz
- Harrison Reiser
- Jan Pochyla
- Jan-Martin Fruehwacht
- Julian Gruber
- Justin Slattery
- Justine Tunney
- KaroDidi
- Leandro Boscariol
- Maisons du monde
- Marcel Duran
- Mathieu Agopian
- Mehdi Kabab
- Mikko Peltonen
- Rafael Garcia
- Raphaël Benitte
- Tim Bunce
Logo
----
CasperJS logo designed by `Jeremy Forveille <http://www.forveillejeremy.com/>`_
.. _debugging:
.. index:: Bugs, Debugging
=========
Debugging
=========
.. contents:: A few tips for debugging your casper scripts:
:local:
Use the :index:`verbose` mode
-----------------------------
By default & by design, a ``Casper`` instance won't print anything to the console. This can be very limitating & frustrating when creating or debugging scripts, so a good practice is to always start coding a script using these :index:`settings`::
var casper = require('casper').create({
verbose: true,
logLevel: "debug"
});
The ``verbose`` setting will tell Casper to write every logged message at the ``logLevel`` logging level onto the standard output, so you'll be able to trace every step made.
.. warning::
Output will then be pretty verbose, and will potentially display sensitive informations onto the console. **Use with care on production.**
Hook in the deep using :index:`events`
--------------------------------------
:doc:`Events <events-filters>` are a very powerful features of CasperJS, and you should probably give it a look if you haven't already.
Some interesting events you may eventually use to debug your scripts:
- The ``http.status.XXX`` event will be emitted everytime a resource is sent with the `HTTP code <http://en.wikipedia.org/wiki/List_of_HTTP_status_codes>`_ corresponding to ``XXX``;
- The ``remote.alert`` everytime an ``alert()`` call is performed client-side;
- ``remote.message`` everytime a message is sent to the client-side console;
- ``step.added`` everytime a step is added to the stack;
- etc…
Listening to an event is dead easy::
casper.on('http.status.404', function(resource) {
this.log('Hey, this one is 404: ' + resource.url, 'warning');
});
Ensure to check the :ref:`full list <events_list>` of all the other available events.
.. _debugging_dump:
Dump serialized values to the console
-------------------------------------
Sometimes it's helpful to inspect a variable, especially Object contents. The :ref:`utils_dump() <utils_dump>` function can achieve just that::
require('utils').dump({
foo: {
bar: 42
},
});
.. note::
:ref:`utils_dump() <utils_dump>` won't be able to serialize function nor complex cyclic structures though.
Localize yourself in modules
----------------------------
If you're creating Casper modules, a cool thing to know is that there's a special built-in variable available in every module, ``__file__``, which contains the absolute path to current javascript file (the module file).
Name your closures
------------------
Probably one of the most easy but effective best practice, always name your closures:
**Hard to track:**
::
casper.start('http://foo.bar/', function() {
this.evaluate(function() {
// ...
});
});
**Easier:**
::
casper.start('http://foo.bar/', function afterStart() {
this.evaluate(function evaluateStuffAfterStart() {
// ...
});
});
That way, everytime one is failing, its name will be printed out in the :index:`stack trace`, **so you can more easily locate it within your code**.
.. note::
This one also applies for all your other Javascript works, of course ;)
.. _extending:
.. index:: extending, inheritance, prototype
=========
Extending
=========
Sometimes it can be convenient to add your own methods to a ``Casper`` object instance; you can easily do so as illustrated in the example below::
var casper = require('casper').create({
verbose: true,
logLevel: "debug"
});
var links = {
'http://edition.cnn.com/': 0,
'http://www.nytimes.com/': 0,
'http://www.bbc.co.uk/': 0,
'http://www.guardian.co.uk/': 0
};
casper.countLinks = function() {
return this.evaluate(function() {
return __utils__.findAll('a[href]').length;
});
};
casper.renderJSON = function(what) {
return this.echo(JSON.stringify(what, null, ' '));
};
casper.start();
casper.each(Object.keys(links), function(casper, link) {
this.thenOpen(link, function() {
links[link] = this.countLinks();
});
});
casper.run(function() {
this.renderJSON(links).exit();
});
But that's just plain old *monkey-patching* the ``casper`` object, and you may probably want a more OO approach… That's where the ``inherits()`` function from the ``utils`` module and ported from `nodejs <http://nodejs.org/>`_ comes handy::
var Casper = require('casper').Casper;
var utils = require('utils');
var links = {
'http://edition.cnn.com/': 0,
'http://www.nytimes.com/': 0,
'http://www.bbc.co.uk/': 0,
'http://www.guardian.co.uk/': 0
};
function Fantomas() {
Fantomas.super_.apply(this, arguments);
}
// Let's make our Fantomas class extending the Casper one
// please note that at this point, CHILD CLASS PROTOTYPE WILL BE OVERRIDEN
utils.inherits(Fantomas, Casper);
Fantomas.prototype.countLinks = function() {
return this.evaluate(function() {
return __utils__.findAll('a[href]').length;
});
};
Fantomas.prototype.renderJSON = function(what) {
return this.echo(JSON.stringify(what, null, ' '));
};
var fantomas = new Fantomas({
verbose: true,
logLevel: "debug"
});
fantomas.start();
Object.keys(links).forEach(function(url) {
fantomas.thenOpen(url, function() {
links[url] = this.countLinks();
});
});
fantomas.run(function() {
this.renderJSON(links).exit();
});
.. note::
The use of the ``super_`` child class property which becomes available once its parent has been defined using ``inherits()``; it contains a reference to the parent constructor.
**Don't forget to call ``Casper``'s parent constructor!**
Of course this approach is bit more verbose than the easy *monkey-patching* one, so please ensure you're not just overengineering stuff by subclassing the ``Casper`` class.
.. index:: coffeescript
Using CoffeeScript
~~~~~~~~~~~~~~~~~~
If you're writing your casper scripts using `CoffeeScript <http://coffeescript.org/>`_, extending casper is getting a bit more straightforward:
.. code-block:: coffeescript
links =
'http://edition.cnn.com/': 0
'http://www.nytimes.com/': 0
'http://www.bbc.co.uk/': 0
'http://www.guardian.co.uk/': 0
class Fantomas extends require('casper').Casper
countLinks: ->
@evaluate ->
__utils__.findAll('a').length
renderJSON: (what) ->
@echo JSON.stringify what, null, ' '
fantomas = new Fantomas
loadImages: false
logLevel: "debug"
verbose: true
fantomas.start()
for url of links
do (url) ->
fantomas.thenOpen url, ->
links[url] = @countLinks()
fantomas.run ->
@renderJSON links
@exit()
This diff is collapsed. Click to expand it.
======================
CasperJS documentation
======================
CasperJS_ is a navigation scripting & testing utility for PhantomJS_, written in Javascript.
.. figure:: _static/images/casperjs-logo.png
:align: right
.. toctree::
:maxdepth: 2
installation
quickstart
cli
selectors
testing
modules/index
writing_modules
events-filters
logging
extending
debugging
faq
changelog
upgrading/index
credits
license
You can also search the :ref:`genindex` if you're looking for something particular.
.. index:: Community, Contributing, Help, Support
Community
---------
- `get the code <https://github.com/n1k0/casperjs>`_ and `contribute <https://github.com/n1k0/casperjs/blob/master/CONTRIBUTING.md#contribution-guide>`_
- join the `mailing list <https://groups.google.com/forum/#!forum/casperjs>`_
- check out `the ecosystem <https://github.com/casperjs>`_
- follow `@casperjs\_org <https://twitter.com/casperjs_org>`_ on Twitter
- there's also a `Google+ account <https://plus.google.com/106641872690063476159>`_ (not much updated though)
.. _CasperJS: http://casperjs.org/
.. _PhantomJS: http://phantomjs.org/
.. _installation:
.. index:: Installation
============
Installation
============
CasperJS can be installed on most Linuxes, OSX and Windows.
Prerequisites
-------------
.. index:: PhantomJS, Python
- PhantomJS_ 1.8.1 or greater. Installation instructions can be found `here <http://phantomjs.org/download.html>`_
- Python_ 2.6 or greater
.. note::
.. versionadded:: 1.0
A `Ruby <http://ruby-lang.org/>`_ version of the ``casperjs`` executable is also available in the ``rubybin/`` directory; in order to use the :index:`Ruby` version instead of the Python one:
.. code-block:: text
$ ln -sf `pwd`/rubybin/casperjs /usr/local/bin/casperjs
Or using the ruby interpreter:
.. code-block:: text
$ ruby /path/to/casperjs/rubybin/casperjs
CasperJS version 1.1-DEV at /path/to/casperjs/rubybin/casperjs, using PhantomJS version 1.7.0
...
.. index:: Homebrew
Installing from Homebrew (OSX)
------------------------------
Installation of both PhantomJS and CasperJS can be achieved through `Homebrew <http://mxcl.github.com/homebrew/>`_::
$ brew install casperjs
.. index:: git
Installing from git
-------------------
Installation can be achieved using `git <http://git-scm.com/>`_. The code is mainly hosted on `Github <https://github.com/n1k0/casperjs>`_.
From a stable tag
~~~~~~~~~~~~~~~~~
.. code-block:: text
$ git clone git://github.com/n1k0/casperjs.git
$ cd casperjs
$ git checkout tags/1.0
$ ln -sf `pwd`/bin/casperjs /usr/local/bin/casperjs
Once PhantomJS and CasperJS installed on your machine, you should obtain something like this:
.. code-block:: text
$ phantomjs --version
1.7
$ casperjs --version
1.0
From the master branch
~~~~~~~~~~~~~~~~~~~~~~
The ``master`` branch hosts the current development version of CasperJS.
.. code-block:: text
$ git clone git://github.com/n1k0/casperjs.git
$ cd casperjs
$ git checkout master
$ ln -sf `pwd`/bin/casperjs /usr/local/bin/casperjs
To check your current installed version:
.. code-block:: text
$ casperjs --version
1.1-DEV
You are now ready to write your :doc:`first script <quickstart>`!
Installing from an archive
--------------------------
You can download tagged archives of CasperJS code:
**Latest stable version:**
- https://github.com/n1k0/casperjs/zipball/1.0.0 (zip)
- https://github.com/n1k0/casperjs/tarball/1.0.0 (tar.gz)
**Latest development version (master branch):**
- https://github.com/n1k0/casperjs/zipball/master (zip)
- https://github.com/n1k0/casperjs/tarball/master (tar.gz)
Operations are then the same as with a git checkout.
.. index:: Windows
CasperJS on Windows
-------------------
Phantomjs installation additions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Append ``";C:\phantomjs"`` to your ``PATH`` environment variable.
- Modify this path appropriately if you installed PhantomJS to a different location.
Casperjs installation additions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.0
CasperJS, as of 1.0.0-RC3, ships with a Batch script so you don't need Python nor Ruby to use it.
- Append ``";C:\casperjs\batchbin"`` to your ``PATH`` environment variable.
- Modify this path appropriately if you installed CasperJS to a different location.
You can now run any regular casper scripts that way:
.. code-block:: text
C:> casperjs.bat myscript.js
Earlier versions of CasperJS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before 1.0.0-RC3, you had to setup your casper scripts that way::
phantom.casperPath = 'C:\\casperjs-1.1';
phantom.injectJs(phantom.casperPath + '\\bin\\bootstrap.js');
var casper = require('casper').create();
// do stuff
Run the script using the ``phantom.exe`` program:
.. code-block:: text
C:> phantomjs.exe myscript.js
.. note::
There is no output coloration when running CasperJS on Microsoft platforms.
.. index:: Bugs, REPL
Known Bugs & Limitations
------------------------
- Due to its asynchronous nature, CasperJS doesn't work well with `PhantomJS' REPL <http://code.google.com/p/phantomjs/wiki/InteractiveModeREPL>`_.
.. _PhantomJS: http://phantomjs.org/
.. _Python: http://python.org/
.. _license:
.. index:: Licensing
=======
License
=======
`CasperJS <http://casperjs.org>`_ is released under the terms of the
`MIT license <http://en.wikipedia.org/wiki/MIT_License>`_.
::
Copyright (c) 2011-{{year}} Nicolas Perriault
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
.. _logging:
.. index:: Logging, log levels
=======
Logging
=======
CasperJS allows logging using the :ref:`casper.log() <casper_log>` method and these standard event levels:
- ``debug``
- ``info``
- ``warning``
- ``error``
Sample use::
var casper = require('casper').create();
casper.log('plop', 'debug');
casper.log('plip', 'warning');
.. index:: verbose
Now, there are two things to distinguish: log *storage* and log *display*; by default CasperJS won't print the logs to the standard output. In order to do so, you must enable the ``verbose`` Casper option::
var casper = require('casper').create({
verbose: true
});
Also, by default Casper is configured to filter logging which is under the ``error`` level; you can override this setting by configuring the ``logLevel`` option::
var casper = require('casper').create({
verbose: true,
logLevel: 'debug'
});
You can also dump a JSON log of your Casper suite just by rendering the contents of the ``Casper.logs`` property::
var casper = require('casper').create({
// ...
casper.run(function() {
require('utils').dump(this.logs);
this.exit();
});
Last, if you print log messages to the standard output using the ``verbose`` option, you'll get some fancy colors::
var casper = require('casper').create({
verbose: true,
logLevel: 'debug'
})
casper.log('this is a debug message', 'debug');
casper.log('and an informative one', 'info');
casper.log('and a warning', 'warning');
casper.log('and an error', 'error');
casper.exit();
This will give the following output:
.. figure:: _static/images/logoutput.png
:align: center
:alt: image
image
.. hint::
CasperJS doesn't write logs on the filesystem. You have to implement this by yourself if needed.
.. _colorizer_module:
.. index:: Colors, colorizer
========================
The ``colorizer`` module
========================
The ``colorizer`` module contains a ``Colorizer`` class which can generate ANSI colored strings::
var colorizer = require('colorizer').create('Colorizer');
console.log(colorizer.colorize("Hello World", "INFO"));
Though most of the times you will use it transparently using the :ref:`Casper.echo() <casper_echo>` method::
casper.echo('an informative message', 'INFO'); // printed in green
casper.echo('an error message', 'ERROR'); // printed in red
Skipping CasperJS styling operations
------------------------------------
If you wish to skip the whole coloration operation and get uncolored plain text, just set the ``colorizerType`` casper option to ``Dummy``::
var casper = require('casper').create({
colorizerType: 'Dummy'
});
casper.echo("Hello", "INFO");
.. index:: Windows
.. note::
That's especially useful if you're using CasperJS on the Windows platform, as there's no support for colored output on this platform.
.. _colorizer_styles:
.. index:: Printing styles
Available predefined styles
---------------------------
Available predefined styles are:
- ``ERROR``: white text on red background
- ``INFO``: green text
- ``TRACE``: green text
- ``PARAMETER``: cyan text
- ``COMMENT``: yellow text
- ``WARNING``: red text
- ``GREEN_BAR``: white text on green background
- ``RED_BAR``: white text on red background
- ``INFO_BAR``: cyan text
- ``WARN_BAR``: white text on orange background
Here's a sample output of what it can look like:
.. figure:: ../_static/images/colorizer.png
:align: center
``colorize()``
-------------------------------------------------------------------------------
**Signature:** ``colorize(String text, String styleName)``
Computes a colored version of the provided text string using a given predefined style::
var colorizer = require('colorizer').create();
console.log(colorizer.colorize("I'm a red error", "ERROR"));
.. note::
Most of the time you won't have to use a ``Colorizer`` instance directly as CasperJS provides all the necessary methods.
See the list of the :ref:`predefined styles available <colorizer_styles>`.
``format()``
-------------------------------------------------------------------------------
**Signature:** ``format(String text, Object style)``
Formats a text string using the provided style definition. A style definition is a standard javascript ``Object`` instance which can define the following properties:
- String ``bg``: background color name
- String ``fg``: foreground color name
- Boolean ``bold``: apply bold formatting
- Boolean ``underscore``: apply underline formatting
- Boolean ``blink``: apply blink formatting
- Boolean ``reverse``: apply reverse formatting
- Boolean ``conceal``: apply conceal formatting
.. note::
Available color names are ``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan`` and ``white``::
var colorizer = require('colorizer').create();
colorizer.format("We all live in a yellow submarine", {
bg: 'yellow',
fg: 'blue',
bold: true
});
.. _modules_index:
.. index:: modules
=================
API Documentation
=================
Here you'll find a quite complete reference of the CasperJS API. If something is erroneous or missing, please `file an issue <https://github.com/n1k0/casperjs/issues/new>`_.
.. toctree::
:glob:
*
.. _utils_module:
.. index:: Utilities, Helpers
====================
The ``utils`` module
====================
This module provides simple helper functions, some of them being very specific to CasperJS though.
Functions reference
+++++++++++++++++++
Usage is pretty much straightforward::
var utils = require('utils');
utils.dump({plop: 42});
``betterTypeOf()``
-------------------------------------------------------------------------------
**Signature:** ``betterTypeOf(input)``
Provides a better ``typeof`` operator equivalent, eg. able to retrieve the ``Array`` type.
.. index:: dump, Serialization, Debugging, JSON
.. _utils_dump:
``dump()``
-------------------------------------------------------------------------------
**Signature:** ``dump(value)``
Dumps a JSON_ representation of passed argument to the standard output. Useful for :ref:`debugging your scripts <debugging_dump>`.
``fileExt()``
-------------------------------------------------------------------------------
**Signature:** ``fileExt(file)``
Retrieves the extension of passed filename.
``fillBlanks()``
-------------------------------------------------------------------------------
**Signature:** ``fillBlanks(text, pad)``
Fills a string with trailing spaces to match ``pad`` length.
.. index:: String formatting
``format()``
-------------------------------------------------------------------------------
**Signature:** ``format(f)``
Formats a string against passed args. ``sprintf`` equivalent.
.. note::
This is a port of nodejs ``util.format()``.
``getPropertyPath()``
-------------------------------------------------------------------------------
**Signature:** ``getPropertyPath(Object obj, String path)``
.. versionadded:: 1.0
Retrieves the value of an Object foreign property using a dot-separated path string::
var account = {
username: 'chuck',
skills: {
kick: {
roundhouse: true
}
}
}
utils.getPropertyPath(account, 'skills.kick.roundhouse'); // true
.. warning::
This function doesn't handle object key names containing a dot.
.. index:: inheritance
``inherits()``
-------------------------------------------------------------------------------
**Signature:** ``inherits(ctor, superCtor)``
Makes a constructor inheriting from another. Useful for subclassing and :doc:`extending <../extending>`.
.. note::
This is a port of nodejs ``util.inherits()``.
``isArray()``
-------------------------------------------------------------------------------
**Signature:** ``isArray(value)``
Checks if passed argument is an instance of ``Array``.
``isCasperObject()``
-------------------------------------------------------------------------------
**Signature:** ``isCasperObject(value)``
Checks if passed argument is an instance of ``Casper``.
``isClipRect()``
-------------------------------------------------------------------------------
**Signature:** ``isClipRect(value)``
Checks if passed argument is a ``cliprect`` object.
.. index:: falsiness
``isFalsy()``
-------------------------------------------------------------------------------
**Signature:** ``isFalsy(subject)``
.. versionadded:: 1.0
Returns subject `falsiness <http://11heavens.com/falsy-and-truthy-in-javascript>`_.
``isFunction()``
-------------------------------------------------------------------------------
**Signature:** ``isFunction(value)``
Checks if passed argument is a function.
``isJsFile()``
-------------------------------------------------------------------------------
**Signature:** ``isJsFile(file)``
Checks if passed filename is a Javascript one (by checking if it has a ``.js`` or ``.coffee`` file extension).
``isNull()``
-------------------------------------------------------------------------------
**Signature:** ``isNull(value)``
Checks if passed argument is a ``null``.
``isNumber()``
-------------------------------------------------------------------------------
**Signature:** ``isNumber(value)``
Checks if passed argument is an instance of ``Number``.
``isObject()``
-------------------------------------------------------------------------------
**Signature:** ``isObject(value)``
Checks if passed argument is an object.
``isString()``
-------------------------------------------------------------------------------
**Signature:** ``isString(value)``
Checks if passed argument is an instance of ``String``.
.. index:: truthiness
``isTruthy()``
-------------------------------------------------------------------------------
**Signature:** ``isTruthy(subject)``
.. versionadded:: 1.0
Returns subject `truthiness <http://11heavens.com/falsy-and-truthy-in-javascript>`_.
``isType()``
-------------------------------------------------------------------------------
**Signature:** ``isType(what, type)``
Checks if passed argument has its type matching the ``type`` argument.
``isUndefined()``
-------------------------------------------------------------------------------
**Signature:** ``isUndefined(value)``
Checks if passed argument is ``undefined``.
``isWebPage()``
-------------------------------------------------------------------------------
**Signature:** ``isWebPage(what)``
Checks if passed argument is an instance of native PhantomJS' ``WebPage`` object.
``mergeObjects()``
-------------------------------------------------------------------------------
**Signature:** ``mergeObjects(origin, add)``
Merges two objects recursively.
.. index:: DOM
``node()``
-------------------------------------------------------------------------------
**Signature:** ``node(name, attributes)``
Creates an (HT\|X)ML element, having optional ``attributes`` added.
.. index:: JSON
``serialize()``
-------------------------------------------------------------------------------
**Signature:** ``serialize(value)``
Serializes a value using JSON_ format. Will serialize functions as strings. Useful for :doc:`debugging <../debugging>` and comparing objects.
``unique()``
-------------------------------------------------------------------------------
**Signature:** ``unique(array)``
Retrieves unique values from within a given ``Array``.
.. _JSON: http://json.org/
.. _quickstart:
==========
Quickstart
==========
Once CasperJS is :doc:`properly installed <installation>`, you can write your first script. You can use plain :ref:`Javascript <quickstart_javascript>` or :ref:`CoffeeScript <quickstart_coffeescript>`.
.. hint::
If you're not too comfortable with Javascript, a :ref:`dedicated FAQ entry <faq_javascript>` is waiting for you.
.. _quickstart_javascript:
A minimal scraping script
-------------------------
Fire up your favorite editor, create and save a ``sample.js`` file like below::
var casper = require('casper').create();
casper.start('http://casperjs.org/', function() {
this.echo(this.getTitle());
});
casper.thenOpen('http://phantomjs.org', function() {
this.echo(this.getTitle());
});
casper.run();
Run it:
.. code-block:: text
$ casperjs sample.js
You should get something like this:
.. code-block:: text
$ casperjs c.js
CasperJS, a navigation scripting and testing utility for PhantomJS | CasperJS 1.0.0
PhantomJS: Headless WebKit with JavaScript API
.. topic:: What did we just do?
1. we created a new :ref:`Casper <casper_module>` instance
2. we started it and opened ``http://casperjs.org/``
3. *once* the page has been loaded, we asked to print the title of that webpage (the content of its ``<title>`` tag)
4. *then* we opened another url, ``http://phantomjs.org/``
5. *once* the new page has been loaded, we asked to print its title too
6. we executed the whole process
Now let's scrape Google!
------------------------
In the following example, we'll query google for two terms consecutively, *"casperjs"* and *"phantomjs"*, aggregate the result links in a standard ``Array`` and output the result to the console.
Fire up your favorite editor and save the javascript code below in a
``googlelinks.js`` file::
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.fr/', function() {
// search for 'casperjs' from google form
this.fill('form[action="/search"]', { q: 'casperjs' }, true);
});
casper.then(function() {
// aggregate results for the 'casperjs' search
links = this.evaluate(getLinks);
// now search for 'phantomjs' by filling the form again
this.fill('form[action="/search"]', { q: 'phantomjs' }, true);
});
casper.then(function() {
// aggregate results for the 'phantomjs' search
links = links.concat(this.evaluate(getLinks));
});
casper.run(function() {
// echo results in some pretty fashion
this.echo(links.length + ' links found:');
this.echo(' - ' + links.join('\n - ')).exit();
});
Run it:
.. code-block:: text
$ casperjs googlelinks.js
20 links found:
- https://github.com/n1k0/casperjs
- https://github.com/n1k0/casperjs/issues/2
- https://github.com/n1k0/casperjs/tree/master/samples
- https://github.com/n1k0/casperjs/commits/master/
- http://www.facebook.com/people/Casper-Js/100000337260665
- http://www.facebook.com/public/Casper-Js
- http://hashtags.org/tag/CasperJS/
- http://www.zerotohundred.com/newforums/members/casper-js.html
- http://www.yellowpages.com/casper-wy/j-s-enterprises
- http://local.trib.com/casper+wy/j+s+chinese+restaurant.zq.html
- http://www.phantomjs.org/
- http://code.google.com/p/phantomjs/
- http://code.google.com/p/phantomjs/wiki/QuickStart
- http://svay.com/blog/index/post/2011/08/31/Paris-JS-10-%3A-Introduction-%C3%A0-PhantomJS
- https://github.com/ariya/phantomjs
- http://dailyjs.com/2011/01/28/phantoms/
- http://css.dzone.com/articles/phantom-js-alternative
- http://pilvee.com/blog/tag/phantom-js/
- http://ariya.blogspot.com/2011/01/phantomjs-minimalistic-headless-webkit.html
- http://www.readwriteweb.com/hack/2011/03/phantomjs-the-power-of-webkit.php
.. _quickstart_coffeescript:
.. index:: coffeescript
CoffeeScript version
--------------------
You can also write Casper scripts using the `CoffeeScript syntax <http://jashkenas.github.com/coffee-script/>`_:
.. code-block:: coffeescript
getLinks = ->
links = document.querySelectorAll "h3.r a"
Array::map.call links, (e) -> e.getAttribute "href"
links = []
casper = require('casper').create()
casper.start "http://google.fr/", ->
# search for 'casperjs' from google form
@fill "form[action='/search']", q: "casperjs", true
casper.then ->
# aggregate results for the 'casperjs' search
links = @evaluate getLinks
# search for 'phantomjs' from google form
@fill "form[action='/search']", q: "phantomjs", true
casper.then ->
# concat results for the 'phantomjs' search
links = links.concat @evaluate(getLinks)
casper.run ->
# display results
@echo links.length + " links found:"
@echo(" - " + links.join("\n - ")).exit()
Just remember to suffix your script with the ``.coffee`` extension.
A minimal testing script
------------------------
CasperJS is also a :ref:`testing framework <testing>`; test scripts are slightly different than scraping ones, though they share most of their API. A simplest test script::
// hello-test.js
casper.test.assert(true);
casper.test.done();
Run it using the ``casperjs test`` subcommand:
.. code-block:: text
$ casperjs test hello-test.js
Test file: hello-test.js
PASS Subject is strictly true
PASS 1 tests executed in 0.103s, 1 passed, 0 failed.
.. note::
As you can see, there's no need to create a ``casper`` instance in a test script as a preconfigured one has already made available for you.
You can read more about testing in the :ref:`dedicated section <testing>`.
.. _selectors:
.. index:: selector, DOM, HTML
=========
Selectors
=========
CasperJS makes an heavy use of selectors in order to work with the `DOM <http://www.w3.org/TR/dom/>`_, and can transparently use either `CSS3 <http://www.w3.org/TR/selectors/>`_ or `XPath <http://www.w3.org/TR/xpath/>`_ expressions.
All the examples below are based on this HTML code:
.. code-block:: html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>My page</title>
</head>
<body>
<h1 class="page-title">Hello</h1>
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
<footer><p>©2012 myself</p></footer>
</body>
</html>
.. index:: CSS, CSS3
CSS3
----
By default, CasperJS accepts `CSS3 selector strings <http://www.w3.org/TR/selectors/#selectors>`_ to check for elements within the DOM.
To check if the ``<h1 class="page-title">`` element exists in the example page, you can use::
var casper = require('casper').create();
casper.start('http://domain.tld/page.html', function() {
if (this.exists('h1.page-title')) {
this.echo('the heading exists');
}
});
casper.run();
Or if you're using the :doc:`testing framework <testing>`::
casper.test.begin('The heading exists', 1, function suite(test) {
casper.start('http://domain.tld/page.html', function() {
this.assertExists('h1.page-title');
}).run(function() {
test.done();
});
});
Some other convenient testing methods are relying on selectors::
casper.test.begin('Page content tests', 3, function suite(test) {
casper.start('http://domain.tld/page.html', function() {
this.assertExists('h1.page-title');
this.assertSelectorHasText('h1.page-title', 'Hello');
this.assertVisible('footer');
}).run(function() {
test.done();
});
});
.. index:: XPath
XPath
-----
.. versionadded:: 0.6.8
You can alternatively use `XPath expressions <http://en.wikipedia.org/wiki/XPath>`_ instead::
casper.start('http://domain.tld/page.html', function() {
this.test.assertExists({
type: 'xpath',
path: '//*[@class="plop"]'
}, 'the element exists');
});
To ease the use and reading of XPath expressions, a ``selectXPath`` helper is available from the ``casper`` module::
var x = require('casper').selectXPath;
casper.start('http://domain.tld/page.html', function() {
this.test.assertExists(x('//*[@id="plop"]'), 'the element exists');
});
.. warning::
The only limitation of XPath use in CasperJS is in the :ref:`casper.fill() <casper_fill>` method when you want to fill **file fields**; PhantomJS natively only allows the use of CSS3 selectors in its `uploadFile method <https://github.com/ariya/phantomjs/wiki/API-Reference#wiki-webpage-uploadFile>`_, hence this limitation.
.. _testing:
.. index:: Testing
=======
Testing
=======
CasperJS ships with its own :doc:`testing framework <modules/tester>`, providing a handful set of tools to ease testing your webapps.
.. warning::
.. versionchanged:: 1.1
The testing framework — hence its whole API — can only be used when using the ``casperjs test`` subcommand.
If you try to use the ``casper.test`` property out of the testing environment, you'll get an error.
.. index:: Unit testing
Unit testing
------------
Imagine a dumb ``Cow`` object we want to unit test::
function Cow() {
this.mowed = false;
this.moo = function moo() {
this.mowed = true; // mootable state: don't do that at home
return 'moo!';
};
}
Let's write a tiny test suite for it::
// cow-test.js
casper.test.begin('Cow can moo', 2, function suite(test) {
var cow = new Cow();
test.assertEquals(cow.moo(), 'moo!');
test.assert(cow.mowed);
test.done();
});
Run the tests using the ``casperjs test`` command:
.. code-block:: text
$ casperjs test cow-test.js
You should theoretically get something like this:
.. figure:: _static/images/cow-test-ok.png
:align: center
Make it fail::
casper.test.begin('Cow can moo', 2, function suite(test) {
var cow = new Cow();
test.assertEquals(cow.moo(), 'BAZINGA!');
test.assert(cow.mowed);
test.done();
});
You'll get this instead:
.. figure:: _static/images/cow-test-ko.png
:align: center
.. hint::
The whole ``tester`` module API is documented :doc:`here <modules/tester>`.
.. index:: Functional testing, Browser testing, Test suite
Browser tests
-------------
Now let's write a suite for testing google search (yes, you read it well)::
// googletesting.js
casper.test.begin('Google search retrieves 10 or more results', 5, function suite(test) {
casper.start("http://www.google.fr/", function() {
test.assertTitle("Google", "google homepage title is the one expected");
test.assertExists('form[action="/search"]', "main form is found");
this.fill('form[action="/search"]', {
q: "casperjs"
}, true);
});
casper.then(function() {
test.assertTitle("casperjs - Recherche Google", "google title is ok");
test.assertUrlMatch(/q=casperjs/, "search term has been submitted");
test.assertEval(function() {
return __utils__.findAll("h3.r").length >= 10;
}, "google search for \"casperjs\" retrieves 10 or more results");
});
casper.run(function() {
test.done();
});
});
Now run the tests suite:
.. code-block:: text
$ casperjs test googletesting.js
You'll probably get something like this:
.. figure:: _static/images/testsuiteok.png
:align: center
Advanced techniques
-------------------
The :ref:`Tester#begin() <tester_begin>` accepts either a function or an object to describe a suite; the object option allows to set up ``setUp()`` and ``tearDown()`` functions::
// cow-test.js
casper.test.begin('Cow can moo', 2, {
setUp: function(test) {
this.cow = new Cow();
},
tearDown: function(test) {
this.cow.destroy();
},
test: function(test) {
test.assertEquals(this.cow.moo(), 'moo!');
test.assert(this.cow.mowed);
test.done();
}
});
Test command args and options
-----------------------------
Arguments
~~~~~~~~~
The ``capserjs test`` command will treat every passed argument as file or directory paths containing tests. It will recursively scan any passed directory to search for ``*.js`` or ``*.coffee`` files and add them to the stack.
.. warning ::
There are two important conditions when writing tests:
- You **must not** create a new ``Casper`` instance in a test file;
- You **must** call ``Tester.done()`` when all the tests contained in a suite (or in a file) have been executed.
Options
~~~~~~~
Options are prefixed with a double-dash (``--``):
- ``--xunit=<filename>`` will export test suite results in a :ref:`XUnit XML file <xunit_report>`
- ``--direct`` will print :doc:`log messages <logging>` directly to the console
- ``--log-level=<logLevel>`` sets the logging level (see the :doc:`related section <logging>`)
.. versionadded:: 1.0
- ``--includes=foo.js,bar.js`` will include the ``foo.js`` and ``bar.js`` files before each test file execution;
- ``--pre=pre-test.js`` will add the tests contained in ``pre-test.js`` **before** executing the whole test suite;
- ``--post=post-test.js`` will add the tests contained in ``post-test.js`` **after** having executed the whole test suite;
- ``--fail-fast`` will terminate the current test suite as soon as a first failure is encountered.
Sample custom command:
.. code-block:: text
$ casperjs test --includes=foo.js,bar.js \
--pre=pre-test.js \
--post=post-test.js \
--direct \
--log-level=debug \
--fail-fast \
test1.js test2.js /path/to/some/test/dir
.. hint::
A `demo gist <https://gist.github.com/3813361>`_ is also available in order to get you started with a sample suite involving some of these options.
.. _xunit_report:
.. index:: XUnit, XML, Jenkins, Continuous Integration
Exporting results in XUnit format
---------------------------------
CasperJS can export the results of the test suite to an XUnit XML file, which is compatible with continuous integration tools such as `Jenkins <http://jenkins-ci.org/>`_. To save the XUnit log of your test suite, use the ``--xunit`` option:
.. code-block:: text
$ casperjs test googletesting.js --save=log.xml
You should get a pretty XUnit XML report like this:
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuites duration="1.249">
<testsuite errors="0" failures="0" name="Google search retrieves 10 or more results" package="googletesting" tests="5" time="1.249" timestamp="2012-12-30T21:27:26.320Z">
<testcase classname="googletesting" name="google homepage title is the one expected" time="0.813"/>
<testcase classname="googletesting" name="main form is found" time="0.002"/>
<testcase classname="googletesting" name="google title is ok" time="0.416"/>
<testcase classname="googletesting" name="search term has been submitted" time="0.017"/>
<testcase classname="googletesting" name="google search for &quot;casperjs&quot; retrieves 10 or more results" time="0.001"/>
<system-out/>
</testsuite>
</testsuites>
CasperJS own tests
------------------
CasperJS has its own unit and functional test suite, located in the ``tests`` subfolder. To run this test suite:
.. code-block:: text
$ casperjs selftest
.. note::
Running this test suite is a great way to find any bug on your platform. If it fails, feel free to `file an issue <https://github.com/n1k0/casperjs/issues/new>`_ or to ask on the `CasperJS mailing-list <https://groups.google.com/forum/#!forum/casperjs>`_.
.. index:: extending
Extending Casper for Testing
----------------------------
This command:
.. code-block:: text
$ casperjs test [path]
is just a shortcut for this one:
.. code-block:: text
$ casper /path/to/casperjs/tests/run.js [path]
So if you want to extend Casper capabilities for your tests, your best bet is to write your own runner and extend the casper object instance from there.
.. hint::
You can find the default runner code in `run.js <https://github.com/n1k0/casperjs/blob/master/tests/run.js>`_.
Upgrading to 1.1
================
The most visible change is the way you write tests. With 1.0, you were able to access a ``.test`` property from any casper script and so running a suite using the standard ``casperjs`` executable::
// 1.0 style test script not using the `casperjs test` subcommand
var casper = require('casper').create();
casper.start('http://foo.bar/', function() {
this.test.assert(true);
});
casper.run(function() {
this.test.done(1);
this.test.renderResults(true);
});
In 1.1, the test framework has been heavily refactored to decouple the tester from a casper instance as much as possible, so it's no more possible to run a test suite right from the standard ``casperjs`` command as you would have done with the script shown above.
Instead you now have to use the :doc:`casperjs test <../testing>` subcommand mandatorily to access a tester instance from the ``casper.test`` property.
.. warning::
As of 1.1:
- you shouldn't invoke the ``renderResults()`` method directly anymore
- you shouldn't use the ``done()`` first argument to set planned test as it's been deprecated
- you can't access the ``casper.test`` property when not using the ``casperjs test`` subcommand
If you try, you'll get an error::
// test.js
var casper = require('casper').create();
casper.test.assert(true);
Will give:
.. code-block:: text
$ casperjs test.js
CasperError: casper.test property is only available using the `casperjs test` command
The new ``Tester#begin()`` method
---------------------------------
However, a new :ref:`begin() <tester_begin>` method as been added to the :ref:`Tester <tester_module>` prototype, to ease describing your tests::
casper.test.begin('Description of my test', 1, function(test) {
test.assert(true);
test.done();
});
More asynchronously::
casper.test.begin('Description of my test', 1, function(test) {
casper.start('http://foo.bar/', function() {
test.assert(true);
});
casper.run(function() {
test.done();
});
});
.. note::
Please note that ``begin()``'s the second argument which is now the place to set the number of planned tests.
Upgrading
=========
.. toctree::
:maxdepth: 1
1.1
.. _writing_modules:
.. index:: Modules, Modules, Custom module
Writing CasperJS modules
========================
As of 1.1, CasperJS relies on PhantomJS' native ``require()`` function internally though it had to be patched in order to allow requiring casper modules using their full name, eg. ``require('casper')``.
So if you plan to write your own modules and uses casperjs' ones from them, be sure to call the ``patchRequire()`` function::
// my module, stored in universe.js
// patching phantomjs' require()
var require = patchRequire(require);
// now you're ready to go
var utils = require('utils');
var magic = 42;
exports.answer = function() {
return utils.format("it's %d", magic);
};
.. warning::
When using CoffeeScript ``global.require`` must be passed to ``patchRequire()`` instead of just ``require``.
From your root casper script::
var universe = require('./universe');
console.log(universe.answer()); // prints "It's 42"