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 %}
/**
* casper.css
* ~~~~~~~~~~~~~~~
*
* CasperJS stylesheet, based on RTD one:
*
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
* Armin Ronacher for Werkzeug.
*
* Customized for ReadTheDocs by Eric Pierce & Eric Holscher
*
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* PAGE LAYOUT -------------------------------------------------------------- */
body {
font: 100%/1.5 Asap, "ff-meta-web-pro-1", "ff-meta-web-pro-2", Arial, "Helvetica Neue", sans-serif;
text-align: center;
color: #fff;
background-color: #222;
padding: 0;
margin: 0;
}
img {
border: 0;
max-width: 100%;
}
.body > .admonition.note {
margin: 0 0 2em 0;
}
.body > .admonition.note .first {
display: none;
}
div.document {
text-align: left;
background-color: #333;
}
div.bodywrapper {
background: #111 url(images/bg.png);
border-left: 1px solid #333;
border-bottom: 1px solid #333;
margin: 0 18em 0 0;
}
div.body {
margin: 0;
padding: 0.5em 1.3em;
min-width: 20em;
}
div.related {
font-size: 1em;
background-color: #465158;
}
div.documentwrapper {
float: left;
width: 100%;
background-color: #333;
}
/* HEADINGS --------------------------------------------------------------- */
h1 {
margin: 0;
padding: 0 0 0.3em 0;
font-size: 2em;
line-height: 1.15;
color: #fff;
clear: both;
}
h2 {
margin: 2em 0 0.2em 0;
font-size: 1.35em;
padding: 0;
color: #fff;
}
.section h2 {
border-bottom: 3px solid #777;
margin-top: 2.5em
}
h3 {
margin: 1em 0 -0.3em 0;
font-size: 1.2em;
color: #fff;
}
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
color: #fff;
}
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
display: none;
margin: 0 0 0 0.3em;
padding: 0 0.2em 0 0.2em;
color: #333 !important;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
h5:hover a.anchor, h6:hover a.anchor {
display: inline;
}
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
h5 a.anchor:hover, h6 a.anchor:hover {
color: #777;
background-color: #eee;
}
/* LINKS ------------------------------------------------------------------ */
/* Normal links get a pseudo-underline */
a {
color: #0bc;
text-decoration: none;
}
a.reference, a.internal {
color: #abf;
}
a.reference em, a.internal em {
font-style: normal;
}
/* Links in sidebar, TOC, index trees and tables have no underline */
.sphinxsidebar a,
.toctree-wrapper a,
.indextable a,
#indices-and-tables a {
color: #0bc;
text-decoration: none;
border-bottom: none;
}
/* Most links get an underline-effect when hovered */
a:hover,
div.toctree-wrapper a:hover,
.indextable a:hover,
#indices-and-tables a:hover {
color: #2be;
text-decoration: none;
}
/*toctree dedicated styles*/
div.toctree-wrapper ul {
list-style-type: none;
padding-left: 2em;
}
div.toctree-wrapper ul ul {
margin-top: .5em;
}
div.toctree-wrapper li {
margin-bottom: .5em;
}
div.toctree-wrapper a, .toctree-wrapper a:visited {
padding: .2em .4em;
background-color: #555;
color:#fff;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
div.toctree-wrapper a:hover {
color: #eee;
background-color: #777;
}
/* Footer links */
div.footer a {
color: #0bc;
text-decoration: none;
border: none;
}
div.footer a:hover {
color: #2be;
border: none;
}
/* Permalink anchor (subtle grey with a red hover) */
div.body a.headerlink {
color: #ccc;
font-size: 1em;
margin-left: 6px;
padding: 0 4px 0 4px;
text-decoration: none;
border: none;
}
div.body a.headerlink:hover {
color: #fff;
border: none;
}
/* NAVIGATION BAR --------------------------------------------------------- */
div.related ul {
height: 2.5em;
min-height: 2.5em;
background-color: #2c2c2c;
background-image: -moz-linear-gradient(top, #333333, #222222);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
background-image: -webkit-linear-gradient(top, #333333, #222222);
background-image: -o-linear-gradient(top, #333333, #222222);
background-image: linear-gradient(to bottom, #333333, #222222);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff333333', endColorstr='#ff222222', GradientType=0);
border-bottom: 1px solid #222;
-moz-border-radius: 4px;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
*zoom: 1;
}
div.related ul li {
margin: 0;
padding: 0.65em 0;
float: left;
display: block;
color: white; /* For the >> separators */
font-size: 0.8em;
}
div.related ul li.right {
float: right;
margin-right: 5px;
color: transparent; /* Hide the | separators */
}
/* "Breadcrumb" links in nav bar */
div.related ul li a {
order: none;
background-color: inherit;
font-weight: bold;
margin: 6px 0 6px 4px;
line-height: 1.75em;
color: #ffffff;
padding: 0.4em 0.8em;
border: none;
border-radius: 3px;
}
/* previous / next / modules / index links look more like buttons */
div.related ul li.right a {
margin: 0.375em 0;
background-color: #555;
text-shadow: 0 1px rgba(0, 0, 0, 0.5);
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
/* All navbar links light up as buttons when hovered */
div.related ul li a:hover {
background-color: #777;
color: #fff;
text-decoration: none;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
/* Take extra precautions for tt within links */
a tt,
div.related ul li a tt {
background: inherit !important;
color: inherit !important;
}
.sphinxsidebar a tt span.pre {
color: #eee;
background-color: #444;
padding: 0 .5em;
border-radius: 4px;
}
.sphinxsidebar a:active tt span.pre {
color: #f66;
}
/* SIDEBAR ---------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 0;
}
div.sphinxsidebar {
margin: 0;
margin-left: -100%;
float: right;
top: 3em;
left: 0;
padding: 0 1em;
width: 18em;
font-size: 90%;
}
div.sphinxsidebar img {
max-width: 12em;
}
div.sphinxsidebar input[type="image"] {
display: inline;
float: none;
border: 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4,
div.sphinxsidebar p.logo {
margin: 1.2em 0 0.3em 0;
font-size: 1em;
padding: 0;
color: #fff;
font-family: Asap, Arial, "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif;
}
div.sphinxsidebar h3 a {
color: #fff;
}
div.sphinxsidebar ul,
div.sphinxsidebar p {
margin-top: 0;
padding-left: 0;
line-height: 130%;
}
/* No bullets for nested lists, but a little extra indentation */
div.sphinxsidebar ul ul {
list-style-type: none;
margin-left: 1.2em;
padding: 0;
}
/* A little top/bottom padding to prevent adjacent links' borders
* from overlapping each other */
div.sphinxsidebar ul li {
padding: 0;
margin: 2px 0;
}
/* A little left-padding to make these align with the ULs */
div.sphinxsidebar p.topless {
padding-left: 0 0 0 1em;
}
/* Make these into hidden one-liners */
div.sphinxsidebar ul li,
div.sphinxsidebar p.topless {
white-space: nowrap;
overflow: hidden;
border: 1px solid transparent; /* To prevent things jumping around on hover */
}
/* ...which become visible when hovered */
div.sphinxsidebar ul li:hover,
div.sphinxsidebar p.topless:hover {
background-color: #333;
overflow: visible;
}
/* Search text box and "Go" button */
#searchbox {
margin-top: 2em;
margin-bottom: 1em;
background: #666;
padding: 0.5em;
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
margin-right: 0;
}
#searchbox h3 {
margin-top: 0;
}
/* Make search box and button abut and have a border */
input,
div.sphinxsidebar input {
border: 1px solid #999;
float: left;
}
/* Search textbox */
input[type="text"] {
margin: 0;
padding: 0 3px;
height: 20px;
width: 144px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
-moz-border-radius-topleft: 3px;
-moz-border-radius-bottomleft: 3px;
-webkit-border-top-left-radius: 3px;
-webkit-border-bottom-left-radius: 3px;
}
/* Search button */
input[type="submit"] {
margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */
height: 22px;
color: #444;
background-color: #e8ecef;
padding: 1px 4px;
font-weight: bold;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
-moz-border-radius-topright: 3px;
-moz-border-radius-bottomright: 3px;
-webkit-border-top-right-radius: 3px;
-webkit-border-bottom-right-radius: 3px;
}
input[type="submit"]:hover {
color: #000;
background-color: #ddd;
}
div.sphinxsidebar p.searchtip {
clear: both;
padding: 0.5em 0 0 0;
color: #fff;
font-size: 0.9em;
}
/* Sidebar links are unusual */
div.sphinxsidebar li a,
div.sphinxsidebar p a {
color: #eee;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border: 1px solid transparent; /* To prevent things jumping around on hover */
padding: 0 5px 0 5px;
}
div.sphinxsidebar li a:hover,
div.sphinxsidebar p a:hover {
color: #fff;
background-color: #333;
}
div.sphinxsidebar p.logo a {
border: 0;
}
/* Tweak any link appearing in a heading */
div.sphinxsidebar h3 a {
}
/* OTHER STUFF ------------------------------------------------------------ */
/* labels */
.versionmodified {
font-style: normal;
}
.bookmarklet, .versionadded, .versionchanged {
display: inline-block;
padding: 4px 6px;
font-size: 13.536px;
font-weight: bold;
line-height: 14px;
color: #ffffff;
vertical-align: baseline;
white-space: nowrap;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: #999999;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
text-align: center;
font-style: normal;
}
.bookmarklet a, .versionadded a, .versionchanged a {
color: #fff;
}
.bookmarklet {
background-color: #2d6987;
}
.versionadded {
background-color: #468847;
}
div.admonition p.versionadded,
div.warning p.versionadded {
padding: 4px 6px;
}
.versionchanged {
background-color: #b04040;
}
div.admonition p.versionchanged,
div.warning p.versionchanged {
padding: 4px 6px;
}
/* Standard tags */
cite, code, tt {
font-family: 'Source Code Pro', 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.01em;
}
tt {
color: #f66;
background-color: #444;
padding: 0 5px;
font-size: 95%;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt {
padding: 0;
background: none;
}
tt.descname, tt.descclassname, tt.xref {
border: 0;
}
hr {
border-top: 1px solid #777;
border-bottom: none;
margin: 2em auto;
width: 50%;
}
pre, #_fontwidthtest {
font-family: 'Source Code Pro', 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
margin: 1em 2em;
font-size: 0.95em;
letter-spacing: 0.015em;
line-height: 120%;
padding: 0.5em;
border: 1px solid #ccc;
background-color: #eee;
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
}
pre a {
color: inherit;
text-decoration: underline;
}
td.linenos pre {
margin: 1em 0em;
}
td.code pre {
margin: 1em 0em;
}
div.quotebar {
background-color: #f8f8f8;
max-width: 250px;
float: right;
padding: 2px 7px;
border: 1px solid #ccc;
}
div.topic {
background-color: #333;
border: 0;
padding-bottom: .5em;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
}
table {
border-collapse: collapse;
margin: 0 -0.5em 0 -0.5em;
}
table td, table th {
padding: 0.2em 0.5em 0.2em 0.5em;
}
/* ADMONITIONS AND WARNINGS ------------------------------------------------- */
/* Shared by admonitions, warnings and sidebars */
div.admonition,
div.warning,
div.sidebar {
font-size: 0.9em;
margin: 2em;
padding: 0;
/*
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
*/
}
div.admonition p,
div.warning p,
div.sidebar p {
margin: 0.5em 1em 0.5em 1em;
padding: 0;
}
div.admonition pre,
div.warning pre,
div.sidebar pre {
margin: 0.4em 1em 0.4em 1em;
}
div.admonition p.admonition-title,
div.warning p.admonition-title,
div.sidebar p.sidebar-title {
margin: 0;
padding: 0.1em 0 0.1em 0.5em;
color: white;
font-weight: bold;
font-size: 1.1em;
text-shadow: 0 1px rgba(0, 0, 0, 0.5);
}
div.admonition ul, div.admonition ol,
div.warning ul, div.warning ol,
div.sidebar ul, div.sidebar ol {
margin: 0.1em 0.5em 0.5em 3em;
padding: 0;
}
/* Admonitions and sidebars only */
div.admonition, div.sidebar {
border: none;
background-color: #555;
color: #fff;
padding: .5em;
margin-bottom: 1em;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
div.admonition p.admonition-title,
div.sidebar p.sidebar-title {
padding-bottom: .5em;
border-bottom: 1px solid #888;
}
/* Warnings only */
div.warning {
background-color: #333;
}
div.warning p.admonition-title {
background-color: #b04040;
border-bottom: 1px solid #900000;
border-radius: 4px;
}
/* Sidebars only */
div.sidebar {
max-width: 30%;
}
div.versioninfo {
margin: 1em 0 0 0;
border: 1px solid #ccc;
background-color: #DDEAF0;
padding: 8px;
line-height: 1.3em;
font-size: 0.9em;
}
.viewcode-back {
font-family: Asap, 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
dl {
margin: 1em 0 2.5em 0;
}
/* Highlight target when you click an internal link */
dt:target {
background: #ffe080;
}
/* Don't highlight whole divs */
div.highlight {
background: transparent;
}
div.highlight pre,
div.highlight-javascript pre,
div.highlight-html pre {
background-color: #4b4b4b;
background-color: rgba(75, 75, 75, 0.5);
color: #eee;
font-size: 15px;
line-height: 21px;
white-space: pre;
overflow: auto;
border: none;
}
div.admonition pre {
background-color: #333;
}
/* But do highlight spans (so search results can be highlighted) */
span.highlight {
background: #111;
}
div.highlight .c1 {
color: #999;
}
div.highlight .cp {
color: #3aC;
}
div.highlight .s,
div.highlight .s1,
div.highlight .s2 {
color: orange;
}
div.highlight .kc {
color: red;
}
div.highlight .k,
div.highlight .kd {
color: #3aC;
}
div.highlight .nb {
color: #e88;
}
div.highlight .nx {
color: #fff;
}
div.highlight .p {
color: #eee;
}
div.footer {
color: #eeeeee;
padding: 1em 2em 1em 2em;
clear: both;
font-size: 0.8em;
text-align: center;
background-color: #222;
}
p {
margin: 0.8em 0 0.5em 0;
}
.section p img.math {
margin: 0;
}
.section p img {
margin: 1em 2em;
}
/* MOBILE LAYOUT -------------------------------------------------------------- */
@media screen and (max-width: 600px) {
h1, h2, h3, h4, h5 {
position: relative;
}
ul {
padding-left: 1.25em;
}
div.bodywrapper a.headerlink, #indices-and-tables h1 a {
color: #e6e6e6;
font-size: 80%;
float: right;
line-height: 1.8;
position: absolute;
right: -0.7em;
visibility: inherit;
}
div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a {
line-height: 1.5;
}
pre {
font-size: 0.7em;
overflow: auto;
word-wrap: break-word;
white-space: pre-wrap;
}
div.related ul {
height: 2.5em;
padding: 0;
text-align: left;
}
div.related ul li {
clear: both;
color: #465158;
padding: 0.2em 0;
}
div.related ul li:last-child {
border-bottom: 1px dotted #8ca1af;
padding-bottom: 0.4em;
margin-bottom: 1em;
width: 100%;
}
div.related ul li a {
color: #fff;
padding-right: 0;
}
div.related ul li a:hover {
background: inherit;
color: inherit;
}
div.related ul li.right {
clear: none;
padding: 0.65em 0;
margin-bottom: 0.5em;
}
div.related ul li.right a {
color: #fff;
padding-right: 0.8em;
}
div.related ul li.right a:hover {
background-color: #8ca1af;
}
div.body {
clear: both;
min-width: 0;
word-wrap: break-word;
}
div.bodywrapper {
margin: 0 0 0 0;
}
div.sphinxsidebar {
float: none;
margin: 0;
width: auto;
}
div.sphinxsidebar input[type="text"] {
height: 2em;
line-height: 2em;
width: 70%;
}
div.sphinxsidebar input[type="submit"] {
height: 2em;
margin-left: 0.5em;
width: 20%;
}
div.sphinxsidebar p.searchtip {
background: inherit;
margin-bottom: 1em;
}
div.sphinxsidebar ul li, div.sphinxsidebar p.topless {
white-space: normal;
}
.bodywrapper img {
display: block;
margin-left: auto;
margin-right: auto;
max-width: 100%;
}
div.documentwrapper {
float: none;
}
div.admonition, div.warning, pre, blockquote {
margin-left: 0em;
margin-right: 0em;
}
.body p img {
margin: 0;
}
#searchbox {
background: transparent;
}
.related:not(:first-child) li {
display: none;
}
.related:not(:first-child) li.right {
display: block;
}
div.footer {
padding: 1em;
}
.rtd_doc_footer .rtd-badge {
float: none;
margin: 1em auto;
position: static;
}
.rtd_doc_footer .rtd-badge.revsys-inline {
margin-right: auto;
margin-bottom: 2em;
}
table.indextable {
display: block;
width: auto;
}
.indextable tr {
display: block;
}
.indextable td {
display: block;
padding: 0;
width: auto !important;
}
.indextable td dt {
margin: 1em 0;
}
ul.search {
margin-left: 0.25em;
}
ul.search li div.context {
font-size: 90%;
line-height: 1.1;
margin-bottom: 1;
margin-left: 0;
}
}
.donate {
text-align: center;
}
.donate .flattr {
margin-top: 1.5em;
}
/*
* rtd.css
* ~~~~~~~~~~~~~~~
*
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
* Armin Ronacher for Werkzeug.
*
* Customized for ReadTheDocs by Eric Pierce & Eric Holscher
*
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* RTD colors
* light blue: #e8ecef
* medium blue: #8ca1af
* dark blue: #465158
* dark grey: #444444
*
* white hover: #d1d9df;
* medium blue hover: #697983;
* green highlight: #8ecc4c
* light blue (project bar): #e8ecef
*/
@import url("basic.css");
/* PAGE LAYOUT -------------------------------------------------------------- */
body {
font: 100%/1.5 "ff-meta-web-pro-1","ff-meta-web-pro-2",Arial,"Helvetica Neue",sans-serif;
text-align: center;
color: black;
background-color: #465158;
padding: 0;
margin: 0;
}
img {
border: 0;
max-width: 100%;
}
div.document {
text-align: left;
background-color: #e8ecef;
}
div.bodywrapper {
background-color: #ffffff;
border-left: 1px solid #ccc;
border-bottom: 1px solid #ccc;
margin: 0 0 0 16em;
}
div.body {
margin: 0;
padding: 0.5em 1.3em;
min-width: 20em;
}
div.related {
font-size: 1em;
background-color: #465158;
}
div.documentwrapper {
float: left;
width: 100%;
background-color: #e8ecef;
}
/* HEADINGS --------------------------------------------------------------- */
h1 {
margin: 0;
padding: 0.7em 0 0.3em 0;
font-size: 1.5em;
line-height: 1.15;
color: #111;
clear: both;
}
h2 {
margin: 2em 0 0.2em 0;
font-size: 1.35em;
padding: 0;
color: #465158;
}
h3 {
margin: 1em 0 -0.3em 0;
font-size: 1.2em;
color: #6c818f;
}
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
color: black;
}
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
display: none;
margin: 0 0 0 0.3em;
padding: 0 0.2em 0 0.2em;
color: #aaa !important;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
h5:hover a.anchor, h6:hover a.anchor {
display: inline;
}
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
h5 a.anchor:hover, h6 a.anchor:hover {
color: #777;
background-color: #eee;
}
/* LINKS ------------------------------------------------------------------ */
/* Normal links get a pseudo-underline */
a {
color: #444;
text-decoration: none;
border-bottom: 1px solid #ccc;
}
/* Links in sidebar, TOC, index trees and tables have no underline */
.sphinxsidebar a,
.toctree-wrapper a,
.indextable a,
#indices-and-tables a {
color: #444;
text-decoration: none;
border-bottom: none;
}
/* Most links get an underline-effect when hovered */
a:hover,
div.toctree-wrapper a:hover,
.indextable a:hover,
#indices-and-tables a:hover {
color: #111;
text-decoration: none;
border-bottom: 1px solid #111;
}
/* Footer links */
div.footer a {
color: #86989B;
text-decoration: none;
border: none;
}
div.footer a:hover {
color: #a6b8bb;
text-decoration: underline;
border: none;
}
/* Permalink anchor (subtle grey with a red hover) */
div.body a.headerlink {
color: #ccc;
font-size: 1em;
margin-left: 6px;
padding: 0 4px 0 4px;
text-decoration: none;
border: none;
}
div.body a.headerlink:hover {
color: #c60f0f;
border: none;
}
/* NAVIGATION BAR --------------------------------------------------------- */
div.related ul {
height: 2.5em;
}
div.related ul li {
margin: 0;
padding: 0.65em 0;
float: left;
display: block;
color: white; /* For the >> separators */
font-size: 0.8em;
}
div.related ul li.right {
float: right;
margin-right: 5px;
color: transparent; /* Hide the | separators */
}
/* "Breadcrumb" links in nav bar */
div.related ul li a {
order: none;
background-color: inherit;
font-weight: bold;
margin: 6px 0 6px 4px;
line-height: 1.75em;
color: #ffffff;
padding: 0.4em 0.8em;
border: none;
border-radius: 3px;
}
/* previous / next / modules / index links look more like buttons */
div.related ul li.right a {
margin: 0.375em 0;
background-color: #697983;
text-shadow: 0 1px rgba(0, 0, 0, 0.5);
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
/* All navbar links light up as buttons when hovered */
div.related ul li a:hover {
background-color: #8ca1af;
color: #ffffff;
text-decoration: none;
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
}
/* Take extra precautions for tt within links */
a tt,
div.related ul li a tt {
background: inherit !important;
color: inherit !important;
}
/* SIDEBAR ---------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 0;
}
div.sphinxsidebar {
margin: 0;
margin-left: -100%;
float: left;
top: 3em;
left: 0;
padding: 0 1em;
width: 14em;
font-size: 1em;
text-align: left;
background-color: #e8ecef;
}
div.sphinxsidebar img {
max-width: 12em;
}
div.sphinxsidebar input[type="image"] {
display: inline;
float: none;
border: 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4,
div.sphinxsidebar p.logo {
margin: 1.2em 0 0.3em 0;
font-size: 1em;
padding: 0;
color: #222222;
font-family: "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif;
}
div.sphinxsidebar h3 a {
color: #444444;
}
div.sphinxsidebar ul,
div.sphinxsidebar p {
margin-top: 0;
padding-left: 0;
line-height: 130%;
background-color: #e8ecef;
}
/* No bullets for nested lists, but a little extra indentation */
div.sphinxsidebar ul ul {
list-style-type: none;
margin-left: 1.5em;
padding: 0;
}
/* A little top/bottom padding to prevent adjacent links' borders
* from overlapping each other */
div.sphinxsidebar ul li {
padding: 1px 0;
}
/* A little left-padding to make these align with the ULs */
div.sphinxsidebar p.topless {
padding-left: 0 0 0 1em;
}
/* Make these into hidden one-liners */
div.sphinxsidebar ul li,
div.sphinxsidebar p.topless {
white-space: nowrap;
overflow: hidden;
}
/* ...which become visible when hovered */
div.sphinxsidebar ul li:hover,
div.sphinxsidebar p.topless:hover {
overflow: visible;
}
/* Search text box and "Go" button */
#searchbox {
margin-top: 2em;
margin-bottom: 1em;
background: #ddd;
padding: 0.5em;
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
}
#searchbox h3 {
margin-top: 0;
}
/* Make search box and button abut and have a border */
input,
div.sphinxsidebar input {
border: 1px solid #999;
float: left;
}
/* Search textbox */
input[type="text"] {
margin: 0;
padding: 0 3px;
height: 20px;
width: 144px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
-moz-border-radius-topleft: 3px;
-moz-border-radius-bottomleft: 3px;
-webkit-border-top-left-radius: 3px;
-webkit-border-bottom-left-radius: 3px;
}
/* Search button */
input[type="submit"] {
margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */
height: 22px;
color: #444;
background-color: #e8ecef;
padding: 1px 4px;
font-weight: bold;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
-moz-border-radius-topright: 3px;
-moz-border-radius-bottomright: 3px;
-webkit-border-top-right-radius: 3px;
-webkit-border-bottom-right-radius: 3px;
}
input[type="submit"]:hover {
color: #ffffff;
background-color: #8ecc4c;
}
div.sphinxsidebar p.searchtip {
clear: both;
padding: 0.5em 0 0 0;
background: #ddd;
color: #666;
font-size: 0.9em;
}
/* Sidebar links are unusual */
div.sphinxsidebar li a,
div.sphinxsidebar p a {
background: #e8ecef; /* In case links overlap main content */
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border: 1px solid transparent; /* To prevent things jumping around on hover */
padding: 0 5px 0 5px;
}
div.sphinxsidebar li a:hover,
div.sphinxsidebar p a:hover {
color: #111;
text-decoration: none;
border: 1px solid #888;
}
div.sphinxsidebar p.logo a {
border: 0;
}
/* Tweak any link appearing in a heading */
div.sphinxsidebar h3 a {
}
/* OTHER STUFF ------------------------------------------------------------ */
cite, code, tt {
font-family: 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.01em;
}
tt {
background-color: #f2f2f2;
color: #444;
}
tt.descname, tt.descclassname, tt.xref {
border: 0;
}
hr {
border: 1px solid #abc;
margin: 2em;
}
pre, #_fontwidthtest {
font-family: 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
margin: 1em 2em;
font-size: 0.95em;
letter-spacing: 0.015em;
line-height: 120%;
padding: 0.5em;
border: 1px solid #ccc;
background-color: #eee;
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
}
pre a {
color: inherit;
text-decoration: underline;
}
td.linenos pre {
margin: 1em 0em;
}
td.code pre {
margin: 1em 0em;
}
div.quotebar {
background-color: #f8f8f8;
max-width: 250px;
float: right;
padding: 2px 7px;
border: 1px solid #ccc;
}
div.topic {
background-color: #f8f8f8;
}
table {
border-collapse: collapse;
margin: 0 -0.5em 0 -0.5em;
}
table td, table th {
padding: 0.2em 0.5em 0.2em 0.5em;
}
/* ADMONITIONS AND WARNINGS ------------------------------------------------- */
/* Shared by admonitions, warnings and sidebars */
div.admonition,
div.warning,
div.sidebar {
font-size: 0.9em;
margin: 2em;
padding: 0;
/*
border-radius: 6px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
*/
}
div.admonition p,
div.warning p,
div.sidebar p {
margin: 0.5em 1em 0.5em 1em;
padding: 0;
}
div.admonition pre,
div.warning pre,
div.sidebar pre {
margin: 0.4em 1em 0.4em 1em;
}
div.admonition p.admonition-title,
div.warning p.admonition-title,
div.sidebar p.sidebar-title {
margin: 0;
padding: 0.1em 0 0.1em 0.5em;
color: white;
font-weight: bold;
font-size: 1.1em;
text-shadow: 0 1px rgba(0, 0, 0, 0.5);
}
div.admonition ul, div.admonition ol,
div.warning ul, div.warning ol,
div.sidebar ul, div.sidebar ol {
margin: 0.1em 0.5em 0.5em 3em;
padding: 0;
}
/* Admonitions and sidebars only */
div.admonition, div.sidebar {
border: 1px solid #609060;
background-color: #e9ffe9;
}
div.admonition p.admonition-title,
div.sidebar p.sidebar-title {
background-color: #70A070;
border-bottom: 1px solid #609060;
}
/* Warnings only */
div.warning {
border: 1px solid #900000;
background-color: #ffe9e9;
}
div.warning p.admonition-title {
background-color: #b04040;
border-bottom: 1px solid #900000;
}
/* Sidebars only */
div.sidebar {
max-width: 30%;
}
div.versioninfo {
margin: 1em 0 0 0;
border: 1px solid #ccc;
background-color: #DDEAF0;
padding: 8px;
line-height: 1.3em;
font-size: 0.9em;
}
.viewcode-back {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
dl {
margin: 1em 0 2.5em 0;
}
/* Highlight target when you click an internal link */
dt:target {
background: #ffe080;
}
/* Don't highlight whole divs */
div.highlight {
background: transparent;
}
/* But do highlight spans (so search results can be highlighted) */
span.highlight {
background: #ffe080;
}
div.footer {
background-color: #465158;
color: #eeeeee;
padding: 0 2em 2em 2em;
clear: both;
font-size: 0.8em;
text-align: center;
}
p {
margin: 0.8em 0 0.5em 0;
}
.section p img.math {
margin: 0;
}
.section p img {
margin: 1em 2em;
}
/* MOBILE LAYOUT -------------------------------------------------------------- */
@media screen and (max-width: 600px) {
h1, h2, h3, h4, h5 {
position: relative;
}
ul {
padding-left: 1.25em;
}
div.bodywrapper a.headerlink, #indices-and-tables h1 a {
color: #e6e6e6;
font-size: 80%;
float: right;
line-height: 1.8;
position: absolute;
right: -0.7em;
visibility: inherit;
}
div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a {
line-height: 1.5;
}
pre {
font-size: 0.7em;
overflow: auto;
word-wrap: break-word;
white-space: pre-wrap;
}
div.related ul {
height: 2.5em;
padding: 0;
text-align: left;
}
div.related ul li {
clear: both;
color: #465158;
padding: 0.2em 0;
}
div.related ul li:last-child {
border-bottom: 1px dotted #8ca1af;
padding-bottom: 0.4em;
margin-bottom: 1em;
width: 100%;
}
div.related ul li a {
color: #465158;
padding-right: 0;
}
div.related ul li a:hover {
background: inherit;
color: inherit;
}
div.related ul li.right {
clear: none;
padding: 0.65em 0;
margin-bottom: 0.5em;
}
div.related ul li.right a {
color: #fff;
padding-right: 0.8em;
}
div.related ul li.right a:hover {
background-color: #8ca1af;
}
div.body {
clear: both;
min-width: 0;
word-wrap: break-word;
}
div.bodywrapper {
margin: 0 0 0 0;
}
div.sphinxsidebar {
float: none;
margin: 0;
width: auto;
}
div.sphinxsidebar input[type="text"] {
height: 2em;
line-height: 2em;
width: 70%;
}
div.sphinxsidebar input[type="submit"] {
height: 2em;
margin-left: 0.5em;
width: 20%;
}
div.sphinxsidebar p.searchtip {
background: inherit;
margin-bottom: 1em;
}
div.sphinxsidebar ul li, div.sphinxsidebar p.topless {
white-space: normal;
}
.bodywrapper img {
display: block;
margin-left: auto;
margin-right: auto;
max-width: 100%;
}
div.documentwrapper {
float: none;
}
div.admonition, div.warning, pre, blockquote {
margin-left: 0em;
margin-right: 0em;
}
.body p img {
margin: 0;
}
#searchbox {
background: transparent;
}
.related:not(:first-child) li {
display: none;
}
.related:not(:first-child) li.right {
display: block;
}
div.footer {
padding: 1em;
}
.rtd_doc_footer .rtd-badge {
float: none;
margin: 1em auto;
position: static;
}
.rtd_doc_footer .rtd-badge.revsys-inline {
margin-right: auto;
margin-bottom: 2em;
}
table.indextable {
display: block;
width: auto;
}
.indextable tr {
display: block;
}
.indextable td {
display: block;
padding: 0;
width: auto !important;
}
.indextable td dt {
margin: 1em 0;
}
ul.search {
margin-left: 0.25em;
}
ul.search li div.context {
font-size: 90%;
line-height: 1.1;
margin-bottom: 1;
margin-left: 0;
}
}
.donate {
text-align: center;
}
.donate .flattr {
margin-top: 1.5em;
}
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #303030 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .nx { color: #111111 } /* Std */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
/* https://github.com/n1k0/casperjs-docs/issues/2 */
#casperjs-documentation img {
-webkit-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5));
-moz-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5));
-ms-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5));
-o-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5));
filter: drop-shadow(0 1px 20px rgba(0,0,0,.5));
}
/**
* 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 ;)
.. _events_filters:
Events & filters
================
CasperJS provides an `event handler <#events>`_ very similar to the `nodejs <http://nodejs.org>`_' `one <https://github.com/joyent/node/blob/master/lib/events.js>`_; actually it borrows most of its codebase. CasperJS also adds `filters <#filters>`_, which are basically ways to alter values asynchronously.
.. index:: ! events
Events
------
Using events is pretty much straightforward if you're a node developer, or if you worked with any evented system before::
var casper = require('casper').create();
casper.on('resource.received', function(resource) {
casper.echo(resource.url);
});
Emitting you own events
+++++++++++++++++++++++
Of course you can emit your own events, using the ``Casper.emit()`` method::
var casper = require('casper').create();
// listening to a custom event
casper.on('google.loaded', function() {
this.echo('Google page title is ' + this.getTitle());
});
casper.start('http://google.com/', function() {
// emitting a custom event
this.emit('google.loaded');
});
casper.run();
.. _events_list:
Events reference
++++++++++++++++
``back``
~~~~~~~~
**Arguments:** ``None``
Emitted when the embedded browser is asked to go back a step in its history.
``capture.saved``
~~~~~~~~~~~~~~~~~
**Arguments:** ``targetFile``
Emitted when a :index:`screenshot` image has been captured.
.. index:: click
``click``
~~~~~~~~~
**Arguments:** ``selector``
Emitted when the ``Casper.click()`` method has been called.
``die``
~~~~~~~
**Arguments:** ``message, status``
Emitted when the ``Casper.die()`` method has been called.
.. index:: download
``downloaded.file``
~~~~~~~~~~~~~~~~~~~
**Arguments:** ``targetPath``
Emitted when a file has been downloaded by :ref:`Casper.download() <casper_download>`; ``target`` will contain the path to the downloaded file.
.. index:: error
``error``
~~~~~~~~~
**Arguments:** ``msg, backtrace``
.. versionadded:: 0.6.9
Emitted when an error hasn't been caught. Do basically what PhantomJS' ``onError()`` native handler does.
.. index:: exit
``exit``
~~~~~~~~
**Arguments:** ``status``
Emitted when the ``Casper.exit()`` method has been called.
.. index:: fill
``fill``
~~~~~~~~
**Arguments:** ``selector, vals, submit``
Emitted when a form is filled using the ``Casper.fill()`` method.
``forward``
~~~~~~~~~~~
**Arguments:** ``None``
Emitted when the embedded browser is asked to go forward a step in its history.
.. index:: auth
``http.auth``
~~~~~~~~~~~~~
**Arguments:** ``username, password``
Emitted when http authentication parameters are set.
.. index:: HTTP
``http.status.[code]``
~~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``resource``
Emitted when any given HTTP reponse is received with the status code specified by ``[code]``, eg.::
casper.on('http.status.404', function(resource) {
casper.echo(resource.url + ' is 404');
})
``load.started``
~~~~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when PhantomJS' ``WebPage.onLoadStarted`` event callback is called.
``load.failed``
~~~~~~~~~~~~~~~
**Arguments:** ``Object``
Emitted when PhantomJS' ``WebPage.onLoadFinished`` event callback has been called and failed.
``load.finished``
~~~~~~~~~~~~~~~~~
**Arguments:** ``status``
Emitted when PhantomJS' ``WebPage.onLoadFinished`` event callback is called.
.. index:: log
``log``
~~~~~~~
**Arguments:** ``entry``
Emitted when the ``Casper.log()`` method has been called. The ``entry`` parameter is an Object like this::
{
level: "debug",
space: "phantom",
message: "A message",
date: "a javascript Date instance"
}
..index:: click
``mouse.click``
~~~~~~~~~~~~~~~
**Arguments:** ``args``
Emitted when the mouse left-click something or somewhere.
``mouse.down``
~~~~~~~~~~~~~~
**Arguments:** ``args``
Emitted when the mouse presses on something or somewhere with the left button.
``mouse.move``
~~~~~~~~~~~~~~
**Arguments:** ``args``
Emitted when the mouse moves onto something or somewhere.
``mouse.up``
~~~~~~~~~~~~
**Arguments:** ``args``
Emitted when the mouse releases the left button over something or somewhere.
``navigation.requested``
~~~~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``url, navigationType, navigationLocked, isMainFrame``
.. versionadded:: 1.0
Emitted each time a navigation operation has been requested. Available navigation types are: ``LinkClicked``, ``FormSubmitted``, ``BackOrForward``, ``Reload``, ``FormResubmitted`` and ``Other``.
.. index:: HTTP
``open``
~~~~~~~~
``location, settings``
Emitted when an HTTP request is sent. First callback arg is the location, second one is a request settings Object of the form::
{
method: "post",
data: "foo=42&chuck=norris"
}
``page.created``
~~~~~~~~~~~~~~~~
**Arguments:** ``page``
Emitted when PhantomJS' ``WebPage`` object used by CasperJS has been created.
``page.error``
~~~~~~~~~~~~~~
**Arguments:** ``message, trace``
Emitted when retrieved page leaved a Javascript error uncaught::
casper.on("page.error", function(msg, trace) {
this.echo("Error: " + msg, "ERROR");
});
``page.initialized``
~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``WebPage``
Emitted when PhantomJS' ``WebPage`` object used by CasperJS has been initialized.
.. index:: HTTP
``page.resource.received``
~~~~~~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``response``
Emitted when the HTTP response corresponding to current required url has been received.
.. index:: HTTP
``page.resource.requested``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``request``
Emitted when a new HTTP request is performed to open the required url.
``popup.created``
~~~~~~~~~~~~~~~~~
**Arguments:** ``WebPage``
Emitted when a new window has been opened.
``popup.loaded``
~~~~~~~~~~~~~~~~
**Arguments:** ``WebPage``
Emitted when a new window has been loaded.
``popup.closed``
~~~~~~~~~~~~~~~~
**Arguments:** ``WebPage``
Emitted when a new opened window has been closed.
``popup.created``
~~~~~~~~~~~~~~~~~
**Arguments:** ``WebPage``
Emitted when a new window has been opened.
``remote.alert``
~~~~~~~~~~~~~~~~
**Arguments:** ``message``
Emitted when a remote ``alert()`` call has been performed.
``remote.message``
~~~~~~~~~~~~~~~~~~
**Arguments:** ``msg``
Emitted when any remote console logging call has been performed.
``resource.received``
~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``resource``
Emitted when any resource has been received.
``resource.requested``
~~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``request``
Emitted when any resource has been requested.
``run.complete``
~~~~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when the whole series of steps in the stack have been executed.
``run.start``
~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when ``Casper.run()`` is called.
``starting``
~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when ``Casper.start()`` is called.
``started``
~~~~~~~~~~~
**Arguments:** ``None``
Emitted when Casper has been started using ``Casper.start()``.
``step.added``
~~~~~~~~~~~~~~
**Arguments:** ``step``
Emitted when a new navigation step has been added to the stack.
``step.complete``
~~~~~~~~~~~~~~~~~
**Arguments:** ``stepResult``
Emitted when a navigation step has been executed.
``step.created``
~~~~~~~~~~~~~~~~
**Arguments:** ``fn``
Emitted when a new navigation step has been created.
``step.start``
~~~~~~~~~~~~~~
**Arguments:** ``step``
Emitted when a navigation step has been started.
``step.timeout``
~~~~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when a navigation step has been executed.
``timeout``
~~~~~~~~~~~
**Arguments:** ``None``
Emitted when the execution time of the script has reached the ``Casper.options.timeout`` value.
``url.changed``
~~~~~~~~~~~~~~~
**Arguments:** ``url``
.. versionadded:: 1.0
Emitted each time the current page url changes.
.. index:: viewport
``viewport.changed``
~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``[width, height]``
Emitted when the viewport has been changed.
``wait.done``
~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when a ``Casper.wait()``\ *operation ends.*
``wait.start``
~~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when a ``Casper.wait()`` operation starts.
``waitFor.timeout``
~~~~~~~~~~~~~~~~~~~
**Arguments:** ``None``
Emitted when the execution time of a ``Casper.wait*()`` operation has exceeded the value of ``Casper.options.stepTimeout``.
.. index:: filters
Filters
-------
Filters allow you to alter some values asynchronously. Sounds obscure? Let's take a simple example and imagine you would like to alter every single url opened by CasperJS to append a ``foo=42`` query string parameter::
var casper = require('casper').create();
casper.setFilter('open.location', function(location) {
return /\?+/.test(location) ? location += "&foo=42" : location += "?foo=42";
});
There you have it, every single requested url will have this appended. Let me bet you'll find far more interesting use cases than my silly one ;)
Here'a the list of all available filters with their expected return value:
Filters reference
+++++++++++++++++
.. index:: screenshot
``capture.target_filename``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Arguments:** ``args``
**Return type:** ``String``
Allows to alter the value of the filename where a screen capture should be stored.
``echo.message``
~~~~~~~~~~~~~~~~
**Arguments:** ``message``
**Return type:** ``String``
Allows to alter every message written onto stdout.
``log.message``
~~~~~~~~~~~~~~~
**Arguments:** ``message``
**Return type:** ``String``
Allows to alter every log message.
``open.location``
~~~~~~~~~~~~~~~~~
**Arguments:** ``args``
**Return type:** ``String``
Allows to alter every url before it being opened.
``page.confirm``
~~~~~~~~~~~~~~~~
**Arguments:** ``message``
**Return type:** ``Boolean``
.. versionadded:: 1.0
Allows to react on a javascript ``confirm()`` call::
casper.setFilter("page.confirm", function(msg) {
return msg === "Do you like vbscript?" ? false : true;
});
``page.prompt``
~~~~~~~~~~~~~~~
**Arguments:** ``message, value``
**Return type:** ``String``
.. versionadded:: 1.0
Allows to react on a javascript ``prompt()`` call::
casper.setFilter("page.prompt", function(msg, value) {
if (msg === "What's your name?") {
return "Chuck";
}
});
.. _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()
.. _faq:
.. index:: FAQ, Help
===
FAQ
===
.. contents:: Here's a selection of the most frequently asked questions by CasperJS newcomers:
:local:
:backlinks: top
.. index:: Node.js
Is CasperJS a `node.js <http://nodejs.org/>`_ library?
------------------------------------------------------
**No.** CasperJS is written on top of PhantomJS_, which is a node-independent Qt_/WebKit_ based library. If you try to run your CasperJS script with node, it just won't work out of the box.
.. hint:: If you want to drive CasperJS from node, try `SpookyJS <https://github.com/WaterfallEngineering/SpookyJS>`_.
.. index:: Bugs, Contributing, error
I'm stuck! I think there's a bug! What can I do?
------------------------------------------------
Before rage-tweeting:
1. Read the `docs <http://casperjs.org/>`_
2. Check if an `issue <https://github.com/n1k0/casperjs/issues>`_ has been open about your problem already
3. Check you're running the `latest stable tag <https://github.com/n1k0/casperjs/tags>`_
4. Check you're running the `latest version <http://code.google.com/p/phantomjs/downloads/list>`_ of PhantomJS_
5. Ask on the `project mailing list <https://groups.google.com/forum/#!forum/casperjs>`_:
a. try to post a reproducible, minimal test case
b. compare casperjs results with native phantomjs ones
c. if the problem also occurs with native phantomjs, ask on `phantomjs mailing list <https://groups.google.com/forum/#!forum/phantomjs>`_
6. Eventually, `file an issue <https://github.com/n1k0/casperjs/issues/new>`_.
.. index:: Testing
The ``casper.test`` property is undefined, I can't write any test!
------------------------------------------------------------------
That's because as of 1.1, the ``casper.test`` property is only set to a :doc:`Tester <modules/tester>` instance when using the ``casperjs test`` subcommand.
You may want to read the :doc:`testing documentation <testing>` for more information.
.. index:: Code reuse
I keep copy and pasting stuff in my test scripts, that's boring
---------------------------------------------------------------
Have a look at `this gist <https://gist.github.com/3813361>`_, it might help.
Also, don't forget that CasperJS supports a `CommonJS-compliant module pattern <http://wiki.commonjs.org/wiki/Modules/1.1>`_ implementation.
.. note::
CasperJS' implementation of ``require()`` differs a bit from the one provided by PhantomJS_, but I personnaly never really encountered any functional difference.
.. index:: Versionning
What is the versioning policy of CasperJS?
------------------------------------------
Releases will follow the `SemVer standard <http://semver.org/>`_; they
will be numbered with the follow format:
.. code-block:: text
<major>.<minor>.<patch>[-<identifier>]
And constructed with the following guidelines:
- Breaking backwards compatibility bumps the major
- New additions without breaking backwards compatibility bumps the minor
- Bug fixes and misc changes bump the patch
- Unstable, special and trunk versions will have a proper identifier
.. index:: jQuery
Can I use jQuery with CasperJS?
-------------------------------
Sure, you can use `jQuery <http://jquery.com/>`_, as every single other javascript library on Earth.
A first solution is to inject it into the remote DOM environment by hand using the standard ``WebPage.injectJs()`` method::
casper.page.injectJs('/path/to/jquery.js');
If you need jQuery being available everytime, you can also make it being injected in every received response by setting the ``clientScripts`` option of CasperJS::
var casper = require('casper').create({
clientScripts: ["includes/jquery.min.js"]
});
.. note::
You can't *inject* scripts using the HTTP protocol, you actually have to use a relative/absolute filesystem path to the script resource.
.. index:: Windows, Python, Ruby
Can I use CasperJS without using the ``casperjs`` executable?
-------------------------------------------------------------
Yes, you can call a CasperJS script directly with the ``phantomjs``
executable, but if you do so, you must set the ``phantom.casperPath``
property to the path where the library root is located on your system::
// casperscript.js
phantom.casperPath = '/path/to/casperjs';
phantom.injectJs(phantom.casperPath + '/bin/bootstrap.js');
var casper = require('casper').create();
// ...
You can run such a script like any other standard PhantomJS_ script::
$ phantomjs casperscript.js
**If you're on Windows**, this is the way you may manage to get casper
working the most easily::
phantom.casperPath = 'C:\\path\\to\\your\\repo\\lib\\casperjs-0.6.X';
phantom.injectJs(phantom.casperPath + '\\bin\\bootstrap.js');
var casper = require('casper').create();
// do stuff
.. index:: HTTP
How can I catch HTTP 404 and other status codes?
------------------------------------------------
You can define your own `HTTP status
code <http://en.wikipedia.org/wiki/List_of_HTTP_status_codes>`_ handlers
by using the ``httpStatusHandlers`` option of the Casper object. You can
also catch other HTTP status codes as well, as demoed below::
var casper = require('casper').create();
casper.on('http.status.404', function(resource) {
this.echo('wait, this url is 404: ' + resource.url);
});
casper.on('http.status.500', function(resource) {
this.echo('woops, 500 error: ' + resource.url);
});
casper.start('http://mywebsite/404', function() {
this.echo('We suppose this url return an HTTP 404');
});
casper.thenOpen('http://mywebsite/500', function() {
this.echo('We suppose this url return an HTTP 500');
});
casper.run(function() {
this.echo('Done.').exit();
});
.. hint::
Check out all the other cool :doc:`events <events-filters>` you may use as well.
.. index:: log, Logging
Where does CasperJS write its logfile?
--------------------------------------
Nowhere. CasperJS doesn't write logs on the filesystem. You have to implement this by yourself if needed.
.. index:: __utils__, AJAX
What's this mysterious ``__utils__`` object?
--------------------------------------------
The ``__utils__`` object is actually a :ref:`ClientUtils object <clientutils_prototype>` which have been automatically injected into the page DOM and is therefore alway available.
So everytime to perform an :ref:`evaluate() <casper_evaluate>` call, you have this instance available to perform common operation like:
- fetching nodes using CSS3 or XPath selectors,
- retrieving information about element properties (attributes, size, bounds, etc.),
- sending AJAX requests,
- triggering DOM events
Check out the :doc:`whole API <modules/clientutils>`. You even have :ref:`a bookmarklet <bookmarklet>` to play around with this ``__utils__`` instance right within your browser console!
.. note::
You're not obliged at all to use the ``__utils__`` instance in your scripts. It's just there because it's used by CasperJS internals.
.. index:: Step stack, Asynchronicity
How does ``then()`` and the step stack work?
--------------------------------------------
Disclaimer This entry is based on an `answer I made on Stack Overflow <http://stackoverflow.com/a/11957919/330911>`_.
The ``then()`` method basically adds a new navigation step in a stack. A step is a javascript function which can do two different things:
1. waiting for the previous step - if any - being executed
2. waiting for a requested url and related page to load
Let's take a simple navigation scenario::
var casper = require('casper').create();
casper.start();
casper.then(function step1() {
this.echo('this is step one');
});
casper.then(function step2() {
this.echo('this is step two');
});
casper.thenOpen('http://google.com/', function step3() {
this.echo('this is step 3 (google.com is loaded)');
});
You can print out all the created steps within the stack like this::
require('utils').dump(casper.steps.map(function(step) {
return step.toString();
}));
That gives::
$ casperjs test-steps.js
[
"function step1() { this.echo('this is step one'); }",
"function step2() { this.echo('this is step two'); }",
"function _step() { this.open(location, settings); }",
"function step3() { this.echo('this is step 3 (google.com is loaded)'); }"
]
Notice the ``_step()`` function which has been added automatically by CasperJS to load the url for us; when the url is loaded, the next step available in the stack — which is ``step3()`` — is *then* called.
When you have defined your navigation steps, ``run()`` executes them one by one sequentially::
casper.run();
.. note:: The callback/listener stuff is an implementation of the `Promise pattern <http://blog.thepete.net/blog/2011/07/02/javascript-promises/>`_.
Is it possible to achieve parallel browsing using CasperJS?
-----------------------------------------------------------
`Officially no <https://groups.google.com/d/topic/casperjs/Scx4Cjqp7hE/discussion>`_, but you may want to try.
Can I access & manipulate DOM elements directly from the CasperJS environment?
------------------------------------------------------------------------------
No. Like in PhantomJS, you have to use :ref:`Casper#evaluate() <casper_evaluate>` to access actual page DOM and manipulate elements.
For example, you **can't** do this::
// this won't work
casper.then(function() {
var titleNode = document.querySelector('h1');
this.echo('Title is: ' + titleNode.textContent);
titleNode.textContent = 'New title';
this.echo('Title is now: ' + titleNode.textContent);
});
You have to use the :ref:`Casper#evaluate() <casper_evaluate>` method in order to communicate with the page DOM::
// this will
casper.then(function() {
var titleText = this.evaluate(function() {
return document.querySelector('h1').textContent;
});
this.echo('Title is: ' + titleText);
this.evaluate(function() {
document.querySelector('h1').textContent = 'New title';
});
this.echo('Title is now: ' + this.evaluate(function() {
return document.querySelector('h1').textContent;
}));
});
Of course, it's a whole lot more verbose, but Casper provides convenient methods to ease accessing elements properties, eg. :ref:`Casper#fetchText() <casper_fetchtext>` and :ref:`Casper#getElementInfo() <casper_getelementinfo>`::
// this will
casper.then(function() {
this.echo('Title is: ' + this.fetchText('h1'));
this.evaluate(function() {
document.querySelector('h1').textContent = 'New title';
});
this.echo('Element HTML is now: ' + this.getElementInfo('h1').html);
});
.. _faq_javascript:
Okay, honestly, I'm stuck with Javascript.
------------------------------------------
Don't worry, you're not alone. Javascript is a great language, but it's far more difficult to master than one might expect at first look.
Here are some great resources to get started efficiently with the language:
- Learn and practice Javascript online at `Code Academy <http://www.codecademy.com/tracks/javascript>`_
- `Eloquent Javascript <http://eloquentjavascript.net/contents.html>`_
- `JavaScript Enlightenment <http://www.javascriptenlightenment.com/JavaScript_Enlightenment.pdf>`_ (PDF)
- last, a `great tutorial on Advanced Javascript Techniques <http://ejohn.org/apps/learn/>`_ by John Resig, the author of jQuery. If you master this one, you're almost done with the language.
.. _PhantomJS: http://phantomjs.org/
.. _Qt: http://qt.digia.com/
.. _WebKit: http://www.webkit.org/
======================
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.
.. _casper_module:
=====================
The ``casper`` module
=====================
.. index:: Casper
The ``Casper`` class
++++++++++++++++++++
The easiest way to get a casper instance is to use the module's ``create()`` method::
var casper = require('casper').create();
But you can also retrieve the main Function and instantiate it by yourself::
var casper = new require('casper').Casper();
.. hint::
Also, check out :doc:`how to extend Casper with your own methods <../extending>`.
Both the ``Casper`` constructor and the ``create()`` function accept a single ``options`` argument which is a standard javascript object::
var casper = require('casper').create({
verbose: true,
logLevel: "debug"
});
.. _casper_options:
.. index:: Casper options, options
``Casper.options``
++++++++++++++++++
An ``options`` object can be passed to the ``Casper`` constructor, eg.::
var casper = require('casper').create({
clientScripts: [
'includes/jquery.js', // These two scripts will be injected in remote
'includes/underscore.js' // DOM on every request
],
pageSettings: {
loadImages: false, // The WebPage instance used by Casper will
loadPlugins: false // use these settings
},
logLevel: "info", // Only "info" level messages will be logged
verbose: true // log messages will be printed out to the console
});
You can also alter options at runtime::
var casper = require('casper').create();
casper.options.waitTimeout = 1000;
The whole list of available options is detailed below.
.. index:: Client scripts
.. _casper_option_clientscripts:
``clientScripts``
-------------------------------------------------------------------------------
**Type:** ``Array``
**Default:** ``[]``
A collection of script filepaths to include in every page loaded
.. index:: exit, error
``exitOnError``
-------------------------------------------------------------------------------
**Type:** ``Boolean``
**Default:** ``true``
Sets if CasperJS must exit when an uncaught error has been thrown by the script.
.. index:: HTTP
``httpStatusHandlers``
-------------------------------------------------------------------------------
**Type:** ``Object``
**Default:** ``{}``
A javascript Object containing functions to call when a requested resource has a given HTTP status code. A dedicated sample is provided as an example.
.. index:: Logging
``logLevel``
-------------------------------------------------------------------------------
**Type:** ``String``
**Default:** ``"error"``
Logging level (see the logging section for more information)
``onAlert``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
A function to be called when a javascript alert() is triggered
``onDie``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
A function to be called when Casper#die() is called
.. index:: error, Error handling
``onError``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
A function to be called when an "error" level event occurs
.. index:: error, Error handling
``onLoadError``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
A function to be called when a requested resource cannot be loaded
``onPageInitialized``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
A function to be called after ``WebPage`` instance has been initialized
.. index:: HTTP
``onResourceReceived``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
Proxy method for PhantomJS' ``WebPage#onResourceReceived()`` callback, but the current Casper instance is passed as first argument.
.. index:: HTTP
``onResourceRequested``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
Proxy method for PhantomJS' WebPage#onResourceRequested() callback, but the current Casper instance is passed as first argument.
.. index:: Step stack
``onStepComplete``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``null``
A function to be executed when a step function execution is finished.
.. index:: Step stack, Error handling, timeout
``onStepTimeout``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``Function``
A function to be executed when a step function execution time exceeds the value of the stepTimeout option, if any has been set.
By default, on timeout the script will exit displaying an error, except in test environment where it will just add a failure to the suite results.
.. index:: Error handling, timeout
``onTimeout``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``Function``
A function to be executed when script execution time exceeds the value of the timeout option, if any has been set.
By default, on timeout the script will exit displaying an error, except in test environment where it will just add a failure to the suite results.
.. index:: Error handling, timeout
``onWaitTimeout``
-------------------------------------------------------------------------------
**Type:** ``Function``
**Default:** ``Function``
A function to be executed when a ``waitFor*`` function execution time exceeds the value of the waitTimeout option, if any has been set.
By default, on timeout the script will exit displaying an error, except in test environment where it will just add a failure to the suite results.
``page``
-------------------------------------------------------------------------------
**Type:** ``WebPage``
**Default:** ``null``
An existing PhantomJS ``WebPage`` instance
.. index:: settings, PhantomJS, SSL, auth, XSS
``pageSettings``
-------------------------------------------------------------------------------
**Type:** ``Object``
**Default:** ``{}``
PhantomJS's WebPage settings object. Available settings are:
- ``javascriptEnabled`` defines whether to execute the script in the page or not (default to ``true``)
- ``loadImages`` defines whether to load the inlined images or not
- ``loadPlugins`` defines whether to load NPAPI plugins (Flash, Silverlight, …) or not
- ``localToRemoteUrlAccessEnabled`` defines whether local resource (e.g. from file) can access remote URLs or not (default to ``false``)
- ``userAgent`` defines the user agent sent to server when the web page requests resources
- ``userName`` sets the user name used for HTTP authentication
- ``password`` sets the password used for HTTP authentication
- ``XSSAuditingEnabled`` defines whether load requests should be monitored for cross-site scripting attempts (default to ``false``)
.. index:: Remote scripts
``remoteScripts``
-------------------------------------------------------------------------------
**Type:** ``Array``
**Default:** ``[]``
.. versionadded:: 1.0
A collection of remote script urls to include in every page loaded
.. index:: Logging
``safeLogs``
-------------------------------------------------------------------------------
**Type:** ``Boolean``
**Default:** ``true``
.. versionadded:: 1.0
When this option is set to true — which is the default, any password information entered in <input type="password"> will be obfuscated in log messages. Set safeLogs to false to disclose passwords in plain text (not recommended).
.. index:: Step stack, timeout
``stepTimeout``
-------------------------------------------------------------------------------
**Type:** ``Number``
**Default:** ``null``
Max step timeout in milliseconds; when set, every defined step function will have to execute before this timeout value has been reached. You can define the onStepTimeout() callback to catch such a case. By default, the script will die() with an error message.
.. index:: timeout
``timeout``
-------------------------------------------------------------------------------
**Type:** ``Number``
**Default:** ``null``
Max timeout in milliseconds
.. index:: verbose
``verbose``
-------------------------------------------------------------------------------
**Type:** ``Boolean``
**Default:** ``false``
Realtime output of log messages
.. index:: viewport
``viewportSize``
-------------------------------------------------------------------------------
**Type:** ``Object``
**Default:** ``null``
Viewport size, eg. ``{width: 800, height: 600}``
.. note::
PhantomJS ships with a default viewport of 400x300, and CasperJS won't override it by default.
.. index:: timeout
``waitTimeout``
-------------------------------------------------------------------------------
**Type:** ``Number``
**Default:** ``5000``
Default wait timeout, for ``wait*`` family functions.
``Casper`` prototype
++++++++++++++++++++
``back()``
-------------------------------------------------------------------------------
**Signature:** ``back()``
Moves back a step in browser's history::
casper.start('http://foo.bar/1')
casper.thenOpen('http://foo.bar/2');
casper.thenOpen('http://foo.bar/3');
casper.back();
casper.run(function() {
console.log(this.getCurrentUrl()); // 'http://foo.bar/2'
});
Also have a look at ``Casper.forward()``.
.. _casper_base64encode:
.. index:: Base64
``base64encode()``
-------------------------------------------------------------------------------
**Signature:** ``base64encode(String url [, String method, Object data])``
Encodes a resource using the base64 algorithm synchronously using
client-side XMLHttpRequest.
.. note::
We cannot use ``window.btoa()`` because it fails miserably in the version of WebKit shipping with PhantomJS.
Example: retrieving google logo image encoded in base64::
var base64logo = null;
casper.start('http://www.google.fr/', function() {
base64logo = this.base64encode('http://www.google.fr/images/srpr/logo3w.png');
});
casper.run(function() {
this.echo(base64logo).exit();
});
You can also perform an HTTP POST request to retrieve the contents to
encode::
var base46contents = null;
casper.start('http://domain.tld/download.html', function() {
base46contents = this.base64encode('http://domain.tld/', 'POST', {
param1: 'foo',
param2: 'bar'
});
});
casper.run(function() {
this.echo(base46contents).exit();
});
.. index:: bypass, Step stack
``bypass()``
-------------------------------------------------------------------------------
**Signature:** ``bypass(Numbr nb)``
Bypasses a given number of defined navigation steps::
casper.start();
casper.then(function() {
// This step will be executed
});
casper.then(function() {
this.bypass(2);
});
casper.then(function() {
// This test won't be executed
});
casper.then(function() {
// Nor this one
});
casper.run();
.. _casper_click:
.. index:: click
``click()``
-------------------------------------------------------------------------------
**Signature:** ``click(String selector)``
Performs a click on the element matching the provided :doc:`selector expression <../selectors>`. The method tries two strategies sequentially:
1. trying to trigger a MouseEvent in Javascript
2. using native QtWebKit event if the previous attempt failed
Example::
casper.start('http://google.fr/');
casper.thenEvaluate(function(term) {
document.querySelector('input[name="q"]').setAttribute('value', term);
document.querySelector('form[name="f"]').submit();
}, 'CasperJS');
casper.then(function() {
// Click on 1st result link
this.click('h3.r a');
});
casper.then(function() {
console.log('clicked ok, new location is ' + this.getCurrentUrl());
});
casper.run();
.. index:: click
``clickLabel()``
-------------------------------------------------------------------------------
**Signature:** ``clickLabel(String label[, String tag])``
.. versionadded:: 0.6.1
Clicks on the first DOM element found containing ``label`` text. Optionaly ensures that the element node name is ``tag``::
// <a href="...">My link is beautiful</a>
casper.then(function() {
this.clickLabel('My link is beautiful', 'a');
});
// <button type="submit">But my button is sexier</button>
casper.then(function() {
this.clickLabel('But my button is sexier', 'button');
});
.. index:: screenshot
``capture()``
-------------------------------------------------------------------------------
**Signature:** ``capture(String targetFilepath, Object clipRect)``
Proxy method for PhantomJS' ``WebPage#render``. Adds a ``clipRect`` parameter for automatically setting page ``clipRect`` setting and reverts it back once done::
casper.start('http://www.google.fr/', function() {
this.capture('google.png', {
top: 100,
left: 100,
width: 500,
height: 400
});
});
casper.run();
.. index:: screenshot, Base64
``captureBase64()``
-------------------------------------------------------------------------------
**Signature:** ``captureBase64(String format[, Mixed area])``
.. versionadded:: 0.6.5
Computes the `Base64 <http://en.wikipedia.org/wiki/Base64>`_ representation of a binary image capture of the current page, or an area within the page, in a given format.
Supported image formats are ``bmp``, ``jpg``, ``jpeg``, ``png``, ``ppm``, ``tiff``, ``xbm`` and ``xpm``.
The ``area`` argument can be either of the following types:
- ``String``: area is a CSS3 selector string, eg. ``div#plop form[name="form"] input[type="submit"]``
- ``clipRect``: area is a clipRect object, eg. ``{"top":0,"left":0,"width":320,"height":200}``
- ``Object``: area is a :doc:`selector object <../selectors>`, eg. an XPath selector
Example::
casper.start('http://google.com', function() {
// selector capture
console.log(this.captureBase64('png', '#lga'));
// clipRect capture
console.log(this.captureBase64('png', {
top: 0,
left: 0,
width: 320,
height: 200
}));
// whole page capture
console.log(this.captureBase64('png'));
});
casper.run();
.. _casper_captureselector:
.. index:: screenshot
``captureSelector()``
-------------------------------------------------------------------------------
**Signature:** ``captureSelector(String targetFile, String selector)``
Captures the page area containing the provided selector and saves it to ``targetFile``::
casper.start('http://www.weather.com/', function() {
this.captureSelector('weather.png', '#wx-main');
});
casper.run();
``clear()``
-------------------------------------------------------------------------------
**Signature:** ``clear()``
.. versionadded:: 0.6.5
Clears the current page execution environment context. Useful to avoid having previously loaded DOM contents being still active.
Think of it as a way to stop javascript execution within the remote DOM environment::
casper.start('http://www.google.fr/', function() {
this.clear(); // javascript execution in this page has been stopped
});
casper.then(function() {
// ...
});
casper.run();
.. index:: Debugging
``debugHTML()``
-------------------------------------------------------------------------------
**Signature:** ``debugHTML([String selector, Boolean outer])``
Outputs the results of `getHTML()`_ directly to the console. It takes the same arguments as ``getHTML()``.
.. index:: Debugging
``debugPage()``
-------------------------------------------------------------------------------
**Signature:** ``debugPage()``
Logs the textual contents of the current page directly to the standard output, for debugging purpose::
casper.start('http://www.google.fr/', function() {
this.debugPage();
});
casper.run();
``die()``
-------------------------------------------------------------------------------
**Signature:** ``die(String message[, int status])``
Exits phantom with a logged error message and an optional exit status code::
casper.start('http://www.google.fr/', function() {
this.die("Fail.", 1);
});
casper.run();
.. _casper_download:
.. index:: download
``download()``
-------------------------------------------------------------------------------
**Signature:** ``download(String url, String target[, String method, Object data])``
Saves a remote resource onto the filesystem. You can optionally set the HTTP method using the ``method`` argument, and pass request arguments through the ``data`` object (see `base64encode()`_)::
casper.start('http://www.google.fr/', function() {
var url = 'http://www.google.fr/intl/fr/about/corporate/company/';
this.download(url, 'google_company.html');
});
casper.run(function() {
this.echo('Done.').exit();
});
``each()``
-------------------------------------------------------------------------------
**Signature:** ``each(Array array, Function fn)``
Iterates over provided array items and execute a callback::
var links = [
'http://google.com/',
'http://yahoo.com/',
'http://bing.com/'
];
casper.start().each(links, function(self, link) {
self.thenOpen(link, function() {
this.echo(this.getTitle());
});
});
casper.run();
.. hint::
Have a look at the `googlematch.js <https://github.com/n1k0/casperjs/blob/master/samples/googlematch.js>`_ sample script for a concrete use case.
.. _casper_echo:
.. index:: echo, Printing
``echo()``
-------------------------------------------------------------------------------
**Signature:** ``echo(String message[, String style])``
Prints something to stdout, optionally with some fancy color (see the :ref:`colorizer module <colorizer_module>` for more information)::
casper.start('http://www.google.fr/', function() {
this.echo('Page title is: ' + this.evaluate(function() {
return document.title;
}), 'INFO'); // Will be printed in green on the console
});
casper.run();
.. index:: evaluate, DOM
.. _casper_evaluate:
``evaluate()``
-------------------------------------------------------------------------------
**Signature:** ``evaluate(Function fn[, arg1[, arg2[, …]]])``
Basically `PhantomJS' WebPage#evaluate <https://github.com/ariya/phantomjs/wiki/API-Reference#wiki-webpage-evaluate>`_ equivalent. Evaluates an expression **in the current page DOM context**::
casper.evaluate(function(username, password) {
document.querySelector('#username').value = username;
document.querySelector('#password').value = password;
document.querySelector('#submit').click();
}, 'sheldon.cooper', 'b4z1ng4');
.. note::
For filling and submitting forms, rather use the `fill()`_ method.
.. warning::
The pre-1.0 way of passing arguments using an object has been kept for BC purpose, though it may `not work in some case <https://github.com/n1k0/casperjs/issues/349>`_; so you're encouraged to use the method described above.
.. topic:: Understanding ``evaluate()``
The concept behind this method is probably the most difficult to understand when discovering CasperJS. As a reminder, think of the ``evaluate()`` method as a *gate* between the CasperJS environment and the one of the page you have opened; everytime you pass a closure to ``evaluate()``, you're entering the page and execute code as if you were using the browser console.
Here's a quickly drafted diagram trying to basically explain the separation of concerns:
.. figure:: ../_static/images/evaluate-diagram.png
:align: center
``evaluateOrDie()``
-------------------------------------------------------------------------------
**Signature:** ``evaluateOrDie(Function fn[, String message])``
Evaluates an expression within the current page DOM and ``die()`` if it returns anything but ``true``::
casper.start('http://foo.bar/home', function() {
this.evaluateOrDie(function() {
return /logged in/.match(document.title);
}, 'not authenticated');
});
casper.run();
.. index:: exit
``exit()``
-------------------------------------------------------------------------------
**Signature:** ``exit([int status])``
Exits PhantomJS with an optional exit status code.
.. index:: DOM
``exists()``
-------------------------------------------------------------------------------
**Signature:** ``exists(String selector)``
Checks if any element within remote DOM matches the provided :doc:`selector <../selectors>`::
casper.start('http://foo.bar/home', function() {
if (this.exists('#my_super_id')) {
this.echo('found #my_super_id', 'INFO');
} else {
this.echo('#my_super_id not found', 'ERROR');
}
});
casper.run();
.. _casper_fetchtext:
``fetchText()``
-------------------------------------------------------------------------------
**Signature:** ``fetchText(String selector)``
Retrieves text contents matching a given :doc:`selector expression <../selectors>`. If you provide one matching more than one element, their textual contents will be concatenated::
casper.start('http://google.com/search?q=foo', function() {
this.echo(this.fetchText('h3'));
}).run();
``forward()``
-------------------------------------------------------------------------------
**Signature:** ``forward()``
Moves a step forward in browser's history::
casper.start('http://foo.bar/1')
casper.thenOpen('http://foo.bar/2');
casper.thenOpen('http://foo.bar/3');
casper.back(); // http://foo.bar/2
casper.back(); // http://foo.bar/1
casper.forward(); // http://foo.bar/2
casper.run();
Also have a look at `back()`_.
.. _casper_log:
.. index:: Logging
``log()``
-------------------------------------------------------------------------------
**Signature:** ``log(String message[, String level, String space])``
Logs a message with an optional level in an optional space. Available levels are ``debug``, ``info``, ``warning`` and ``error``. A space is a kind of namespace you can set for filtering your logs. By default, Casper logs messages in two distinct spaces: ``phantom`` and ``remote``, to distinguish what happens in the PhantomJS environment from the remote one::
casper.start('http://www.google.fr/', function() {
this.log("I'm logging an error", "error");
});
casper.run();
.. _casper_fill:
.. index:: Form
``fill()``
-------------------------------------------------------------------------------
**Signature:** ``fill(String selector, Object values[, Boolean submit])``
Fills the fields of a form with given values and optionally submits it.
Example with this sample html form:
.. code-block :: html
<form action="/contact" id="contact-form" enctype="multipart/form-data">
<input type="text" name="subject"/>
<textearea name="content"></textearea>
<input type="radio" name="civility" value="Mr"/> Mr
<input type="radio" name="civility" value="Mrs"/> Mrs
<input type="text" name="name"/>
<input type="email" name="email"/>
<input type="file" name="attachment"/>
<input type="checkbox" name="cc"/> Receive a copy
<input type="submit"/>
</form>
A script to fill and submit this form::
casper.start('http://some.tld/contact.form', function() {
this.fill('form#contact-form', {
'subject': 'I am watching you',
'content': 'So be careful.',
'civility': 'Mr',
'name': 'Chuck Norris',
'email': 'chuck@norris.com',
'cc': true,
'attachment': '/Users/chuck/roundhousekick.doc'
}, true);
});
casper.then(function() {
this.evaluateOrDie(function() {
return /message sent/.test(document.body.innerText);
}, 'sending message failed');
});
casper.run(function() {
this.echo('message sent').exit();
});
.. warning::
1. The ``fill()`` method currently can't fill **file fields using XPath selectors**; PhantomJS natively only allows the use of CSS3 selectors in its uploadFile method, hence this limitation.
2. Please Don't use CasperJS nor PhantomJS to send spam, or I'll be calling the Chuck. More seriously, please just don't.
.. index:: URL
``getCurrentUrl()``
-------------------------------------------------------------------------------
**Signature:** ``getCurrentUrl()``
Retrieves current page URL. Note that the url will be url-decoded::
casper.start('http://www.google.fr/', function() {
this.echo(this.getCurrentUrl()); // "http://www.google.fr/"
});
casper.run();
.. index:: DOM
``getElementAttribute()``
-------------------------------------------------------------------------------
**Signature:** ``getElementAttribute(String selector, String attribute)``
.. versionadded:: 1.0
Retrieves the value of an attribute on the first element matching the provided :doc:`selector <../selectors>`::
var casper = require('casper').create();
casper.start('http://www.google.fr/', function() {
require('utils').dump(this.getElementAttribute('div[title="Google"]', 'title')); // "Google"
});
casper.run();
.. index:: DOM
``getElementBounds()``
-------------------------------------------------------------------------------
**Signature:** ``getElementBounds(String selector)``
Retrieves boundaries for a DOM element matching the provided :doc:`selector <../selectors>`.
It returns an Object with four keys: ``top``, ``left``, ``width`` and ``height``, or ``null`` if the selector doesn't exist::
var casper = require('casper').create();
casper.start('http://www.google.fr/', function() {
require('utils').dump(this.getElementBounds('div[title="Google"]'));
});
casper.run();
This will output something like::
{
"height": 95,
"left": 352,
"top": 16,
"width": 275
}
.. index:: DOM
``getElementsBounds()``
-------------------------------------------------------------------------------
**Signature:** ``getElementsBounds(String selector)``
.. versionadded:: 1.0
Retrieves a list of boundaries for all DOM elements matching the provided :doc:`selector <../selectors>`.
It returns an array of objects with four keys: ``top``, ``left``, ``width`` and ``height`` (see `getElementBounds()`_).
.. _casper_getelementinfo:
.. index:: DOM
``getElementInfo()``
-------------------------------------------------------------------------------
**Signature:** ``getElementInfo(String selector)``
.. versionadded:: 1.0
Retrieves information about the first element matching the provided :doc:`selector <../selectors>`::
casper.start('http://google.com/', function() {
require('utils').dump(this.getElementInfo('#hplogo'));
});
Gives something like::
{
"nodeName": "div",
"attributes": {
"dir": "ltr",
"title": "Google",
"align": "left",
"id": "hplogo",
"onload": "window.lol&&lol()",
"style": "background:url(images/srpr/logo3w.png) no-repeat;background-size:275px 95px;height:95px;width:275px"
},
"tag": "<div dir=\"ltr\" title=\"Google\" align=\"left\" id=\"hplogo\" onload=\"window.lol&amp;&amp;lol()\" style=\"background:url(images/srpr/logo3w.png) no-repeat;background-size:275px 95px;height:95px;width:275px\"><div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div></div>",
"html": "<div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div>",
"text": "France\n",
"x": 582.5,
"y": 192,
"width": 275,
"height": 95,
"visible": true
}
.. index:: Form
``getFormValues()``
-------------------------------------------------------------------------------
**Signature:** ``getFormValues(String selector)``
.. versionadded:: 1.0
Retrieves a given form all of its field values::
casper.start('http://www.google.fr/', function() {
this.fill('form', {q: 'plop'}, false);
this.echo(this.getFormValues('form').q); // 'plop'
});
casper.run();
.. index:: Globals, window
``getGlobal()``
-------------------------------------------------------------------------------
**Signature:** ``getGlobal(String name)``
Retrieves a global variable value within the remote DOM environment by its name. Basically, ``getGlobal('foo')`` will retrieve the value of ``window.foo`` from the page::
casper.start('http://www.google.fr/', function() {
this.echo(this.getGlobal('innerWidth')); // 1024
});
casper.run();
.. index:: Debugging
``getHTML()``
-------------------------------------------------------------------------------
**Signature:** ``getHTML([String selector, Boolean outer])``
.. versionadded:: 1.0
Retrieves HTML code from the current page. By default, it outputs the whole page HTML contents::
casper.start('http://www.google.fr/', function() {
this.echo(this.getHTML());
});
casper.run();
The ``getHTML()`` method can also dump HTML contents matching a given :doc:`selector <../selectors>`; for example with this HTML code:
.. code-block:: html
<html>
<body>
<h1 id="foobar">Plop</h1>
</body>
</html>
You can fetch those contents using::
casper.start('http://www.site.tld/', function() {
this.echo(this.getHTML('h1#foobar')); // => 'Plop'
});
The ``outer`` argument allows to retrieve the outer HTML contents of the matching element::
casper.start('http://www.site.tld/', function() {
this.echo(this.getHTML('h1#foobar', true)); // => '<h1 id="foobar">Plop</h1>'
});
``getPageContent()``
-------------------------------------------------------------------------------
**Signature:** ``getPageContent()``
.. versionadded:: 1.0
Retrieves current page contents, dealing with exotic other content types than HTML::
var casper = require('casper').create();
casper.start().then(function() {
this.open('http://search.twitter.com/search.json?q=casperjs', {
method: 'get',
headers: {
'Accept': 'application/json'
}
});
});
casper.run(function() {
require('utils').dump(JSON.parse(this.getPageContent()));
this.exit();
});
.. index:: DOM
``getTitle()``
-------------------------------------------------------------------------------
**Signature:** ``getTitle()``
Retrieves current page title::
casper.start('http://www.google.fr/', function() {
this.echo(this.getTitle()); // "Google"
});
casper.run();
.. _casper_mouseevent:
.. index:: events
``mouseEvent()``
-------------------------------------------------------------------------------
**Signature:** ``mouseEvent(String type, String selector)``
.. versionadded:: 0.6.9
Triggers a mouse event on the first element found matching the provided selector.
Supported events are ``mouseup``, ``mousedown``, ``click``, ``mousemove``, ``mouseover`` and ``mouseout``::
casper.start('http://www.google.fr/', function() {
this.mouseEvent('click', 'h2 a');
});
casper.run();
.. index:: HTTP, HTTP Request, HTTP Method, HTTP Headers
``open()``
-------------------------------------------------------------------------------
**Signature:** ``open(String location, Object Settings)``
Performs an HTTP request for opening a given location. You can forge ``GET``, ``POST``, ``PUT``, ``DELETE`` and ``HEAD`` requests.
Example for a standard ``GET`` request::
casper.start();
casper.open('http://www.google.com/').then(function() {
this.echo('GOT it.');
});
casper.run();
Example for a ``POST`` request::
casper.start();
casper.open('http://some.testserver.com/post.php', {
method: 'post',
data: {
'title': 'Plop',
'body': 'Wow.'
}
});
casper.then(function() {
this.echo('POSTED it.');
});
casper.run();
To pass nested parameters arrays::
casper.open('http://some.testserver.com/post.php', {
method: 'post',
data: {
'standard_param': 'foo',
'nested_param[]': [ // please note the use of square brackets!
'Something',
'Something else'
]
}
});
.. versionadded:: 1.0
You can also set custom request headers to send when performing an outgoing request, passing the ``headers`` option::
casper.open('http://some.testserver.com/post.php', {
method: 'post',
data: {
'title': 'Plop',
'body': 'Wow.'
},
headers: {
'Accept-Language': 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
}
});
``reload()``
-------------------------------------------------------------------------------
**Signature:** ``reload([Function then])``
.. versionadded:: 1.0
Reloads current page location::
casper.start('http://google.com', function() {
this.echo("loaded");
this.reload(function() {
this.echo("loaded again");
});
});
casper.run();
``repeat()``
-------------------------------------------------------------------------------
**Signature:** ``repeat(int times, Function then)``
Repeats a navigation step a given number of times::
casper.start().repeat(3, function() {
this.echo("Badger");
});
casper.run();
.. _casper_resourceexists:
.. index:: HTTP
``resourceExists()``
-------------------------------------------------------------------------------
**Signature:** ``resourceExists(Mixed test)``
Checks if a resource has been loaded. You can pass either a function or a string to perform the test::
casper.start('http://www.google.com/', function() {
if (this.resourceExists('logo3w.png')) {
this.echo('Google logo loaded');
} else {
this.echo('Google logo not loaded', 'ERROR');
}
});
casper.run();
.. note::
If you want to wait for a resource to be loaded, use the `waitForResource()`_ method.
.. index:: Step stack, run
``run()``
-------------------------------------------------------------------------------
**Signature:** ``run(fn onComplete[, int time])``
Runs the whole suite of steps and optionally executes a callback when they've all been done. Obviously, **calling this method is mandatory** in order to run the Casper navigation suite.
Casper suite **won't run**::
casper.start('http://foo.bar/home', function() {
// ...
});
// hey, it's missing .run() here!
Casper suite **will run**::
casper.start('http://foo.bar/home', function() {
// ...
});
casper.run();
``Casper.run()`` also accepts an ``onComplete`` callback, which you can consider as a custom final step to perform when all the other steps have been executed. Just don't forget to ``exit()`` Casper if you define one!::
casper.start('http://foo.bar/home', function() {
// ...
});
casper.then(function() {
// ...
});
casper.run(function() {
this.echo('So the whole suite ended.');
this.exit(); // <--- don't forget me!
});
.. index:: Form
``sendKeys()``
-------------------------------------------------------------------------------
**Signature:** ``sendKeys(Selector selector, String keys[, Object options])``
.. versionadded:: 1.0
Sends native keyboard events to the element matching the provided :doc:`selector <../selectors>`::
casper.then(function() {
this.sendKeys('form.contact input#name', 'Duke');
this.sendKeys('form.contact textarea#message', "Damn, I'm looking good.");
this.click('form.contact input[type="submit"]');
});
.. index:: auth
``setHttpAuth()``
-------------------------------------------------------------------------------
**Signature:** ``setHttpAuth(String username, String password)``
Sets ``HTTP_AUTH_USER`` and ``HTTP_AUTH_PW`` values for HTTP based authentication systems::
casper.start();
casper.setHttpAuth('sheldon.cooper', 'b4z1ng4');
casper.thenOpen('http://password-protected.domain.tld/', function() {
this.echo("I'm in. Bazinga.");
})
casper.run();
Of course you can directly pass the auth string in the url to open::
var url = 'http://sheldon.cooper:b4z1ng4@password-protected.domain.tld/';
casper.start(url, function() {
this.echo("I'm in. Bazinga.");
})
casper.run();
.. index:: start, initialization
``start()``
-------------------------------------------------------------------------------
**Signature:** ``start(String url[, Function then])``
Configures and starts Casper, then open the provided ``url`` and optionally adds the step provided by the ``then`` argument::
casper.start('http://google.fr/', function() {
this.echo("I'm loaded.");
});
casper.run();
Alternatively::
casper.start('http://google.fr/');
casper.then(function() {
this.echo("I'm loaded.");
});
casper.run();
Or alternatively::
casper.start('http://google.fr/');
casper.then(function() {
casper.echo("I'm loaded.");
});
casper.run();
Matter of taste!
.. note::
You must call the ``start()`` method in order to be able to add navigation steps and run the suite. If you don't you'll get an error message inviting you to do so anyway.
``status()``
-------------------------------------------------------------------------------
**Signature:** ``status(Boolean asString)``
.. versionadded:: 1.0
Returns the status of current Casper instance::
casper.start('http://google.fr/', function() {
this.echo(this.status(true));
});
casper.run();
.. index:: Step stack, Asynchronicity
``then()``
-------------------------------------------------------------------------------
**Signature:** ``then(Function then)``
This method is the standard way to add a new navigation step to the stack, by providing a simple function::
casper.start('http://google.fr/');
casper.then(function() {
this.echo("I'm in your google.");
});
casper.then(function() {
this.echo('Now, let me write something');
});
casper.then(function() {
this.echo('Oh well.');
});
casper.run();
You can add as many steps as you need. Note that the current ``Casper`` instance automatically binds the ``this`` keyword for you within step functions.
To run all the steps you defined, call the `run()`_ method, and voila.
.. index:: HTTP Response
.. note::
You must `start()`_ the casper instance in order to use the ``then()`` method.
.. topic:: Accessing the current HTTP response
.. versionadded:: 1.0
You can access the current HTTP response object using the first parameter of your step callback::
casper.start('http://www.google.fr/', function(response) {
require('utils').dump(response);
});
That gives:
.. code-block:: text
$ casperjs dump-headers.js
{
"contentType": "text/html; charset=UTF-8",
"headers": [
{
"name": "Date",
"value": "Thu, 18 Oct 2012 08:17:29 GMT"
},
{
"name": "Expires",
"value": "-1"
},
// ... lots of other headers
],
"id": 1,
"redirectURL": null,
"stage": "end",
"status": 200,
"statusText": "OK",
"time": "2012-10-18T08:17:37.068Z",
"url": "http://www.google.fr/"
}
So to fetch a particular header by its name::
casper.start('http://www.google.fr/', function(response) {
this.echo(response.headers.get('Date'));
});
That gives:
.. code-block:: text
$ casperjs dump-headers.js
Thu, 18 Oct 2012 08:26:34 GMT
.. index:: bypass, Step stack
``thenBypass()``
-------------------------------------------------------------------------------
**Signature:** ``thenBypass(Number nb)``
Adds a navigation step which will bypass a given number of following steps::
casper.start('http://foo.bar/');
casper.thenBypass(2);
casper.then(function() {
// This test won't be executed
});
casper.then(function() {
// Nor this one
});
casper.then(function() {
// While this one will
});
casper.run();
``thenBypassIf()``
-------------------------------------------------------------------------------
**Signature:** ``thenBypassIf(Mixed condition, Number nb)``
Bypass a given number of navigation steps if the provided condition is truthy or is a function that returns a truthy value::
var universe = {
answer: 42
};
casper.start('http://foo.bar/');
casper.thenBypassIf(function() {
return universe && universe.answer === 42;
}, 2);
casper.then(function() {
// This step won't be executed as universe.answer is 42
});
casper.then(function() {
// Nor this one
});
casper.then(function() {
// While this one will
});
casper.run();
``thenBypassUnless()``
-------------------------------------------------------------------------------
**Signature:** ``thenBypassUnless(Mixed condition, Number nb)``
Opposite of `thenBypassIf()`_.
``thenClick()``
-------------------------------------------------------------------------------
**Signature:** ``thenClick(String selector[, Function then])``
Adds a new navigation step to click a given selector and optionally add a new navigation step in a single operation::
// Querying for "Chuck Norris" on Google
casper.start('http://casperjs.org/').thenClick('a', function() {
this.echo("I clicked on first link found, the page is now loaded.");
});
casper.run();
This method is basically a convenient a shortcut for chaining a `then()`_ and an `evaluate()`_ calls.
``thenEvaluate()``
-------------------------------------------------------------------------------
**Signature:** ``thenEvaluate(Function fn[, arg1[, arg2[, …]]])``
Adds a new navigation step to perform code evaluation within the current retrieved page DOM::
// Querying for "Chuck Norris" on Google
casper.start('http://google.fr/').thenEvaluate(function(term) {
document.querySelector('input[name="q"]').setAttribute('value', term);
document.querySelector('form[name="f"]').submit();
}, 'Chuck Norris');
casper.run();
This method is basically a convenient a shortcut for chaining a `then()`_ and an `evaluate()`_ calls.
``thenOpen()``
-------------------------------------------------------------------------------
**Signature:** ``thenOpen(String location[, mixed options])``
Adds a new navigation step for opening a new location, and optionally add a next step when its loaded::
casper.start('http://google.fr/').then(function() {
this.echo("I'm in your google.");
});
casper.thenOpen('http://yahoo.fr/', function() {
this.echo("Now I'm in your yahoo.")
});
casper.run();
.. versionadded:: 1.0
You can also specify request settings by passing a setting object (see `open()`_) as the second argument::
casper.start().thenOpen('http://url.to/some/uri', {
method: "post",
data: {
username: 'chuck',
password: 'n0rr15'
}
}, function() {
this.echo("POST request has been sent.")
});
casper.run();
``thenOpenAndEvaluate()``
-------------------------------------------------------------------------------
**Signature:** ``thenOpenAndEvaluate(String location[, Function then[, arg1[, arg2[, …]]])``
Basically a shortcut for opening an url and evaluate code against remote DOM environment::
casper.start('http://google.fr/').then(function() {
this.echo("I'm in your google.");
});
casper.thenOpenAndEvaluate('http://yahoo.fr/', function() {
var f = document.querySelector('form');
f.querySelector('input[name=q]').value = 'chuck norris';
f.submit();
});
casper.run(function() {
this.debugPage();
this.exit();
});
``toString()``
-------------------------------------------------------------------------------
**Signature:** ``toString()``
.. versionadded:: 1.0
Returns a string representation of current Casper instance::
casper.start('http://google.fr/', function() {
this.echo(this); // [object Casper], currently at http://google.fr/
});
casper.run();
.. index:: User Agent
``userAgent()``
-------------------------------------------------------------------------------
**Signature:** ``userAgent(String agent)``
.. versionadded:: 1.0
Sets the `User-Agent string <http://en.wikipedia.org/wiki/User-Agent>`_ to send through headers when performing requests::
casper.start();
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');
casper.thenOpen('http://google.com/', function() {
this.echo("I'm a Mac.");
});
casper.userAgent('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)');
casper.thenOpen('http://google.com/', function() {
this.echo("I'm a PC.");
});
casper.run();
.. index:: viewport
``viewport()``
-------------------------------------------------------------------------------
**Signature:** ``viewport(Number width, Number height[, Function then])``
Changes current viewport size::
casper.viewport(1024, 768);
To be sure page reflowing has occured, you have to use it asynchronously::
casper.viewport(1024, 768).then(function() {
// new view port is now effective
});
.. versionadded:: 1.1
As of 1.1 you can pass a `then` step function directly to ``viewport()``::
casper.viewport(1024, 768, function() {
// new view port is effective
});
.. note::
PhantomJS comes with a default viewport size of 400x300, and CasperJS doesn't override it by default.
.. index:: DOM
``visible()``
-------------------------------------------------------------------------------
**Signature:** ``visible(String selector)``
Checks if the DOM element matching the provided :doc:`selector expression <../selectors>` is visible in remote page::
casper.start('http://google.com/', function() {
if (this.visible('#hplogo')) {
this.echo("I can see the logo");
} else {
this.echo("I can't see the logo");
}
});
.. index:: wait, sleep
``wait()``
-------------------------------------------------------------------------------
**Signature:** ``wait(Number timeout[, Function then])``
Pause steps suite execution for a given amount of time, and optionally execute a step on done::
casper.start('http://yoursite.tld/', function() {
this.wait(1000, function() {
this.echo("I've waited for a second.");
});
});
casper.run();
You can also write the same thing like this::
casper.start('http://yoursite.tld/');
casper.wait(1000, function() {
this.echo("I've waited for a second.");
});
casper.run();
.. index:: Asynchronicity
``waitFor()``
-------------------------------------------------------------------------------
**Signature:** ``waitFor(Function testFx[, Function then, Function onTimeout, Number timeout])``
Waits until a function returns true to process any next step.
You can also set a callback on timeout using the ``onTimeout`` argument, and set the timeout using the ``timeout`` one, in milliseconds. The default timeout is set to 5000ms::
casper.start('http://yoursite.tld/');
casper.waitFor(function check() {
return this.evaluate(function() {
return document.querySelectorAll('ul.your-list li').length > 2;
});
}, function then() {
this.captureSelector('yoursitelist.png', 'ul.your-list');
});
casper.run();
Example using the ``onTimeout`` callback::
casper.start('http://yoursite.tld/');
casper.waitFor(function check() {
return this.evaluate(function() {
return document.querySelectorAll('ul.your-list li').length > 2;
});
}, function then() { // step to execute when check() is ok
this.captureSelector('yoursitelist.png', 'ul.your-list');
}, function timeout() { // step to execute if check has failed
this.echo("I can't haz my screenshot.").exit();
});
casper.run();
.. _casper_waitforpopup:
.. index:: Popups, New window, window.open, Tabs
``waitForPopup()``
-------------------------------------------------------------------------------
**Signature:** ``waitForPopup(String|RegExp urlPattern[, Function then, Function onTimeout, Number timeout])``
.. versionadded:: 1.0
Waits for a popup having its url matching the provided pattern to be opened and loaded.
The currently loaded popups are available in the ``Casper.popups`` array-like property::
casper.start('http://foo.bar/').then(function() {
this.test.assertTitle('Main page title');
this.clickLabel('Open me a popup');
});
// this will wait for the popup to be opened and loaded
casper.waitForPopup(/popup\.html$/, function() {
this.test.assertEquals(this.popups.length, 1);
});
// this will set the popup DOM as the main active one only for time the
// step closure being executed
casper.withPopup(/popup\.html$/, function() {
this.test.assertTitle('Popup title');
});
// next step will automatically revert the current page to the initial one
casper.then(function() {
this.test.assertTitle('Main page title');
});
.. index:: HTTP, Asynchronicity
``waitForResource()``
-------------------------------------------------------------------------------
**Signature:** ``waitForResource(Function testFx[, Function then, Function onTimeout, Number timeout])``
Wait until a resource that matches the given ``testFx`` is loaded to process a next step. Uses `waitFor()`_::
casper.start('http://foo.bar/');
casper.waitForResource("foobar.png", function() {
this.echo('foobar.png has been loaded.');
});
casper.run();
.. index:: selector
``waitForSelector()``
-------------------------------------------------------------------------------
**Signature:** ``waitForSelector(String selector[, Function then, Function onTimeout, Number timeout])``
Waits until an element matching the provided :doc:`selector expression <../selectors>` exists in remote DOM to process any next step. Uses `waitFor()`_::
casper.start('https://twitter.com/#!/n1k0');
casper.waitForSelector('.tweet-row', function() {
this.captureSelector('twitter.png', 'html');
});
casper.run();
.. index:: selector
``waitWhileSelector()``
-------------------------------------------------------------------------------
**Signature:** ``waitWhileSelector(String selector[, Function then, Function onTimeout, Number timeout])``
Waits until an element matching the provided :doc:`selector expression <../selectors>` does not exist in remote DOM to process a next step. Uses `waitFor()`_::
casper.start('http://foo.bar/');
casper.waitWhileSelector('.selector', function() {
this.echo('.selector is no more!');
});
casper.run();
``waitForSelectorTextChange()``
-------------------------------------------------------------------------------
**Signature:** ``waitForSelectorTextChange(String selectors[, Function then, Function onTimeout, Number timeout])``
Waits until the text on an element matching the provided :doc:`selector expression <../selectors>`
is changed to a different value before processing the next step. Uses `waitFor()`_::
casper.start('http://foo.bar/');
casper.waitForSelectorTextChange('.selector', function() {
this.echo('The text on .selector has been changed.);
});
casper.run();
``waitForText()``
-------------------------------------------------------------------------------
**Signature:** ``waitForText(String text[, Function then, Function onTimeout, Number timeout])``
.. versionadded:: 1.0
Waits until the passed text is present in the page contents before processing the immediate next step. Uses `waitFor()`_::
casper.start('http://why.univer.se/').waitForText("42", function() {
this.echo('Found the answer.');
});
casper.run();
``waitUntilVisible()``
-------------------------------------------------------------------------------
**Signature:** ``waitUntilVisible(String selector[, Function then, Function onTimeout, Number timeout])``
Waits until an element matching the provided :doc:`selector expression <../selectors>` is visible in the remote DOM to process a next step. Uses `waitFor()`_.
``waitWhileVisible()``
-------------------------------------------------------------------------------
**Signature:** ``waitWhileVisible(String selector[, Function then, Function onTimeout, Number timeout])``
Waits until an element matching the provided :doc:`selector expression <../selectors>` is no longer visible in remote DOM to process a next step. Uses `waitFor()`_.
``warn()``
-------------------------------------------------------------------------------
**Signature:** ``warn(String message)``
Logs and prints a warning message to the standard output::
casper.warn("I'm a warning message.");
.. note::
Calling ``warn()`` will trigger the ``warn`` :ref:`event <events_filters>`.
.. index:: Frames, Iframes, Framesets
``withFrame()``
-------------------------------------------------------------------------------
**Signature:** ``withFrame(String|Number frameInfo, Function then)``
.. versionadded:: 1.0
Switches the main page to the frame having the name or frame index number matching the passed argument, and processes a step.
The page context switch only lasts until the step execution is finished::
casper.start('tests/site/frames.html', function() {
this.test.assertTitle('FRAMESET TITLE');
});
casper.withFrame('frame1', function() {
this.test.assertTitle('FRAME TITLE');
});
casper.withFrame(0, function() {
this.test.assertTitle('FRAME TITLE');
});
casper.then(function() {
this.test.assertTitle('FRAMESET TITLE');
});
.. _casper_withpopup:
.. index:: Popups, New window, window.open, Tabs
``withPopup()``
-------------------------------------------------------------------------------
**Signature:** ``withPopup(Mixed popupInfo, Function then)``
.. versionadded:: 1.0
Switches the main page to a popup matching the information passed as argument, and processes a step. The page context switch only lasts until the step execution is finished::
casper.start('http://foo.bar/').then(function() {
this.test.assertTitle('Main page title');
this.clickLabel('Open me a popup');
});
// this will wait for the popup to be opened and loaded
casper.waitForPopup(/popup\.html$/, function() {
this.test.assertEquals(this.popups.length, 1);
});
// this will set the popup DOM as the main active one only for time the
// step closure being executed
casper.withPopup(/popup\.html$/, function() {
this.test.assertTitle('Popup title');
});
// next step will automatically revert the current page to the initial one
casper.then(function() {
this.test.assertTitle('Main page title');
});
.. note::
The currently loaded popups are available in the ``Casper.popups`` array-like property.
.. index:: Zoom
``zoom()``
-------------------------------------------------------------------------------
**Signature:** ``zoom(Number factor)``
.. versionadded:: 1.0
Sets the current page zoom factor::
var casper = require('casper').create();
casper.start().zoom(2).thenOpen('http://google.com', function() {
this.capture('big-google.png');
});
casper.run();
.. _clientutils_module:
.. index:: Client utils, __utils__, DOM
==========================
The ``clientutils`` module
==========================
Casper ships with a few client-side utilities which are injected in the remote DOM environment, and accessible from there through the ``__utils__`` object instance of the ``ClientUtils`` class from the ``clientutils`` module.
.. note::
These tools are provided to avoid coupling CasperJS to any third-party library like :index:`jQuery`, Mootools or something; but you can always include these and have them available client-side using the :ref:`Casper.options.clientScripts <casper_option_clientscripts>` option.
.. _bookmarklet:
.. index:: bookmarklet, DOM, Debugging
Bookmarklet
+++++++++++
A bookmarklet is also available to help injecting Casper's client-side utilities in the DOM of your favorite browser.
Just drag the link above onto your favorites toobar; when clicking, a ``__utils__`` object will be available within the console of your browser:
.. raw:: html
<div class="bookmarklet">
<a href="javascript:(function(){void(function(){if(!document.getElementById('CasperUtils')){var%20CasperUtils=document.createElement('script');CasperUtils.id='CasperUtils';CasperUtils.src='https://raw.github.com/n1k0/casperjs/master/modules/clientutils.js';document.documentElement.appendChild(CasperUtils);var%20interval=setInterval(function(){if(typeof%20ClientUtils==='function'){window.__utils__=new%20window.ClientUtils();clearInterval(interval);}},50);}}());})();">CasperJS Utils</a>
</div>
.. note::
CasperJS and PhantomJS being based on `Webkit <http://webkit.org/>`_, you're strongly encouraged to use a recent Webkit compatible browser to use this bookmarklet (Chrome, Safari, etc…)
.. _clientutils_prototype:
``ClientUtils`` prototype
+++++++++++++++++++++++++
.. index:: echo
``echo()``
-------------------------------------------------------------------------------
**Signature:** ``echo(String message)``
.. versionadded:: 1.0
Print a message out to the casper console from the remote page DOM environment::
casper.start('http://foo.ner/').thenEvaluate(function() {
__utils__.echo('plop'); // this will be printed to your shell at runtime
});
.. index:: Base64
``encode()``
-------------------------------------------------------------------------------
**Signature:** ``encode(String contents)``
Encodes a string using the `base64 algorithm <http://en.wikipedia.org/wiki/Base64>`_. For the records, CasperJS doesn't use builtin ``window.btoa()`` function because it can't deal efficiently with strings encoded using >8b characters::
var base64;
casper.start('http://foo.bar/', function() {
base64 = this.evaluate(function() {
return __utils__.encode("I've been a bit cryptic recently");
});
});
casper.run(function() {
this.echo(base64).exit();
});
.. index:: DOM
``exists()``
-------------------------------------------------------------------------------
**Signature:** ``exists(String selector)``
Checks if a DOM element matching a given :ref:`selector expression <selectors>` exists::
var exists;
casper.start('http://foo.bar/', function() {
exists = this.evaluate(function() {
return __utils__.exists('#some_id');
});
});
casper.run(function() {
this.echo(exists).exit();
});
``findAll()``
-------------------------------------------------------------------------------
**Signature:** ``findAll(String selector)``
Retrieves all DOM elements matching a given :ref:`selector expression <selectors>`::
var links;
casper.start('http://foo.bar/', function() {
links = this.evaluate(function() {
var elements = __utils__.findAll('a.menu');
return Array.prototype.forEach.call(elements, function(e) {
return e.getAttribute('href');
});
});
});
casper.run(function() {
this.echo(JSON.stringify(links)).exit();
});
``findOne()``
-------------------------------------------------------------------------------
**Signature:** ``findOne(String selector)``
Retrieves a single DOM element by a :ref:`selector expression <selectors>`::
var href;
casper.start('http://foo.bar/', function() {
href = this.evaluate(function() {
return __utils__.findOne('#my_id').getAttribute('href');
});
});
casper.run(function() {
this.echo(href).exit();
});
.. index:: Base64
``getBase64()``
-------------------------------------------------------------------------------
**Signature:** ``getBase64(String url[, String method, Object data])``
This method will retrieved a base64 encoded version of any resource behind a url. For example, let's imagine we want to retrieve the base64 representation of some website's logo::
var logo = null;
casper.start('http://foo.bar/', function() {
logo = this.evaluate(function() {
var imgUrl = document.querySelector('img.logo').getAttribute('src');
return __utils__.getBase64(imgUrl);
});
});
casper.run(function() {
this.echo(logo).exit();
});
.. index:: Binary
``getBinary()``
-------------------------------------------------------------------------------
**Signature:** ``getBinary(String url[, String method, Object data])``
This method will retrieved the raw contents of a given binary resource; unfortunately though, PhantomJS cannot process these data directly so you'll have to process them within the remote DOM environment. If you intend to download the resource, use `getBase64()`_ or :ref:`Casper.base64encode() <casper_base64encode>` instead::
casper.start('http://foo.bar/', function() {
this.evaluate(function() {
var imgUrl = document.querySelector('img.logo').getAttribute('src');
console.log(__utils__.getBinary(imgUrl));
});
});
casper.run();
``getDocumentHeight()``
-------------------------------------------------------------------------------
**Signature:** ``getDocumentHeight()``
.. versionadded:: 1.0
Retrieves current document height::
var documentHeight;
casper.start('http://google.com/', function() {
documentHeight = this.evaluate(function() {
return __utils__.getDocumentHeight();
});
this.echo('Document height is ' + documentHeight + 'px');
});
casper.run();
``getElementBounds()``
-------------------------------------------------------------------------------
**Signature:** ``getElementBounds(String selector)``
Retrieves boundaries for a DOM elements matching the provided :ref:`selector <selectors>`.
It returns an Object with four keys: ``top``, ``left``, ``width`` and ``height``, or ``null`` if the selector doesn't exist.
``getElementsBounds()``
-------------------------------------------------------------------------------
**Signature:** ``getElementsBounds(String selector)``
Retrieves boundaries for all DOM element matching the provided :ref:`selector <selectors>`.
It returns an array of objects each having four keys: ``top``, ``left``, ``width`` and ``height``.
.. index:: XPath
``getElementByXPath()``
-------------------------------------------------------------------------------
**Signature:** ``getElementByXPath(String expression [, HTMLElement scope])``
Retrieves a single DOM element matching a given :ref:`XPath expression <selectors>`.
.. versionadded:: 1.0
The ``scope`` argument allow to set the context for executing the XPath query::
// will be performed against the whole document
__utils__.getElementByXPath('.//a');
// will be performed against a given DOM element
__utils__.getElementByXPath('.//a', __utils__.findOne('div.main'));
.. index:: XPath
``getElementsByXPath()``
-------------------------------------------------------------------------------
**Signature:** ``getElementsByXPath(String expression [, HTMLElement scope])``
Retrieves all DOM elements matching a given :ref:`XPath expression <selectors>`, if any.
.. versionadded:: 1.0
The ``scope`` argument allows to set the context for executing the XPath query.
.. index:: Form
``getFieldValue()``
-------------------------------------------------------------------------------
**Signature:** ``getFieldValue(String inputName)``
.. versionadded:: 1.0
Retrieves the value from the field named against the ``inputNamed`` argument:
.. code-block:: html
<form>
<input type="text" name="plop" value="42">
</form>
Using the ``getFieldValue()`` method for ``plop``::
__utils__.getFieldValue('plop'); // 42
.. index:: Form
``getFormValues()``
-------------------------------------------------------------------------------
**Signature:** ``getFormValues(String selector)``
.. versionadded:: 1.0
Retrieves a given form and all of its field values:
.. code-block:: html
<form id="login" action="/login">
<input type="text" name="username" value="foo">
<input type="text" name="password" value="bar">
<input type="submit">
</form>
To get the form values::
__utils__.getFormValues('form#login'); // {username: 'foo', password: 'bar'}
``mouseEvent()``
-------------------------------------------------------------------------------
**Signature:** ``mouseEvent(String type, String selector)``
Dispatches a mouse event to the DOM element behind the provided selector.
Supported events are ``mouseup``, ``mousedown``, ``click``, ``mousemove``, ``mouseover`` and ``mouseout``.
.. index:: XPath
``removeElementsByXPath()``
-------------------------------------------------------------------------------
**Signature:** ``removeElementsByXPath(String expression)``
Removes all DOM elements matching a given :ref:`XPath expression <selectors>`.
.. index:: AJAX
``sendAJAX()``
-----------------------------------------------------------------------------
**Signature:** ``sendAJAX(String url[, String method, Object data, Boolean async])``
.. versionadded:: 1.0
Sends an AJAX request, using the following parameters:
- ``url``: The url to request.
- ``method``: The HTTP method (default: ``GET``).
- ``data``: Request parameters (default: ``null``).
- ``async``: Flag for an asynchroneous request? (default: ``false``)
.. warning::
Don't forget to pass the ``--web-security=no`` option in your CLI call in order to perform cross-domains requests when needed::
var data, wsurl = 'http://api.site.com/search.json';
casper.start('http://my.site.com/', function() {
data = this.evaluate(function(wsurl) {
return JSON.parse(__utils__.sendAJAX(wsurl, 'GET', null, false));
}, {wsurl: wsurl});
});
casper.then(function() {
require('utils').dump(data);
});
``visible()``
-------------------------------------------------------------------------------
**Signature:** ``visible(String selector)``
Checks if an element is visible::
var logoIsVisible = casper.evaluate(function() {
return __utils__.visible('h1');
});
.. _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:
*
.. _tester_module:
.. index:: Testing
=====================
The ``tester`` module
=====================
Casper ships with a ``tester`` module and a ``Tester`` class providing an API for unit & functional testing purpose. By default you can access an instance of this class through the ``test`` property of any ``Casper`` class instance.
.. note::
The best way to learn how to use the Tester API and see it in action is probably to have a look at `CasperJS' own test suites <https://github.com/n1k0/casperjs/blob/master/tests/suites/>`_.
The ``Tester`` prototype
++++++++++++++++++++++++
``assert()``
-------------------------------------------------------------------------------
**Signature:** ``assert(Boolean condition[, String message])``
Asserts that the provided condition strictly resolves to a boolean ``true``::
casper.test.assert(true, "true's true");
casper.test.assert(!false, "truth is out");
.. seealso:: `assertNot()`_
.. index:: DOM
``assertDoesntExist()``
-------------------------------------------------------------------------------
**Signature:** ``assertDoesntExist(String selector[, String message])``
Asserts that an element matching the provided :ref:`selector expression <selectors>` doesn't exists within the remote DOM environment::
casper.test.begin('assertDoesntExist() tests', 1, function(test) {
casper.start().then(function() {
this.setContent('<div class="heaven"></div>');
test.assertDoesntExist('.taxes');
}).run(function() {
test.done();
});
});
.. seealso:: `assertExists()`_
``assertEquals()``
-------------------------------------------------------------------------------
**Signature:** ``assertEquals(mixed testValue, mixed expected[, String message])``
Asserts that two values are strictly equivalent::
casper.test.begin('assertEquals() tests', 3, function(test) {
test.assertEquals(1 + 1, 2);
test.assertEquals([1, 2, 3], [1, 2, 3]);
test.assertEquals({a: 1, b: 2}, {a: 1, b: 2});
test.done();
});
.. seealso:: `assertNotEquals()`_
.. index:: evaluate
``assertEval()``
-------------------------------------------------------------------------------
**Signature:** ``assertEval(Function fn[, String message, Mixed arguments])``
Asserts that a :ref:`code evaluation in remote DOM <casper_evaluate>` strictly resolves to a boolean ``true``::
casper.test.begin('assertEval() tests', 1, function(test) {
casper.start().then(function() {
this.setContent('<div class="heaven">beer</div>');
test.assertEval(function() {
return __utils__.findOne('.heaven').textContent === 'beer';
});
}).run(function() {
test.done();
});
});
``assertEvalEquals()``
-------------------------------------------------------------------------------
**Signature:** ``assertEvalEquals(Function fn, mixed expected[, String message, Mixed arguments])``
Asserts that the result of a :ref:`code evaluation in remote DOM <casper_evaluate>` strictly equals to the expected value::
casper.test.begin('assertEvalEquals() tests', 1, function(test) {
casper.start().then(function() {
this.setContent('<div class="heaven">beer</div>');
test.assertEvalEquals(function() {
return __utils__.findOne('.heaven').textContent;
}, 'beer');
}).run(function() {
test.done();
});
});
.. _tester_assertelementcount:
``assertElementCount()``
-------------------------------------------------------------------------------
**Signature:** ``assertElementCount(String selector, Number count[, String message])``
Asserts that a :ref:`selector expression <selectors>` matches a given number of elements::
casper.test.begin('assertElementCount() tests', 3, function(test) {
casper.start().then(function() {
this.page.content = '<ul><li>1</li><li>2</li><li>3</li></ul>';
test.assertElementCount('ul', 1);
test.assertElementCount('li', 3);
test.assertElementCount('address', 0);
}).run(function() {
test.done();
});
});
.. index:: DOM
``assertExists()``
-------------------------------------------------------------------------------
**Signature:** ``assertExists(String selector[, String message])``
Asserts that an element matching the provided :ref:`selector expression <selectors>` exists in remote DOM environment::
casper.test.begin('assertExists() tests', 1, function(test) {
casper.start().then(function() {
this.setContent('<div class="heaven">beer</div>');
test.assertExists('.heaven');
}).run(function() {
test.done();
});
});
.. seealso:: `assertDoesntExist()`_
.. index:: falsiness
``assertFalsy()``
-------------------------------------------------------------------------------
**Signature:** ``assertFalsy(Mixed subject[, String message])``
.. versionadded:: 1.0
Asserts that a given subject is `falsy <http://11heavens.com/falsy-and-truthy-in-javascript>`_.
.. seealso:: `assertTruthy()`_
.. index:: Form
``assertField()``
-------------------------------------------------------------------------------
**Signature:** ``assertField(String inputName, String expected[, String message])``
Asserts that a given form field has the provided value::
casper.test.begin('assertField() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
this.fill('form[name="gs"]', { q: 'plop' }, false);
test.assertField('q', 'plop');
}).run(function() {
test.done();
});
});
.. versionadded:: 1.0
This also works with any input type: ``select``, ``textarea``, etc.
.. index:: HTTP, HTTP Status Code
``assertHttpStatus()``
-------------------------------------------------------------------------------
**Signature:** ``assertHttpStatus(Number status[, String message])``
Asserts that current `HTTP status code <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ is the same as the one passed as argument::
casper.test.begin('casperjs.org is up and running', 1, function(test) {
casper.start('http://casperjs.org/', function() {
test.assertHttpStatus(200);
}).run(function() {
test.done();
});
});
``assertMatch()``
-------------------------------------------------------------------------------
**Signature:** ``assertMatch(mixed subject, RegExp pattern[, String message])``
Asserts that a provided string matches a provided javascript ``RegExp`` pattern::
casper.test.assertMatch('Chuck Norris', /^chuck/i, 'Chuck Norris' first name is Chuck');
.. seealso::
- `assertUrlMatch()`_
- `assertTitleMatch()`_
``assertNot()``
-------------------------------------------------------------------------------
**Signature:** ``assertNot(mixed subject[, String message])``
Asserts that the passed subject resolves to some `falsy value <http://11heavens.com/falsy-and-truthy-in-javascript>`_::
casper.test.assertNot(false, "Universe is still operational");
.. seealso:: `assert()`_
``assertNotEquals()``
-------------------------------------------------------------------------------
**Signature:** ``assertNotEquals(mixed testValue, mixed expected[, String message])``
.. versionadded:: 0.6.7
Asserts that two values are **not** strictly equals::
casper.test.assertNotEquals(true, "true");
.. seealso:: `assertEquals()`_
``assertNotVisible()``
-------------------------------------------------------------------------------
**Signature:** ``assertNotVisible(String selector[, String message])``
Asserts that the element matching the provided :ref:`selector expression <selectors>` is not visible::
casper.test.begin('assertNotVisible() tests', 1, function(test) {
casper.start().then(function() {
this.setContent('<div class=".foo" style="display:none>boo</div>');
test.assertNotVisible('.foo');
}).run(function() {
test.done();
});
});
.. seealso:: `assertVisible()`_
.. index:: error
``assertRaises()``
-------------------------------------------------------------------------------
**Signature:** ``assertRaises(Function fn, Array args[, String message])``
Asserts that the provided function called with the given parameters raises a javascript ``Error``::
casper.test.assertRaises(function(throwIt) {
if (throwIt) {
throw new Error('thrown');
}
}, [true], 'Error has been raised.');
casper.test.assertRaises(function(throwIt) {
if (throwIt) {
throw new Error('thrown');
}
}, [false], 'Error has been raised.'); // fails
``assertSelectorDoesntHaveText()``
-------------------------------------------------------------------------------
**Signature:** ``assertSelectorDoesntHaveText(String selector, String text[, String message])``
Asserts that given text does not exist in all the elements matching the provided :ref:`selector expression <selectors>`::
casper.test.begin('assertSelectorDoesntHaveText() tests', 1, function(test) {
casper.start('http://google.com/', function() {
test.assertSelectorDoesntHaveText('title', 'Yahoo!');
}).run(function() {
test.done();
});
});
.. seealso:: `assertSelectorHasText()`_
.. index:: selector, DOM
``assertSelectorHasText()``
-------------------------------------------------------------------------------
**Signature:** ``assertSelectorHasText(String selector, String text[, String message])``
Asserts that given text exists in elements matching the provided :ref:`selector expression <selectors>`::
casper.test.begin('assertSelectorHasText() tests', 1, function(test) {
casper.start('http://google.com/', function() {
test.assertSelectorDoesntHaveText('title', 'Google');
}).run(function() {
test.done();
});
});
.. seealso:: `assertSelectorDoesntHaveText()`_
.. index:: HTTP
``assertResourceExists()``
-------------------------------------------------------------------------------
**Signature:** ``assertResourceExists(Function testFx[, String message])``
The ``testFx`` function is executed against all loaded assets and the test passes when at least one resource matches::
casper.test.begin('assertResourceExists() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertResourceExists(function(resource) {
return resource.url.match('logo3w.png');
});
}).run(function() {
test.done();
});
});
Shorter::
casper.test.begin('assertResourceExists() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertResourceExists('logo3w.png');
}).run(function() {
test.done();
});
});
.. hint::
Check the documentation for :ref:`Casper.resourceExists() <casper_resourceexists>`.
``assertTextExists()``
-------------------------------------------------------------------------------
**Signature:** ``assertTextExists(String expected[, String message])``
Asserts that body **plain text content** contains the given string::
casper.test.begin('assertTextExists() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertTextExists('google', 'page body contains "google"');
}).run(function() {
test.done();
});
});
.. seealso:: `assertTextDoesntExist()`_
``assertTextDoesntExist()``
-------------------------------------------------------------------------------
**Signature:** ``assertTextDoesntExist(String unexpected[, String message])``
.. versionadded:: 1.0
Asserts that body **plain text content** doesn't contain the given string::
casper.test.begin('assertTextDoesntExist() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertTextDoesntExist('bing', 'page body does not contain "bing"');
}).run(function() {
test.done();
});
});
.. seealso:: `assertTextExists()`_
``assertTitle()``
-------------------------------------------------------------------------------
**Signature:** ``assertTitle(String expected[, String message])``
Asserts that title of the remote page equals to the expected one::
casper.test.begin('assertTitle() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertTitle('Google', 'google.fr has the correct title');
}).run(function() {
test.done();
});
});
.. seealso:: `assertTitleMatch()`_
``assertTitleMatch()``
-------------------------------------------------------------------------------
**Signature:** ``assertTitleMatch(RegExp pattern[, String message])``
Asserts that title of the remote page matches the provided RegExp pattern::
casper.test.begin('assertTitleMatch() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertTitleMatch(/Google/, 'google.fr has a quite predictable title');
}).run(function() {
test.done();
});
});
.. seealso:: `assertTitle()`_
.. index:: truthiness
``assertTruthy()``
-------------------------------------------------------------------------------
**Signature:** ``assertTruthy(Mixed subject[, String message])``
.. versionadded:: 1.0
Asserts that a given subject is `truthy <http://11heavens.com/falsy-and-truthy-in-javascript>`_.
.. seealso:: `assertFalsy()`_
.. index:: Type
``assertType()``
-------------------------------------------------------------------------------
**Signature:** ``assertType(mixed input, String type[, String message])``
Asserts that the provided input is of the given type::
casper.test.begin('assertType() tests', 1, function suite(test) {
test.assertType(42, "number", "Okay, 42 is a number");
test.assertType([1, 2, 3], "array", "We can test for arrays too!");
test.done();
});
.. note:: Type names are always expressed in lower case.
.. index:: URL
``assertUrlMatch()``
-------------------------------------------------------------------------------
**Signature:** ``assertUrlMatch(Regexp pattern[, String message])``
Asserts that the current page url matches the provided RegExp pattern::
casper.test.begin('assertUrlMatch() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertUrlMatch(/^http:\/\//', 'google.fr is served in http://');
}).run(function() {
test.done();
});
});
.. index:: DOM
``assertVisible()``
-------------------------------------------------------------------------------
**Signature:** ``assertVisible(String selector[, String message])``
Asserts that the element matching the provided :ref:`selector expression <selectors>` is visible::
casper.test.begin('assertVisible() tests', 1, function(test) {
casper.start('http://www.google.fr/', function() {
test.assertVisible('h1');
}).run(function() {
test.done();
});
});
.. seealso:: `assertNotVisible()`_
.. _tester_begin:
.. index:: Test suite, planned tests, Asynchronicity, Termination
``begin()``
-------------------------------------------------------------------------------
**Signatures:**
- ``begin(String description, Number planned, Function suite)``
- ``begin(String description, Function suite)``
- ``begin(String description, Number planned, Object config)``
- ``begin(String description, Object config)``
.. versionadded:: 1.1
Starts a suite of ``<planned>`` tests (if defined). The ``suite`` callback will get the current ``Tester`` instance as its first argument::
function Cow() {
this.mowed = false;
this.moo = function moo() {
this.mowed = true; // mootable state: don't do that
return 'moo!';
};
}
// unit style synchronous test case
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();
});
.. note::
The ``planned`` argument is especially useful in case a given test script is abruptly interrupted leaving you with no obvious way to know it and an erroneously successful status.
A more asynchronous example::
casper.test.begin('Casperjs.org is navigable', 2, function suite(test) {
casper.start('http://casperjs.org/', function() {
test.assertTitleMatches(/casperjs/i);
this.clickLabel('Testing');
});
casper.then(function() {
test.assertUrlMatches(/testing\.html$/);
});
casper.run(function() {
test.done();
});
});
.. important::
`done()`_ **must** be called in order to terminate the suite. This is specially important when doing asynchronous tests so ensure it's called when everything has actually been performed.
.. seealso:: `done()`_
``Tester#begin()`` also accepts a test configuration object, so you can add ``setUp()`` and ``tearDown()`` methods::
// 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();
}
});
.. index:: Colors
``colorize()``
-------------------------------------------------------------------------------
**Signature:** ``colorize(String message, String style)``
Render a colorized output. Basically a proxy method for ``Casper.Colorizer#colorize()``.
``comment()``
-------------------------------------------------------------------------------
**Signature:** ``comment(String message)``
Writes a comment-style formatted message to stdout::
casper.test.comment("Hi, I'm a comment");
.. _tester_done:
.. index:: Test suite, Asynchronicity, Termination, done()
``done()``
-------------------------------------------------------------------------------
**Signature:** ``done()``
.. versionchanged:: 1.1 ``planned`` parameter is deprecated
Flag a test suite started with `begin()`_ as processed::
casper.test.begin('my test suite', 2, function(test) {
test.assert(true);
test.assertNot(false);
test.done();
});
More asynchronously::
casper.test.begin('Casperjs.org is navigable', 2, function suite(test) {
casper.start('http://casperjs.org/', function() {
test.assertTitleMatches(/casperjs/i);
this.clickLabel('Testing');
});
casper.then(function() {
test.assertUrlMatches(/testing\.html$/);
});
casper.run(function() {
test.done();
});
});
.. seealso:: `begin()`_
``error()``
-------------------------------------------------------------------------------
**Signature:** ``error(String message)``
Writes an error-style formatted message to stdout::
casper.test.error("Hi, I'm an error");
.. index:: Test failure
``fail()``
-------------------------------------------------------------------------------
**Signature:** ``fail(String message)``
Adds a failed test entry to the stack::
casper.test.fail("Georges W. Bush");
.. seealso:: `pass()`_
``formatMessage()``
-------------------------------------------------------------------------------
**Signature:** ``formatMessage(String message, String style)``
Formats a message to highlight some parts of it. Only used internally by the tester.
``getFailures()``
-------------------------------------------------------------------------------
**Signature:** ``getFailures()``
.. versionadded:: 1.0
Retrieves failures for current test suite::
casper.test.assertEquals(true, false);
require('utils').dump(casper.test.getFailures());
casper.test.done();
That will give something like this:
.. code-block:: text
$ casperjs test test-getFailures.js
Test file: test-getFailures.js
FAIL Subject equals the expected value
# type: assertEquals
# subject: true
# expected: false
{
"length": 1,
"cases": [
{
"success": false,
"type": "assertEquals",
"standard": "Subject equals the expected value",
"file": "test-getFailures.js",
"values": {
"subject": true,
"expected": false
}
}
]
}
FAIL 1 tests executed, 0 passed, 1 failed.
Details for the 1 failed test:
In c.js:0
assertEquals: Subject equals the expected value
``getPasses()``
-------------------------------------------------------------------------------
**Signature:** ``getPasses()``
.. versionadded:: 1.0
Retrieves a report for successful test cases in the current test suite::
casper.test.assertEquals(true, true);
require('utils').dump(casper.test.getPasses());
casper.test.done();
That will give something like this::
$ casperjs test test-getPasses.js
Test file: test-getPasses.js
PASS Subject equals the expected value
{
"length": 1,
"cases": [
{
"success": true,
"type": "assertEquals",
"standard": "Subject equals the expected value",
"file": "test-getPasses.js",
"values": {
"subject": true,
"expected": true
}
}
]
}
PASS 1 tests executed, 1 passed, 0 failed.
``info()``
-------------------------------------------------------------------------------
**Signature:** ``info(String message)``
Writes an info-style formatted message to stdout::
casper.test.info("Hi, I'm an informative message.");
.. index:: Test success
``pass()``
-------------------------------------------------------------------------------
**Signature:** ``pass(String message)``
Adds a successful test entry to the stack::
casper.test.pass("Barrack Obama");
.. seealso:: `fail()`_
``renderResults()``
-------------------------------------------------------------------------------
**Signature:** ``renderResults(Boolean exit, Number status, String save)``
Render test results, save results in an XUnit formatted file, and optionally exits phantomjs::
casper.test.renderResults(true, 0, 'test-results.xml');
.. note::
This method is not to be called when using the ``casperjs test`` command (see documentation for :doc:`testing <../testing>`), where it's done automatically for you.
``skip()``
-------------------------------------------------------------------------------
**Signature:** ``skip(Number nb, String message)``
Skips a given number of planned tests::
casper.test.begin('Skip tests', 4, function(test) {
test.assert(true, 'First test executed');
test.assert(true, 'Second test executed');
test.skip(2, 'Two tests skipped');
test.done();
});
.. _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"