local docs - fixes #393
Showing
36 changed files
with
8034 additions
and
0 deletions
docs/Makefile
0 → 100644
docs/README.md
0 → 100644
docs/TODO.md
0 → 100644
1 | - credits jeremy (logo) |
docs/_static/casperjs-favicon.ico
0 → 100644
No preview for this file type
docs/_themes/casperjs/addon.html
0 → 100644
1 | <h3>Donate</h3> | ||
2 | <div class="donate"> | ||
3 | <div class="paypal"> | ||
4 | <form action="https://www.paypal.com/cgi-bin/webscr" method="post"> | ||
5 | <input type="hidden" name="cmd" value="_s-xclick"> | ||
6 | <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-----"> | ||
7 | <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="Donate" title="Donate"> | ||
8 | <img alt="" border="0" src="https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif" width="1" height="1"> | ||
9 | </form> | ||
10 | <small>(ghosts have bills, you know)</small> | ||
11 | </div> | ||
12 | <div class="flattr"> | ||
13 | <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> | ||
14 | </div> | ||
15 | </div> |
docs/_themes/casperjs/layout.html
0 → 100644
1 | {%- extends "basic/layout.html" %} | ||
2 | {% block extrahead %} | ||
3 | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic&subset=latin,latin-ext"> | ||
4 | <link rel="stylesheet" title="Dark theme" href="{{ pathto('_static/casperjs-dark.css', 1) }}"> | ||
5 | <link rel="alternate stylesheet" title="Light theme" href="{{ pathto('_static/casperjs-light.css', 1) }}"> | ||
6 | <script type="text/javascript" src="{{ pathto('_static/style-switcher.js', 1) }}"></script> | ||
7 | {% endblock extrahead %} |
docs/_themes/casperjs/localtoc.html
0 → 100644
docs/_themes/casperjs/sourcelink.html
0 → 100644
1 | <h3>Index</h3> | ||
2 | <p><a href="{{ pathto('genindex') }}">Thesaurus</a></p> | ||
3 | |||
4 | {%- if show_source and has_source and sourcename %} | ||
5 | <h3>{{ _('This Page') }}</h3> | ||
6 | <ul class="this-page-menu"> | ||
7 | <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}" | ||
8 | rel="nofollow">{{ _('Show Source') }}</a></li> | ||
9 | {% if display_github %} | ||
10 | <li><a href="https://github.com/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}.rst"> | ||
11 | Show on GitHub</a></li> | ||
12 | <li><a href="https://github.com/{{ github_user }}/{{ github_repo }}/edit/{{ github_version }}{{ conf_py_path }}{{ pagename }}.rst"> | ||
13 | Edit on GitHub</a></li> | ||
14 | {% endif %} | ||
15 | </ul> | ||
16 | {%- endif %} |
1 | /** | ||
2 | * casper.css | ||
3 | * ~~~~~~~~~~~~~~~ | ||
4 | * | ||
5 | * CasperJS stylesheet, based on RTD one: | ||
6 | * | ||
7 | * Sphinx stylesheet -- sphinxdoc theme. Originally created by | ||
8 | * Armin Ronacher for Werkzeug. | ||
9 | * | ||
10 | * Customized for ReadTheDocs by Eric Pierce & Eric Holscher | ||
11 | * | ||
12 | * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. | ||
13 | * :license: BSD, see LICENSE for details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | @import url("basic.css"); | ||
18 | |||
19 | /* PAGE LAYOUT -------------------------------------------------------------- */ | ||
20 | |||
21 | body { | ||
22 | font: 100%/1.5 Asap, "ff-meta-web-pro-1", "ff-meta-web-pro-2", Arial, "Helvetica Neue", sans-serif; | ||
23 | text-align: center; | ||
24 | color: #fff; | ||
25 | background-color: #222; | ||
26 | padding: 0; | ||
27 | margin: 0; | ||
28 | } | ||
29 | |||
30 | img { | ||
31 | border: 0; | ||
32 | max-width: 100%; | ||
33 | } | ||
34 | |||
35 | .body > .admonition.note { | ||
36 | margin: 0 0 2em 0; | ||
37 | } | ||
38 | .body > .admonition.note .first { | ||
39 | display: none; | ||
40 | } | ||
41 | |||
42 | div.document { | ||
43 | text-align: left; | ||
44 | background-color: #333; | ||
45 | } | ||
46 | |||
47 | div.bodywrapper { | ||
48 | background: #111 url(images/bg.png); | ||
49 | border-left: 1px solid #333; | ||
50 | border-bottom: 1px solid #333; | ||
51 | margin: 0 18em 0 0; | ||
52 | } | ||
53 | |||
54 | div.body { | ||
55 | margin: 0; | ||
56 | padding: 0.5em 1.3em; | ||
57 | min-width: 20em; | ||
58 | } | ||
59 | |||
60 | div.related { | ||
61 | font-size: 1em; | ||
62 | background-color: #465158; | ||
63 | } | ||
64 | |||
65 | div.documentwrapper { | ||
66 | float: left; | ||
67 | width: 100%; | ||
68 | background-color: #333; | ||
69 | } | ||
70 | |||
71 | |||
72 | /* HEADINGS --------------------------------------------------------------- */ | ||
73 | |||
74 | h1 { | ||
75 | margin: 0; | ||
76 | padding: 0 0 0.3em 0; | ||
77 | font-size: 2em; | ||
78 | line-height: 1.15; | ||
79 | color: #fff; | ||
80 | clear: both; | ||
81 | } | ||
82 | |||
83 | h2 { | ||
84 | margin: 2em 0 0.2em 0; | ||
85 | font-size: 1.35em; | ||
86 | padding: 0; | ||
87 | color: #fff; | ||
88 | } | ||
89 | .section h2 { | ||
90 | border-bottom: 3px solid #777; | ||
91 | margin-top: 2.5em | ||
92 | } | ||
93 | |||
94 | h3 { | ||
95 | margin: 1em 0 -0.3em 0; | ||
96 | font-size: 1.2em; | ||
97 | color: #fff; | ||
98 | } | ||
99 | |||
100 | div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { | ||
101 | color: #fff; | ||
102 | } | ||
103 | |||
104 | h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { | ||
105 | display: none; | ||
106 | margin: 0 0 0 0.3em; | ||
107 | padding: 0 0.2em 0 0.2em; | ||
108 | color: #333 !important; | ||
109 | } | ||
110 | |||
111 | h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, | ||
112 | h5:hover a.anchor, h6:hover a.anchor { | ||
113 | display: inline; | ||
114 | } | ||
115 | |||
116 | h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, | ||
117 | h5 a.anchor:hover, h6 a.anchor:hover { | ||
118 | color: #777; | ||
119 | background-color: #eee; | ||
120 | } | ||
121 | |||
122 | |||
123 | /* LINKS ------------------------------------------------------------------ */ | ||
124 | |||
125 | /* Normal links get a pseudo-underline */ | ||
126 | a { | ||
127 | color: #0bc; | ||
128 | text-decoration: none; | ||
129 | } | ||
130 | a.reference, a.internal { | ||
131 | color: #abf; | ||
132 | } | ||
133 | |||
134 | a.reference em, a.internal em { | ||
135 | font-style: normal; | ||
136 | } | ||
137 | |||
138 | /* Links in sidebar, TOC, index trees and tables have no underline */ | ||
139 | .sphinxsidebar a, | ||
140 | .toctree-wrapper a, | ||
141 | .indextable a, | ||
142 | #indices-and-tables a { | ||
143 | color: #0bc; | ||
144 | text-decoration: none; | ||
145 | border-bottom: none; | ||
146 | } | ||
147 | |||
148 | /* Most links get an underline-effect when hovered */ | ||
149 | a:hover, | ||
150 | div.toctree-wrapper a:hover, | ||
151 | .indextable a:hover, | ||
152 | #indices-and-tables a:hover { | ||
153 | color: #2be; | ||
154 | text-decoration: none; | ||
155 | } | ||
156 | |||
157 | /*toctree dedicated styles*/ | ||
158 | div.toctree-wrapper ul { | ||
159 | list-style-type: none; | ||
160 | padding-left: 2em; | ||
161 | } | ||
162 | |||
163 | div.toctree-wrapper ul ul { | ||
164 | margin-top: .5em; | ||
165 | } | ||
166 | |||
167 | div.toctree-wrapper li { | ||
168 | margin-bottom: .5em; | ||
169 | } | ||
170 | div.toctree-wrapper a, .toctree-wrapper a:visited { | ||
171 | padding: .2em .4em; | ||
172 | background-color: #555; | ||
173 | color:#fff; | ||
174 | -webkit-border-radius: 4px; | ||
175 | -moz-border-radius: 4px; | ||
176 | border-radius: 4px; | ||
177 | } | ||
178 | div.toctree-wrapper a:hover { | ||
179 | color: #eee; | ||
180 | background-color: #777; | ||
181 | } | ||
182 | |||
183 | /* Footer links */ | ||
184 | div.footer a { | ||
185 | color: #0bc; | ||
186 | text-decoration: none; | ||
187 | border: none; | ||
188 | } | ||
189 | div.footer a:hover { | ||
190 | color: #2be; | ||
191 | border: none; | ||
192 | } | ||
193 | |||
194 | /* Permalink anchor (subtle grey with a red hover) */ | ||
195 | div.body a.headerlink { | ||
196 | color: #ccc; | ||
197 | font-size: 1em; | ||
198 | margin-left: 6px; | ||
199 | padding: 0 4px 0 4px; | ||
200 | text-decoration: none; | ||
201 | border: none; | ||
202 | } | ||
203 | div.body a.headerlink:hover { | ||
204 | color: #fff; | ||
205 | border: none; | ||
206 | } | ||
207 | |||
208 | |||
209 | /* NAVIGATION BAR --------------------------------------------------------- */ | ||
210 | |||
211 | div.related ul { | ||
212 | height: 2.5em; | ||
213 | min-height: 2.5em; | ||
214 | background-color: #2c2c2c; | ||
215 | background-image: -moz-linear-gradient(top, #333333, #222222); | ||
216 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); | ||
217 | background-image: -webkit-linear-gradient(top, #333333, #222222); | ||
218 | background-image: -o-linear-gradient(top, #333333, #222222); | ||
219 | background-image: linear-gradient(to bottom, #333333, #222222); | ||
220 | background-repeat: repeat-x; | ||
221 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff333333', endColorstr='#ff222222', GradientType=0); | ||
222 | border-bottom: 1px solid #222; | ||
223 | -moz-border-radius: 4px; | ||
224 | -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); | ||
225 | -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); | ||
226 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); | ||
227 | *zoom: 1; | ||
228 | } | ||
229 | |||
230 | div.related ul li { | ||
231 | margin: 0; | ||
232 | padding: 0.65em 0; | ||
233 | float: left; | ||
234 | display: block; | ||
235 | color: white; /* For the >> separators */ | ||
236 | font-size: 0.8em; | ||
237 | } | ||
238 | |||
239 | div.related ul li.right { | ||
240 | float: right; | ||
241 | margin-right: 5px; | ||
242 | color: transparent; /* Hide the | separators */ | ||
243 | } | ||
244 | |||
245 | /* "Breadcrumb" links in nav bar */ | ||
246 | div.related ul li a { | ||
247 | order: none; | ||
248 | background-color: inherit; | ||
249 | font-weight: bold; | ||
250 | margin: 6px 0 6px 4px; | ||
251 | line-height: 1.75em; | ||
252 | color: #ffffff; | ||
253 | padding: 0.4em 0.8em; | ||
254 | border: none; | ||
255 | border-radius: 3px; | ||
256 | } | ||
257 | /* previous / next / modules / index links look more like buttons */ | ||
258 | div.related ul li.right a { | ||
259 | margin: 0.375em 0; | ||
260 | background-color: #555; | ||
261 | text-shadow: 0 1px rgba(0, 0, 0, 0.5); | ||
262 | border-radius: 3px; | ||
263 | -webkit-border-radius: 3px; | ||
264 | -moz-border-radius: 3px; | ||
265 | } | ||
266 | /* All navbar links light up as buttons when hovered */ | ||
267 | div.related ul li a:hover { | ||
268 | background-color: #777; | ||
269 | color: #fff; | ||
270 | text-decoration: none; | ||
271 | border-radius: 3px; | ||
272 | -webkit-border-radius: 3px; | ||
273 | -moz-border-radius: 3px; | ||
274 | } | ||
275 | /* Take extra precautions for tt within links */ | ||
276 | a tt, | ||
277 | div.related ul li a tt { | ||
278 | background: inherit !important; | ||
279 | color: inherit !important; | ||
280 | } | ||
281 | |||
282 | .sphinxsidebar a tt span.pre { | ||
283 | color: #eee; | ||
284 | background-color: #444; | ||
285 | padding: 0 .5em; | ||
286 | border-radius: 4px; | ||
287 | } | ||
288 | |||
289 | .sphinxsidebar a:active tt span.pre { | ||
290 | color: #f66; | ||
291 | } | ||
292 | |||
293 | |||
294 | /* SIDEBAR ---------------------------------------------------------------- */ | ||
295 | |||
296 | div.sphinxsidebarwrapper { | ||
297 | padding: 0; | ||
298 | } | ||
299 | |||
300 | div.sphinxsidebar { | ||
301 | margin: 0; | ||
302 | margin-left: -100%; | ||
303 | float: right; | ||
304 | top: 3em; | ||
305 | left: 0; | ||
306 | padding: 0 1em; | ||
307 | width: 18em; | ||
308 | font-size: 90%; | ||
309 | |||
310 | } | ||
311 | |||
312 | div.sphinxsidebar img { | ||
313 | max-width: 12em; | ||
314 | } | ||
315 | |||
316 | div.sphinxsidebar input[type="image"] { | ||
317 | display: inline; | ||
318 | float: none; | ||
319 | border: 0; | ||
320 | } | ||
321 | |||
322 | div.sphinxsidebar h3, | ||
323 | div.sphinxsidebar h4, | ||
324 | div.sphinxsidebar p.logo { | ||
325 | margin: 1.2em 0 0.3em 0; | ||
326 | font-size: 1em; | ||
327 | padding: 0; | ||
328 | color: #fff; | ||
329 | font-family: Asap, Arial, "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif; | ||
330 | } | ||
331 | |||
332 | div.sphinxsidebar h3 a { | ||
333 | color: #fff; | ||
334 | } | ||
335 | |||
336 | div.sphinxsidebar ul, | ||
337 | div.sphinxsidebar p { | ||
338 | margin-top: 0; | ||
339 | padding-left: 0; | ||
340 | line-height: 130%; | ||
341 | |||
342 | } | ||
343 | |||
344 | /* No bullets for nested lists, but a little extra indentation */ | ||
345 | div.sphinxsidebar ul ul { | ||
346 | list-style-type: none; | ||
347 | margin-left: 1.2em; | ||
348 | padding: 0; | ||
349 | } | ||
350 | |||
351 | /* A little top/bottom padding to prevent adjacent links' borders | ||
352 | * from overlapping each other */ | ||
353 | div.sphinxsidebar ul li { | ||
354 | padding: 0; | ||
355 | margin: 2px 0; | ||
356 | } | ||
357 | |||
358 | /* A little left-padding to make these align with the ULs */ | ||
359 | div.sphinxsidebar p.topless { | ||
360 | padding-left: 0 0 0 1em; | ||
361 | } | ||
362 | |||
363 | /* Make these into hidden one-liners */ | ||
364 | div.sphinxsidebar ul li, | ||
365 | div.sphinxsidebar p.topless { | ||
366 | white-space: nowrap; | ||
367 | overflow: hidden; | ||
368 | border: 1px solid transparent; /* To prevent things jumping around on hover */ | ||
369 | } | ||
370 | /* ...which become visible when hovered */ | ||
371 | div.sphinxsidebar ul li:hover, | ||
372 | div.sphinxsidebar p.topless:hover { | ||
373 | background-color: #333; | ||
374 | overflow: visible; | ||
375 | |||
376 | |||
377 | } | ||
378 | |||
379 | /* Search text box and "Go" button */ | ||
380 | #searchbox { | ||
381 | margin-top: 2em; | ||
382 | margin-bottom: 1em; | ||
383 | background: #666; | ||
384 | padding: 0.5em; | ||
385 | border-radius: 6px; | ||
386 | -moz-border-radius: 6px; | ||
387 | -webkit-border-radius: 6px; | ||
388 | margin-right: 0; | ||
389 | } | ||
390 | #searchbox h3 { | ||
391 | margin-top: 0; | ||
392 | } | ||
393 | |||
394 | /* Make search box and button abut and have a border */ | ||
395 | input, | ||
396 | div.sphinxsidebar input { | ||
397 | border: 1px solid #999; | ||
398 | float: left; | ||
399 | } | ||
400 | |||
401 | /* Search textbox */ | ||
402 | input[type="text"] { | ||
403 | margin: 0; | ||
404 | padding: 0 3px; | ||
405 | height: 20px; | ||
406 | width: 144px; | ||
407 | border-top-left-radius: 3px; | ||
408 | border-bottom-left-radius: 3px; | ||
409 | -moz-border-radius-topleft: 3px; | ||
410 | -moz-border-radius-bottomleft: 3px; | ||
411 | -webkit-border-top-left-radius: 3px; | ||
412 | -webkit-border-bottom-left-radius: 3px; | ||
413 | } | ||
414 | /* Search button */ | ||
415 | input[type="submit"] { | ||
416 | margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */ | ||
417 | height: 22px; | ||
418 | color: #444; | ||
419 | background-color: #e8ecef; | ||
420 | padding: 1px 4px; | ||
421 | font-weight: bold; | ||
422 | border-top-right-radius: 3px; | ||
423 | border-bottom-right-radius: 3px; | ||
424 | -moz-border-radius-topright: 3px; | ||
425 | -moz-border-radius-bottomright: 3px; | ||
426 | -webkit-border-top-right-radius: 3px; | ||
427 | -webkit-border-bottom-right-radius: 3px; | ||
428 | } | ||
429 | input[type="submit"]:hover { | ||
430 | color: #000; | ||
431 | background-color: #ddd; | ||
432 | } | ||
433 | |||
434 | div.sphinxsidebar p.searchtip { | ||
435 | clear: both; | ||
436 | padding: 0.5em 0 0 0; | ||
437 | color: #fff; | ||
438 | font-size: 0.9em; | ||
439 | } | ||
440 | |||
441 | /* Sidebar links are unusual */ | ||
442 | div.sphinxsidebar li a, | ||
443 | div.sphinxsidebar p a { | ||
444 | color: #eee; | ||
445 | border-radius: 3px; | ||
446 | -moz-border-radius: 3px; | ||
447 | -webkit-border-radius: 3px; | ||
448 | border: 1px solid transparent; /* To prevent things jumping around on hover */ | ||
449 | padding: 0 5px 0 5px; | ||
450 | } | ||
451 | div.sphinxsidebar li a:hover, | ||
452 | div.sphinxsidebar p a:hover { | ||
453 | color: #fff; | ||
454 | background-color: #333; | ||
455 | } | ||
456 | div.sphinxsidebar p.logo a { | ||
457 | border: 0; | ||
458 | } | ||
459 | |||
460 | /* Tweak any link appearing in a heading */ | ||
461 | div.sphinxsidebar h3 a { | ||
462 | } | ||
463 | |||
464 | |||
465 | /* OTHER STUFF ------------------------------------------------------------ */ | ||
466 | |||
467 | /* labels */ | ||
468 | .versionmodified { | ||
469 | font-style: normal; | ||
470 | } | ||
471 | |||
472 | .bookmarklet, .versionadded, .versionchanged { | ||
473 | display: inline-block; | ||
474 | padding: 4px 6px; | ||
475 | font-size: 13.536px; | ||
476 | font-weight: bold; | ||
477 | line-height: 14px; | ||
478 | color: #ffffff; | ||
479 | vertical-align: baseline; | ||
480 | white-space: nowrap; | ||
481 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | ||
482 | background-color: #999999; | ||
483 | -webkit-border-radius: 3px; | ||
484 | -moz-border-radius: 3px; | ||
485 | border-radius: 3px; | ||
486 | text-align: center; | ||
487 | font-style: normal; | ||
488 | } | ||
489 | .bookmarklet a, .versionadded a, .versionchanged a { | ||
490 | color: #fff; | ||
491 | } | ||
492 | |||
493 | .bookmarklet { | ||
494 | background-color: #2d6987; | ||
495 | } | ||
496 | |||
497 | .versionadded { | ||
498 | background-color: #468847; | ||
499 | } | ||
500 | div.admonition p.versionadded, | ||
501 | div.warning p.versionadded { | ||
502 | padding: 4px 6px; | ||
503 | } | ||
504 | |||
505 | .versionchanged { | ||
506 | background-color: #b04040; | ||
507 | } | ||
508 | div.admonition p.versionchanged, | ||
509 | div.warning p.versionchanged { | ||
510 | padding: 4px 6px; | ||
511 | } | ||
512 | |||
513 | /* Standard tags */ | ||
514 | cite, code, tt { | ||
515 | font-family: 'Source Code Pro', 'Consolas', 'Deja Vu Sans Mono', | ||
516 | 'Bitstream Vera Sans Mono', monospace; | ||
517 | font-size: 0.95em; | ||
518 | letter-spacing: 0.01em; | ||
519 | } | ||
520 | |||
521 | tt { | ||
522 | color: #f66; | ||
523 | background-color: #444; | ||
524 | padding: 0 5px; | ||
525 | font-size: 95%; | ||
526 | -webkit-border-radius: 4px; | ||
527 | -moz-border-radius: 4px; | ||
528 | border-radius: 4px; | ||
529 | } | ||
530 | |||
531 | h1 tt, h2 tt, h3 tt, h4 tt, h5 tt { | ||
532 | padding: 0; | ||
533 | background: none; | ||
534 | } | ||
535 | |||
536 | tt.descname, tt.descclassname, tt.xref { | ||
537 | border: 0; | ||
538 | } | ||
539 | |||
540 | hr { | ||
541 | border-top: 1px solid #777; | ||
542 | border-bottom: none; | ||
543 | margin: 2em auto; | ||
544 | width: 50%; | ||
545 | } | ||
546 | |||
547 | |||
548 | pre, #_fontwidthtest { | ||
549 | font-family: 'Source Code Pro', 'Consolas', 'Deja Vu Sans Mono', | ||
550 | 'Bitstream Vera Sans Mono', monospace; | ||
551 | margin: 1em 2em; | ||
552 | font-size: 0.95em; | ||
553 | letter-spacing: 0.015em; | ||
554 | line-height: 120%; | ||
555 | padding: 0.5em; | ||
556 | border: 1px solid #ccc; | ||
557 | background-color: #eee; | ||
558 | border-radius: 6px; | ||
559 | -moz-border-radius: 6px; | ||
560 | -webkit-border-radius: 6px; | ||
561 | } | ||
562 | |||
563 | pre a { | ||
564 | color: inherit; | ||
565 | text-decoration: underline; | ||
566 | } | ||
567 | |||
568 | td.linenos pre { | ||
569 | margin: 1em 0em; | ||
570 | } | ||
571 | |||
572 | td.code pre { | ||
573 | margin: 1em 0em; | ||
574 | } | ||
575 | |||
576 | div.quotebar { | ||
577 | background-color: #f8f8f8; | ||
578 | max-width: 250px; | ||
579 | float: right; | ||
580 | padding: 2px 7px; | ||
581 | border: 1px solid #ccc; | ||
582 | } | ||
583 | |||
584 | div.topic { | ||
585 | background-color: #333; | ||
586 | border: 0; | ||
587 | padding-bottom: .5em; | ||
588 | border-radius: 4px; | ||
589 | -moz-border-radius: 4px; | ||
590 | -webkit-border-radius: 4px; | ||
591 | } | ||
592 | |||
593 | table { | ||
594 | border-collapse: collapse; | ||
595 | margin: 0 -0.5em 0 -0.5em; | ||
596 | } | ||
597 | |||
598 | table td, table th { | ||
599 | padding: 0.2em 0.5em 0.2em 0.5em; | ||
600 | } | ||
601 | |||
602 | |||
603 | /* ADMONITIONS AND WARNINGS ------------------------------------------------- */ | ||
604 | |||
605 | /* Shared by admonitions, warnings and sidebars */ | ||
606 | div.admonition, | ||
607 | div.warning, | ||
608 | div.sidebar { | ||
609 | font-size: 0.9em; | ||
610 | margin: 2em; | ||
611 | padding: 0; | ||
612 | /* | ||
613 | border-radius: 6px; | ||
614 | -moz-border-radius: 6px; | ||
615 | -webkit-border-radius: 6px; | ||
616 | */ | ||
617 | } | ||
618 | div.admonition p, | ||
619 | div.warning p, | ||
620 | div.sidebar p { | ||
621 | margin: 0.5em 1em 0.5em 1em; | ||
622 | padding: 0; | ||
623 | } | ||
624 | div.admonition pre, | ||
625 | div.warning pre, | ||
626 | div.sidebar pre { | ||
627 | margin: 0.4em 1em 0.4em 1em; | ||
628 | } | ||
629 | div.admonition p.admonition-title, | ||
630 | div.warning p.admonition-title, | ||
631 | div.sidebar p.sidebar-title { | ||
632 | margin: 0; | ||
633 | padding: 0.1em 0 0.1em 0.5em; | ||
634 | color: white; | ||
635 | font-weight: bold; | ||
636 | font-size: 1.1em; | ||
637 | text-shadow: 0 1px rgba(0, 0, 0, 0.5); | ||
638 | } | ||
639 | div.admonition ul, div.admonition ol, | ||
640 | div.warning ul, div.warning ol, | ||
641 | div.sidebar ul, div.sidebar ol { | ||
642 | margin: 0.1em 0.5em 0.5em 3em; | ||
643 | padding: 0; | ||
644 | } | ||
645 | |||
646 | |||
647 | /* Admonitions and sidebars only */ | ||
648 | div.admonition, div.sidebar { | ||
649 | border: none; | ||
650 | background-color: #555; | ||
651 | color: #fff; | ||
652 | padding: .5em; | ||
653 | margin-bottom: 1em; | ||
654 | -webkit-border-radius: 4px; | ||
655 | -moz-border-radius: 4px; | ||
656 | border-radius: 4px; | ||
657 | |||
658 | } | ||
659 | div.admonition p.admonition-title, | ||
660 | div.sidebar p.sidebar-title { | ||
661 | padding-bottom: .5em; | ||
662 | border-bottom: 1px solid #888; | ||
663 | } | ||
664 | |||
665 | |||
666 | /* Warnings only */ | ||
667 | div.warning { | ||
668 | background-color: #333; | ||
669 | } | ||
670 | div.warning p.admonition-title { | ||
671 | background-color: #b04040; | ||
672 | border-bottom: 1px solid #900000; | ||
673 | border-radius: 4px; | ||
674 | } | ||
675 | |||
676 | |||
677 | /* Sidebars only */ | ||
678 | div.sidebar { | ||
679 | max-width: 30%; | ||
680 | } | ||
681 | |||
682 | |||
683 | |||
684 | div.versioninfo { | ||
685 | margin: 1em 0 0 0; | ||
686 | border: 1px solid #ccc; | ||
687 | background-color: #DDEAF0; | ||
688 | padding: 8px; | ||
689 | line-height: 1.3em; | ||
690 | font-size: 0.9em; | ||
691 | } | ||
692 | |||
693 | .viewcode-back { | ||
694 | font-family: Asap, 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', | ||
695 | 'Verdana', sans-serif; | ||
696 | } | ||
697 | |||
698 | div.viewcode-block:target { | ||
699 | background-color: #f4debf; | ||
700 | border-top: 1px solid #ac9; | ||
701 | border-bottom: 1px solid #ac9; | ||
702 | } | ||
703 | |||
704 | dl { | ||
705 | margin: 1em 0 2.5em 0; | ||
706 | } | ||
707 | |||
708 | /* Highlight target when you click an internal link */ | ||
709 | dt:target { | ||
710 | background: #ffe080; | ||
711 | } | ||
712 | /* Don't highlight whole divs */ | ||
713 | div.highlight { | ||
714 | background: transparent; | ||
715 | } | ||
716 | div.highlight pre, | ||
717 | div.highlight-javascript pre, | ||
718 | div.highlight-html pre { | ||
719 | background-color: #4b4b4b; | ||
720 | background-color: rgba(75, 75, 75, 0.5); | ||
721 | color: #eee; | ||
722 | font-size: 15px; | ||
723 | line-height: 21px; | ||
724 | white-space: pre; | ||
725 | overflow: auto; | ||
726 | border: none; | ||
727 | } | ||
728 | div.admonition pre { | ||
729 | background-color: #333; | ||
730 | } | ||
731 | |||
732 | /* But do highlight spans (so search results can be highlighted) */ | ||
733 | span.highlight { | ||
734 | background: #111; | ||
735 | } | ||
736 | |||
737 | div.highlight .c1 { | ||
738 | color: #999; | ||
739 | } | ||
740 | div.highlight .cp { | ||
741 | color: #3aC; | ||
742 | } | ||
743 | |||
744 | div.highlight .s, | ||
745 | div.highlight .s1, | ||
746 | div.highlight .s2 { | ||
747 | color: orange; | ||
748 | } | ||
749 | |||
750 | div.highlight .kc { | ||
751 | color: red; | ||
752 | } | ||
753 | div.highlight .k, | ||
754 | div.highlight .kd { | ||
755 | color: #3aC; | ||
756 | } | ||
757 | |||
758 | div.highlight .nb { | ||
759 | color: #e88; | ||
760 | } | ||
761 | div.highlight .nx { | ||
762 | color: #fff; | ||
763 | } | ||
764 | |||
765 | div.highlight .p { | ||
766 | color: #eee; | ||
767 | } | ||
768 | |||
769 | div.footer { | ||
770 | color: #eeeeee; | ||
771 | padding: 1em 2em 1em 2em; | ||
772 | clear: both; | ||
773 | font-size: 0.8em; | ||
774 | text-align: center; | ||
775 | background-color: #222; | ||
776 | } | ||
777 | |||
778 | p { | ||
779 | margin: 0.8em 0 0.5em 0; | ||
780 | } | ||
781 | |||
782 | .section p img.math { | ||
783 | margin: 0; | ||
784 | } | ||
785 | |||
786 | |||
787 | .section p img { | ||
788 | margin: 1em 2em; | ||
789 | } | ||
790 | |||
791 | |||
792 | /* MOBILE LAYOUT -------------------------------------------------------------- */ | ||
793 | |||
794 | @media screen and (max-width: 600px) { | ||
795 | |||
796 | h1, h2, h3, h4, h5 { | ||
797 | position: relative; | ||
798 | } | ||
799 | |||
800 | ul { | ||
801 | padding-left: 1.25em; | ||
802 | } | ||
803 | |||
804 | div.bodywrapper a.headerlink, #indices-and-tables h1 a { | ||
805 | color: #e6e6e6; | ||
806 | font-size: 80%; | ||
807 | float: right; | ||
808 | line-height: 1.8; | ||
809 | position: absolute; | ||
810 | right: -0.7em; | ||
811 | visibility: inherit; | ||
812 | } | ||
813 | |||
814 | div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a { | ||
815 | line-height: 1.5; | ||
816 | } | ||
817 | |||
818 | pre { | ||
819 | font-size: 0.7em; | ||
820 | overflow: auto; | ||
821 | word-wrap: break-word; | ||
822 | white-space: pre-wrap; | ||
823 | } | ||
824 | |||
825 | div.related ul { | ||
826 | height: 2.5em; | ||
827 | padding: 0; | ||
828 | text-align: left; | ||
829 | } | ||
830 | |||
831 | div.related ul li { | ||
832 | clear: both; | ||
833 | color: #465158; | ||
834 | padding: 0.2em 0; | ||
835 | } | ||
836 | |||
837 | div.related ul li:last-child { | ||
838 | border-bottom: 1px dotted #8ca1af; | ||
839 | padding-bottom: 0.4em; | ||
840 | margin-bottom: 1em; | ||
841 | width: 100%; | ||
842 | } | ||
843 | |||
844 | div.related ul li a { | ||
845 | color: #fff; | ||
846 | padding-right: 0; | ||
847 | } | ||
848 | |||
849 | div.related ul li a:hover { | ||
850 | background: inherit; | ||
851 | color: inherit; | ||
852 | } | ||
853 | |||
854 | div.related ul li.right { | ||
855 | clear: none; | ||
856 | padding: 0.65em 0; | ||
857 | margin-bottom: 0.5em; | ||
858 | } | ||
859 | |||
860 | div.related ul li.right a { | ||
861 | color: #fff; | ||
862 | padding-right: 0.8em; | ||
863 | } | ||
864 | |||
865 | div.related ul li.right a:hover { | ||
866 | background-color: #8ca1af; | ||
867 | } | ||
868 | |||
869 | div.body { | ||
870 | clear: both; | ||
871 | min-width: 0; | ||
872 | word-wrap: break-word; | ||
873 | } | ||
874 | |||
875 | div.bodywrapper { | ||
876 | margin: 0 0 0 0; | ||
877 | } | ||
878 | |||
879 | div.sphinxsidebar { | ||
880 | float: none; | ||
881 | margin: 0; | ||
882 | width: auto; | ||
883 | } | ||
884 | |||
885 | div.sphinxsidebar input[type="text"] { | ||
886 | height: 2em; | ||
887 | line-height: 2em; | ||
888 | width: 70%; | ||
889 | } | ||
890 | |||
891 | div.sphinxsidebar input[type="submit"] { | ||
892 | height: 2em; | ||
893 | margin-left: 0.5em; | ||
894 | width: 20%; | ||
895 | } | ||
896 | |||
897 | div.sphinxsidebar p.searchtip { | ||
898 | background: inherit; | ||
899 | margin-bottom: 1em; | ||
900 | } | ||
901 | |||
902 | div.sphinxsidebar ul li, div.sphinxsidebar p.topless { | ||
903 | white-space: normal; | ||
904 | } | ||
905 | |||
906 | .bodywrapper img { | ||
907 | display: block; | ||
908 | margin-left: auto; | ||
909 | margin-right: auto; | ||
910 | max-width: 100%; | ||
911 | } | ||
912 | |||
913 | div.documentwrapper { | ||
914 | float: none; | ||
915 | } | ||
916 | |||
917 | div.admonition, div.warning, pre, blockquote { | ||
918 | margin-left: 0em; | ||
919 | margin-right: 0em; | ||
920 | } | ||
921 | |||
922 | .body p img { | ||
923 | margin: 0; | ||
924 | } | ||
925 | |||
926 | #searchbox { | ||
927 | background: transparent; | ||
928 | } | ||
929 | |||
930 | .related:not(:first-child) li { | ||
931 | display: none; | ||
932 | } | ||
933 | |||
934 | .related:not(:first-child) li.right { | ||
935 | display: block; | ||
936 | } | ||
937 | |||
938 | div.footer { | ||
939 | padding: 1em; | ||
940 | } | ||
941 | |||
942 | .rtd_doc_footer .rtd-badge { | ||
943 | float: none; | ||
944 | margin: 1em auto; | ||
945 | position: static; | ||
946 | } | ||
947 | |||
948 | .rtd_doc_footer .rtd-badge.revsys-inline { | ||
949 | margin-right: auto; | ||
950 | margin-bottom: 2em; | ||
951 | } | ||
952 | |||
953 | table.indextable { | ||
954 | display: block; | ||
955 | width: auto; | ||
956 | } | ||
957 | |||
958 | .indextable tr { | ||
959 | display: block; | ||
960 | } | ||
961 | |||
962 | .indextable td { | ||
963 | display: block; | ||
964 | padding: 0; | ||
965 | width: auto !important; | ||
966 | } | ||
967 | |||
968 | .indextable td dt { | ||
969 | margin: 1em 0; | ||
970 | } | ||
971 | |||
972 | ul.search { | ||
973 | margin-left: 0.25em; | ||
974 | } | ||
975 | |||
976 | ul.search li div.context { | ||
977 | font-size: 90%; | ||
978 | line-height: 1.1; | ||
979 | margin-bottom: 1; | ||
980 | margin-left: 0; | ||
981 | } | ||
982 | |||
983 | } | ||
984 | |||
985 | .donate { | ||
986 | text-align: center; | ||
987 | } | ||
988 | |||
989 | .donate .flattr { | ||
990 | margin-top: 1.5em; | ||
991 | } |
1 | /* | ||
2 | * rtd.css | ||
3 | * ~~~~~~~~~~~~~~~ | ||
4 | * | ||
5 | * Sphinx stylesheet -- sphinxdoc theme. Originally created by | ||
6 | * Armin Ronacher for Werkzeug. | ||
7 | * | ||
8 | * Customized for ReadTheDocs by Eric Pierce & Eric Holscher | ||
9 | * | ||
10 | * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. | ||
11 | * :license: BSD, see LICENSE for details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | /* RTD colors | ||
16 | * light blue: #e8ecef | ||
17 | * medium blue: #8ca1af | ||
18 | * dark blue: #465158 | ||
19 | * dark grey: #444444 | ||
20 | * | ||
21 | * white hover: #d1d9df; | ||
22 | * medium blue hover: #697983; | ||
23 | * green highlight: #8ecc4c | ||
24 | * light blue (project bar): #e8ecef | ||
25 | */ | ||
26 | |||
27 | @import url("basic.css"); | ||
28 | |||
29 | /* PAGE LAYOUT -------------------------------------------------------------- */ | ||
30 | |||
31 | body { | ||
32 | font: 100%/1.5 "ff-meta-web-pro-1","ff-meta-web-pro-2",Arial,"Helvetica Neue",sans-serif; | ||
33 | text-align: center; | ||
34 | color: black; | ||
35 | background-color: #465158; | ||
36 | padding: 0; | ||
37 | margin: 0; | ||
38 | } | ||
39 | |||
40 | img { | ||
41 | border: 0; | ||
42 | max-width: 100%; | ||
43 | } | ||
44 | |||
45 | div.document { | ||
46 | text-align: left; | ||
47 | background-color: #e8ecef; | ||
48 | } | ||
49 | |||
50 | div.bodywrapper { | ||
51 | background-color: #ffffff; | ||
52 | border-left: 1px solid #ccc; | ||
53 | border-bottom: 1px solid #ccc; | ||
54 | margin: 0 0 0 16em; | ||
55 | } | ||
56 | |||
57 | div.body { | ||
58 | margin: 0; | ||
59 | padding: 0.5em 1.3em; | ||
60 | min-width: 20em; | ||
61 | } | ||
62 | |||
63 | div.related { | ||
64 | font-size: 1em; | ||
65 | background-color: #465158; | ||
66 | } | ||
67 | |||
68 | div.documentwrapper { | ||
69 | float: left; | ||
70 | width: 100%; | ||
71 | background-color: #e8ecef; | ||
72 | } | ||
73 | |||
74 | |||
75 | /* HEADINGS --------------------------------------------------------------- */ | ||
76 | |||
77 | h1 { | ||
78 | margin: 0; | ||
79 | padding: 0.7em 0 0.3em 0; | ||
80 | font-size: 1.5em; | ||
81 | line-height: 1.15; | ||
82 | color: #111; | ||
83 | clear: both; | ||
84 | } | ||
85 | |||
86 | h2 { | ||
87 | margin: 2em 0 0.2em 0; | ||
88 | font-size: 1.35em; | ||
89 | padding: 0; | ||
90 | color: #465158; | ||
91 | } | ||
92 | |||
93 | h3 { | ||
94 | margin: 1em 0 -0.3em 0; | ||
95 | font-size: 1.2em; | ||
96 | color: #6c818f; | ||
97 | } | ||
98 | |||
99 | div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { | ||
100 | color: black; | ||
101 | } | ||
102 | |||
103 | h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { | ||
104 | display: none; | ||
105 | margin: 0 0 0 0.3em; | ||
106 | padding: 0 0.2em 0 0.2em; | ||
107 | color: #aaa !important; | ||
108 | } | ||
109 | |||
110 | h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, | ||
111 | h5:hover a.anchor, h6:hover a.anchor { | ||
112 | display: inline; | ||
113 | } | ||
114 | |||
115 | h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, | ||
116 | h5 a.anchor:hover, h6 a.anchor:hover { | ||
117 | color: #777; | ||
118 | background-color: #eee; | ||
119 | } | ||
120 | |||
121 | |||
122 | /* LINKS ------------------------------------------------------------------ */ | ||
123 | |||
124 | /* Normal links get a pseudo-underline */ | ||
125 | a { | ||
126 | color: #444; | ||
127 | text-decoration: none; | ||
128 | border-bottom: 1px solid #ccc; | ||
129 | } | ||
130 | |||
131 | /* Links in sidebar, TOC, index trees and tables have no underline */ | ||
132 | .sphinxsidebar a, | ||
133 | .toctree-wrapper a, | ||
134 | .indextable a, | ||
135 | #indices-and-tables a { | ||
136 | color: #444; | ||
137 | text-decoration: none; | ||
138 | border-bottom: none; | ||
139 | } | ||
140 | |||
141 | /* Most links get an underline-effect when hovered */ | ||
142 | a:hover, | ||
143 | div.toctree-wrapper a:hover, | ||
144 | .indextable a:hover, | ||
145 | #indices-and-tables a:hover { | ||
146 | color: #111; | ||
147 | text-decoration: none; | ||
148 | border-bottom: 1px solid #111; | ||
149 | } | ||
150 | |||
151 | /* Footer links */ | ||
152 | div.footer a { | ||
153 | color: #86989B; | ||
154 | text-decoration: none; | ||
155 | border: none; | ||
156 | } | ||
157 | div.footer a:hover { | ||
158 | color: #a6b8bb; | ||
159 | text-decoration: underline; | ||
160 | border: none; | ||
161 | } | ||
162 | |||
163 | /* Permalink anchor (subtle grey with a red hover) */ | ||
164 | div.body a.headerlink { | ||
165 | color: #ccc; | ||
166 | font-size: 1em; | ||
167 | margin-left: 6px; | ||
168 | padding: 0 4px 0 4px; | ||
169 | text-decoration: none; | ||
170 | border: none; | ||
171 | } | ||
172 | div.body a.headerlink:hover { | ||
173 | color: #c60f0f; | ||
174 | border: none; | ||
175 | } | ||
176 | |||
177 | |||
178 | /* NAVIGATION BAR --------------------------------------------------------- */ | ||
179 | |||
180 | div.related ul { | ||
181 | height: 2.5em; | ||
182 | } | ||
183 | |||
184 | div.related ul li { | ||
185 | margin: 0; | ||
186 | padding: 0.65em 0; | ||
187 | float: left; | ||
188 | display: block; | ||
189 | color: white; /* For the >> separators */ | ||
190 | font-size: 0.8em; | ||
191 | } | ||
192 | |||
193 | div.related ul li.right { | ||
194 | float: right; | ||
195 | margin-right: 5px; | ||
196 | color: transparent; /* Hide the | separators */ | ||
197 | } | ||
198 | |||
199 | /* "Breadcrumb" links in nav bar */ | ||
200 | div.related ul li a { | ||
201 | order: none; | ||
202 | background-color: inherit; | ||
203 | font-weight: bold; | ||
204 | margin: 6px 0 6px 4px; | ||
205 | line-height: 1.75em; | ||
206 | color: #ffffff; | ||
207 | padding: 0.4em 0.8em; | ||
208 | border: none; | ||
209 | border-radius: 3px; | ||
210 | } | ||
211 | /* previous / next / modules / index links look more like buttons */ | ||
212 | div.related ul li.right a { | ||
213 | margin: 0.375em 0; | ||
214 | background-color: #697983; | ||
215 | text-shadow: 0 1px rgba(0, 0, 0, 0.5); | ||
216 | border-radius: 3px; | ||
217 | -webkit-border-radius: 3px; | ||
218 | -moz-border-radius: 3px; | ||
219 | } | ||
220 | /* All navbar links light up as buttons when hovered */ | ||
221 | div.related ul li a:hover { | ||
222 | background-color: #8ca1af; | ||
223 | color: #ffffff; | ||
224 | text-decoration: none; | ||
225 | border-radius: 3px; | ||
226 | -webkit-border-radius: 3px; | ||
227 | -moz-border-radius: 3px; | ||
228 | } | ||
229 | /* Take extra precautions for tt within links */ | ||
230 | a tt, | ||
231 | div.related ul li a tt { | ||
232 | background: inherit !important; | ||
233 | color: inherit !important; | ||
234 | } | ||
235 | |||
236 | |||
237 | /* SIDEBAR ---------------------------------------------------------------- */ | ||
238 | |||
239 | div.sphinxsidebarwrapper { | ||
240 | padding: 0; | ||
241 | } | ||
242 | |||
243 | div.sphinxsidebar { | ||
244 | margin: 0; | ||
245 | margin-left: -100%; | ||
246 | float: left; | ||
247 | top: 3em; | ||
248 | left: 0; | ||
249 | padding: 0 1em; | ||
250 | width: 14em; | ||
251 | font-size: 1em; | ||
252 | text-align: left; | ||
253 | background-color: #e8ecef; | ||
254 | } | ||
255 | |||
256 | div.sphinxsidebar img { | ||
257 | max-width: 12em; | ||
258 | } | ||
259 | |||
260 | div.sphinxsidebar input[type="image"] { | ||
261 | display: inline; | ||
262 | float: none; | ||
263 | border: 0; | ||
264 | } | ||
265 | |||
266 | div.sphinxsidebar h3, | ||
267 | div.sphinxsidebar h4, | ||
268 | div.sphinxsidebar p.logo { | ||
269 | margin: 1.2em 0 0.3em 0; | ||
270 | font-size: 1em; | ||
271 | padding: 0; | ||
272 | color: #222222; | ||
273 | font-family: "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif; | ||
274 | } | ||
275 | |||
276 | div.sphinxsidebar h3 a { | ||
277 | color: #444444; | ||
278 | } | ||
279 | |||
280 | div.sphinxsidebar ul, | ||
281 | div.sphinxsidebar p { | ||
282 | margin-top: 0; | ||
283 | padding-left: 0; | ||
284 | line-height: 130%; | ||
285 | background-color: #e8ecef; | ||
286 | } | ||
287 | |||
288 | /* No bullets for nested lists, but a little extra indentation */ | ||
289 | div.sphinxsidebar ul ul { | ||
290 | list-style-type: none; | ||
291 | margin-left: 1.5em; | ||
292 | padding: 0; | ||
293 | } | ||
294 | |||
295 | /* A little top/bottom padding to prevent adjacent links' borders | ||
296 | * from overlapping each other */ | ||
297 | div.sphinxsidebar ul li { | ||
298 | padding: 1px 0; | ||
299 | } | ||
300 | |||
301 | /* A little left-padding to make these align with the ULs */ | ||
302 | div.sphinxsidebar p.topless { | ||
303 | padding-left: 0 0 0 1em; | ||
304 | } | ||
305 | |||
306 | /* Make these into hidden one-liners */ | ||
307 | div.sphinxsidebar ul li, | ||
308 | div.sphinxsidebar p.topless { | ||
309 | white-space: nowrap; | ||
310 | overflow: hidden; | ||
311 | } | ||
312 | /* ...which become visible when hovered */ | ||
313 | div.sphinxsidebar ul li:hover, | ||
314 | div.sphinxsidebar p.topless:hover { | ||
315 | overflow: visible; | ||
316 | } | ||
317 | |||
318 | /* Search text box and "Go" button */ | ||
319 | #searchbox { | ||
320 | margin-top: 2em; | ||
321 | margin-bottom: 1em; | ||
322 | background: #ddd; | ||
323 | padding: 0.5em; | ||
324 | border-radius: 6px; | ||
325 | -moz-border-radius: 6px; | ||
326 | -webkit-border-radius: 6px; | ||
327 | } | ||
328 | #searchbox h3 { | ||
329 | margin-top: 0; | ||
330 | } | ||
331 | |||
332 | /* Make search box and button abut and have a border */ | ||
333 | input, | ||
334 | div.sphinxsidebar input { | ||
335 | border: 1px solid #999; | ||
336 | float: left; | ||
337 | } | ||
338 | |||
339 | /* Search textbox */ | ||
340 | input[type="text"] { | ||
341 | margin: 0; | ||
342 | padding: 0 3px; | ||
343 | height: 20px; | ||
344 | width: 144px; | ||
345 | border-top-left-radius: 3px; | ||
346 | border-bottom-left-radius: 3px; | ||
347 | -moz-border-radius-topleft: 3px; | ||
348 | -moz-border-radius-bottomleft: 3px; | ||
349 | -webkit-border-top-left-radius: 3px; | ||
350 | -webkit-border-bottom-left-radius: 3px; | ||
351 | } | ||
352 | /* Search button */ | ||
353 | input[type="submit"] { | ||
354 | margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */ | ||
355 | height: 22px; | ||
356 | color: #444; | ||
357 | background-color: #e8ecef; | ||
358 | padding: 1px 4px; | ||
359 | font-weight: bold; | ||
360 | border-top-right-radius: 3px; | ||
361 | border-bottom-right-radius: 3px; | ||
362 | -moz-border-radius-topright: 3px; | ||
363 | -moz-border-radius-bottomright: 3px; | ||
364 | -webkit-border-top-right-radius: 3px; | ||
365 | -webkit-border-bottom-right-radius: 3px; | ||
366 | } | ||
367 | input[type="submit"]:hover { | ||
368 | color: #ffffff; | ||
369 | background-color: #8ecc4c; | ||
370 | } | ||
371 | |||
372 | div.sphinxsidebar p.searchtip { | ||
373 | clear: both; | ||
374 | padding: 0.5em 0 0 0; | ||
375 | background: #ddd; | ||
376 | color: #666; | ||
377 | font-size: 0.9em; | ||
378 | } | ||
379 | |||
380 | /* Sidebar links are unusual */ | ||
381 | div.sphinxsidebar li a, | ||
382 | div.sphinxsidebar p a { | ||
383 | background: #e8ecef; /* In case links overlap main content */ | ||
384 | border-radius: 3px; | ||
385 | -moz-border-radius: 3px; | ||
386 | -webkit-border-radius: 3px; | ||
387 | border: 1px solid transparent; /* To prevent things jumping around on hover */ | ||
388 | padding: 0 5px 0 5px; | ||
389 | } | ||
390 | div.sphinxsidebar li a:hover, | ||
391 | div.sphinxsidebar p a:hover { | ||
392 | color: #111; | ||
393 | text-decoration: none; | ||
394 | border: 1px solid #888; | ||
395 | } | ||
396 | div.sphinxsidebar p.logo a { | ||
397 | border: 0; | ||
398 | } | ||
399 | |||
400 | /* Tweak any link appearing in a heading */ | ||
401 | div.sphinxsidebar h3 a { | ||
402 | } | ||
403 | |||
404 | |||
405 | |||
406 | |||
407 | /* OTHER STUFF ------------------------------------------------------------ */ | ||
408 | |||
409 | cite, code, tt { | ||
410 | font-family: 'Consolas', 'Deja Vu Sans Mono', | ||
411 | 'Bitstream Vera Sans Mono', monospace; | ||
412 | font-size: 0.95em; | ||
413 | letter-spacing: 0.01em; | ||
414 | } | ||
415 | |||
416 | tt { | ||
417 | background-color: #f2f2f2; | ||
418 | color: #444; | ||
419 | } | ||
420 | |||
421 | tt.descname, tt.descclassname, tt.xref { | ||
422 | border: 0; | ||
423 | } | ||
424 | |||
425 | hr { | ||
426 | border: 1px solid #abc; | ||
427 | margin: 2em; | ||
428 | } | ||
429 | |||
430 | |||
431 | pre, #_fontwidthtest { | ||
432 | font-family: 'Consolas', 'Deja Vu Sans Mono', | ||
433 | 'Bitstream Vera Sans Mono', monospace; | ||
434 | margin: 1em 2em; | ||
435 | font-size: 0.95em; | ||
436 | letter-spacing: 0.015em; | ||
437 | line-height: 120%; | ||
438 | padding: 0.5em; | ||
439 | border: 1px solid #ccc; | ||
440 | background-color: #eee; | ||
441 | border-radius: 6px; | ||
442 | -moz-border-radius: 6px; | ||
443 | -webkit-border-radius: 6px; | ||
444 | } | ||
445 | |||
446 | pre a { | ||
447 | color: inherit; | ||
448 | text-decoration: underline; | ||
449 | } | ||
450 | |||
451 | td.linenos pre { | ||
452 | margin: 1em 0em; | ||
453 | } | ||
454 | |||
455 | td.code pre { | ||
456 | margin: 1em 0em; | ||
457 | } | ||
458 | |||
459 | div.quotebar { | ||
460 | background-color: #f8f8f8; | ||
461 | max-width: 250px; | ||
462 | float: right; | ||
463 | padding: 2px 7px; | ||
464 | border: 1px solid #ccc; | ||
465 | } | ||
466 | |||
467 | div.topic { | ||
468 | background-color: #f8f8f8; | ||
469 | } | ||
470 | |||
471 | table { | ||
472 | border-collapse: collapse; | ||
473 | margin: 0 -0.5em 0 -0.5em; | ||
474 | } | ||
475 | |||
476 | table td, table th { | ||
477 | padding: 0.2em 0.5em 0.2em 0.5em; | ||
478 | } | ||
479 | |||
480 | |||
481 | /* ADMONITIONS AND WARNINGS ------------------------------------------------- */ | ||
482 | |||
483 | /* Shared by admonitions, warnings and sidebars */ | ||
484 | div.admonition, | ||
485 | div.warning, | ||
486 | div.sidebar { | ||
487 | font-size: 0.9em; | ||
488 | margin: 2em; | ||
489 | padding: 0; | ||
490 | /* | ||
491 | border-radius: 6px; | ||
492 | -moz-border-radius: 6px; | ||
493 | -webkit-border-radius: 6px; | ||
494 | */ | ||
495 | } | ||
496 | div.admonition p, | ||
497 | div.warning p, | ||
498 | div.sidebar p { | ||
499 | margin: 0.5em 1em 0.5em 1em; | ||
500 | padding: 0; | ||
501 | } | ||
502 | div.admonition pre, | ||
503 | div.warning pre, | ||
504 | div.sidebar pre { | ||
505 | margin: 0.4em 1em 0.4em 1em; | ||
506 | } | ||
507 | div.admonition p.admonition-title, | ||
508 | div.warning p.admonition-title, | ||
509 | div.sidebar p.sidebar-title { | ||
510 | margin: 0; | ||
511 | padding: 0.1em 0 0.1em 0.5em; | ||
512 | color: white; | ||
513 | font-weight: bold; | ||
514 | font-size: 1.1em; | ||
515 | text-shadow: 0 1px rgba(0, 0, 0, 0.5); | ||
516 | } | ||
517 | div.admonition ul, div.admonition ol, | ||
518 | div.warning ul, div.warning ol, | ||
519 | div.sidebar ul, div.sidebar ol { | ||
520 | margin: 0.1em 0.5em 0.5em 3em; | ||
521 | padding: 0; | ||
522 | } | ||
523 | |||
524 | |||
525 | /* Admonitions and sidebars only */ | ||
526 | div.admonition, div.sidebar { | ||
527 | border: 1px solid #609060; | ||
528 | background-color: #e9ffe9; | ||
529 | } | ||
530 | div.admonition p.admonition-title, | ||
531 | div.sidebar p.sidebar-title { | ||
532 | background-color: #70A070; | ||
533 | border-bottom: 1px solid #609060; | ||
534 | } | ||
535 | |||
536 | |||
537 | /* Warnings only */ | ||
538 | div.warning { | ||
539 | border: 1px solid #900000; | ||
540 | background-color: #ffe9e9; | ||
541 | } | ||
542 | div.warning p.admonition-title { | ||
543 | background-color: #b04040; | ||
544 | border-bottom: 1px solid #900000; | ||
545 | } | ||
546 | |||
547 | |||
548 | /* Sidebars only */ | ||
549 | div.sidebar { | ||
550 | max-width: 30%; | ||
551 | } | ||
552 | |||
553 | |||
554 | |||
555 | div.versioninfo { | ||
556 | margin: 1em 0 0 0; | ||
557 | border: 1px solid #ccc; | ||
558 | background-color: #DDEAF0; | ||
559 | padding: 8px; | ||
560 | line-height: 1.3em; | ||
561 | font-size: 0.9em; | ||
562 | } | ||
563 | |||
564 | .viewcode-back { | ||
565 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', | ||
566 | 'Verdana', sans-serif; | ||
567 | } | ||
568 | |||
569 | div.viewcode-block:target { | ||
570 | background-color: #f4debf; | ||
571 | border-top: 1px solid #ac9; | ||
572 | border-bottom: 1px solid #ac9; | ||
573 | } | ||
574 | |||
575 | dl { | ||
576 | margin: 1em 0 2.5em 0; | ||
577 | } | ||
578 | |||
579 | /* Highlight target when you click an internal link */ | ||
580 | dt:target { | ||
581 | background: #ffe080; | ||
582 | } | ||
583 | /* Don't highlight whole divs */ | ||
584 | div.highlight { | ||
585 | background: transparent; | ||
586 | } | ||
587 | /* But do highlight spans (so search results can be highlighted) */ | ||
588 | span.highlight { | ||
589 | background: #ffe080; | ||
590 | } | ||
591 | |||
592 | div.footer { | ||
593 | background-color: #465158; | ||
594 | color: #eeeeee; | ||
595 | padding: 0 2em 2em 2em; | ||
596 | clear: both; | ||
597 | font-size: 0.8em; | ||
598 | text-align: center; | ||
599 | } | ||
600 | |||
601 | p { | ||
602 | margin: 0.8em 0 0.5em 0; | ||
603 | } | ||
604 | |||
605 | .section p img.math { | ||
606 | margin: 0; | ||
607 | } | ||
608 | |||
609 | |||
610 | .section p img { | ||
611 | margin: 1em 2em; | ||
612 | } | ||
613 | |||
614 | |||
615 | /* MOBILE LAYOUT -------------------------------------------------------------- */ | ||
616 | |||
617 | @media screen and (max-width: 600px) { | ||
618 | |||
619 | h1, h2, h3, h4, h5 { | ||
620 | position: relative; | ||
621 | } | ||
622 | |||
623 | ul { | ||
624 | padding-left: 1.25em; | ||
625 | } | ||
626 | |||
627 | div.bodywrapper a.headerlink, #indices-and-tables h1 a { | ||
628 | color: #e6e6e6; | ||
629 | font-size: 80%; | ||
630 | float: right; | ||
631 | line-height: 1.8; | ||
632 | position: absolute; | ||
633 | right: -0.7em; | ||
634 | visibility: inherit; | ||
635 | } | ||
636 | |||
637 | div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a { | ||
638 | line-height: 1.5; | ||
639 | } | ||
640 | |||
641 | pre { | ||
642 | font-size: 0.7em; | ||
643 | overflow: auto; | ||
644 | word-wrap: break-word; | ||
645 | white-space: pre-wrap; | ||
646 | } | ||
647 | |||
648 | div.related ul { | ||
649 | height: 2.5em; | ||
650 | padding: 0; | ||
651 | text-align: left; | ||
652 | } | ||
653 | |||
654 | div.related ul li { | ||
655 | clear: both; | ||
656 | color: #465158; | ||
657 | padding: 0.2em 0; | ||
658 | } | ||
659 | |||
660 | div.related ul li:last-child { | ||
661 | border-bottom: 1px dotted #8ca1af; | ||
662 | padding-bottom: 0.4em; | ||
663 | margin-bottom: 1em; | ||
664 | width: 100%; | ||
665 | } | ||
666 | |||
667 | div.related ul li a { | ||
668 | color: #465158; | ||
669 | padding-right: 0; | ||
670 | } | ||
671 | |||
672 | div.related ul li a:hover { | ||
673 | background: inherit; | ||
674 | color: inherit; | ||
675 | } | ||
676 | |||
677 | div.related ul li.right { | ||
678 | clear: none; | ||
679 | padding: 0.65em 0; | ||
680 | margin-bottom: 0.5em; | ||
681 | } | ||
682 | |||
683 | div.related ul li.right a { | ||
684 | color: #fff; | ||
685 | padding-right: 0.8em; | ||
686 | } | ||
687 | |||
688 | div.related ul li.right a:hover { | ||
689 | background-color: #8ca1af; | ||
690 | } | ||
691 | |||
692 | div.body { | ||
693 | clear: both; | ||
694 | min-width: 0; | ||
695 | word-wrap: break-word; | ||
696 | } | ||
697 | |||
698 | div.bodywrapper { | ||
699 | margin: 0 0 0 0; | ||
700 | } | ||
701 | |||
702 | div.sphinxsidebar { | ||
703 | float: none; | ||
704 | margin: 0; | ||
705 | width: auto; | ||
706 | } | ||
707 | |||
708 | div.sphinxsidebar input[type="text"] { | ||
709 | height: 2em; | ||
710 | line-height: 2em; | ||
711 | width: 70%; | ||
712 | } | ||
713 | |||
714 | div.sphinxsidebar input[type="submit"] { | ||
715 | height: 2em; | ||
716 | margin-left: 0.5em; | ||
717 | width: 20%; | ||
718 | } | ||
719 | |||
720 | div.sphinxsidebar p.searchtip { | ||
721 | background: inherit; | ||
722 | margin-bottom: 1em; | ||
723 | } | ||
724 | |||
725 | div.sphinxsidebar ul li, div.sphinxsidebar p.topless { | ||
726 | white-space: normal; | ||
727 | } | ||
728 | |||
729 | .bodywrapper img { | ||
730 | display: block; | ||
731 | margin-left: auto; | ||
732 | margin-right: auto; | ||
733 | max-width: 100%; | ||
734 | } | ||
735 | |||
736 | div.documentwrapper { | ||
737 | float: none; | ||
738 | } | ||
739 | |||
740 | div.admonition, div.warning, pre, blockquote { | ||
741 | margin-left: 0em; | ||
742 | margin-right: 0em; | ||
743 | } | ||
744 | |||
745 | .body p img { | ||
746 | margin: 0; | ||
747 | } | ||
748 | |||
749 | #searchbox { | ||
750 | background: transparent; | ||
751 | } | ||
752 | |||
753 | .related:not(:first-child) li { | ||
754 | display: none; | ||
755 | } | ||
756 | |||
757 | .related:not(:first-child) li.right { | ||
758 | display: block; | ||
759 | } | ||
760 | |||
761 | div.footer { | ||
762 | padding: 1em; | ||
763 | } | ||
764 | |||
765 | .rtd_doc_footer .rtd-badge { | ||
766 | float: none; | ||
767 | margin: 1em auto; | ||
768 | position: static; | ||
769 | } | ||
770 | |||
771 | .rtd_doc_footer .rtd-badge.revsys-inline { | ||
772 | margin-right: auto; | ||
773 | margin-bottom: 2em; | ||
774 | } | ||
775 | |||
776 | table.indextable { | ||
777 | display: block; | ||
778 | width: auto; | ||
779 | } | ||
780 | |||
781 | .indextable tr { | ||
782 | display: block; | ||
783 | } | ||
784 | |||
785 | .indextable td { | ||
786 | display: block; | ||
787 | padding: 0; | ||
788 | width: auto !important; | ||
789 | } | ||
790 | |||
791 | .indextable td dt { | ||
792 | margin: 1em 0; | ||
793 | } | ||
794 | |||
795 | ul.search { | ||
796 | margin-left: 0.25em; | ||
797 | } | ||
798 | |||
799 | ul.search li div.context { | ||
800 | font-size: 90%; | ||
801 | line-height: 1.1; | ||
802 | margin-bottom: 1; | ||
803 | margin-left: 0; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | .donate { | ||
808 | text-align: center; | ||
809 | } | ||
810 | |||
811 | .donate .flattr { | ||
812 | margin-top: 1.5em; | ||
813 | } | ||
814 | |||
815 | |||
816 | .highlight .hll { background-color: #ffffcc } | ||
817 | .highlight { background: #eeffcc; } | ||
818 | .highlight .c { color: #408090; font-style: italic } /* Comment */ | ||
819 | .highlight .err { border: 1px solid #FF0000 } /* Error */ | ||
820 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ | ||
821 | .highlight .o { color: #666666 } /* Operator */ | ||
822 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ | ||
823 | .highlight .cp { color: #007020 } /* Comment.Preproc */ | ||
824 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ | ||
825 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ | ||
826 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ | ||
827 | .highlight .ge { font-style: italic } /* Generic.Emph */ | ||
828 | .highlight .gr { color: #FF0000 } /* Generic.Error */ | ||
829 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ | ||
830 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ | ||
831 | .highlight .go { color: #303030 } /* Generic.Output */ | ||
832 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ | ||
833 | .highlight .gs { font-weight: bold } /* Generic.Strong */ | ||
834 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ | ||
835 | .highlight .gt { color: #0040D0 } /* Generic.Traceback */ | ||
836 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ | ||
837 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ | ||
838 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ | ||
839 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ | ||
840 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ | ||
841 | .highlight .kt { color: #902000 } /* Keyword.Type */ | ||
842 | .highlight .m { color: #208050 } /* Literal.Number */ | ||
843 | .highlight .s { color: #4070a0 } /* Literal.String */ | ||
844 | .highlight .na { color: #4070a0 } /* Name.Attribute */ | ||
845 | .highlight .nb { color: #007020 } /* Name.Builtin */ | ||
846 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ | ||
847 | .highlight .no { color: #60add5 } /* Name.Constant */ | ||
848 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ | ||
849 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ | ||
850 | .highlight .ne { color: #007020 } /* Name.Exception */ | ||
851 | .highlight .nf { color: #06287e } /* Name.Function */ | ||
852 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ | ||
853 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ | ||
854 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ | ||
855 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ | ||
856 | .highlight .nx { color: #111111 } /* Std */ | ||
857 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ | ||
858 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ | ||
859 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ | ||
860 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ | ||
861 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ | ||
862 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ | ||
863 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ | ||
864 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ | ||
865 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ | ||
866 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ | ||
867 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ | ||
868 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ | ||
869 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ | ||
870 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ | ||
871 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ | ||
872 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ | ||
873 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ | ||
874 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ | ||
875 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ | ||
876 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ | ||
877 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ | ||
878 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ | ||
879 | |||
880 | /* https://github.com/n1k0/casperjs-docs/issues/2 */ | ||
881 | #casperjs-documentation img { | ||
882 | -webkit-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5)); | ||
883 | -moz-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5)); | ||
884 | -ms-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5)); | ||
885 | -o-filter: drop-shadow(0 1px 20px rgba(0,0,0,.5)); | ||
886 | filter: drop-shadow(0 1px 20px rgba(0,0,0,.5)); | ||
887 | } |
1 | /** | ||
2 | * http://www.alistapart.com/articles/alternate/ | ||
3 | * | ||
4 | * var cookie = readCookie("style"); | ||
5 | * var title = cookie ? cookie : getPreferredStyleSheet(); | ||
6 | * setActiveStyleSheet(title); | ||
7 | */ | ||
8 | (function(exports, $) { | ||
9 | function setActiveStyleSheet(title) { | ||
10 | var i, a, main; | ||
11 | for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) { | ||
12 | if (a.getAttribute("rel").indexOf("style") !== -1 && a.getAttribute("title")) { | ||
13 | a.disabled = true; | ||
14 | if (a.getAttribute("title") === title) { | ||
15 | a.disabled = false; | ||
16 | } | ||
17 | } | ||
18 | } | ||
19 | } | ||
20 | exports.setActiveStyleSheet = setActiveStyleSheet; | ||
21 | |||
22 | function getActiveStyleSheet() { | ||
23 | var i, a; | ||
24 | for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) { | ||
25 | if (a.getAttribute("rel").indexOf("style") !== -1 && a.getAttribute("title") && !a.disabled) { | ||
26 | return a.getAttribute("title"); | ||
27 | } | ||
28 | } | ||
29 | return null; | ||
30 | } | ||
31 | exports.getActiveStyleSheet = getActiveStyleSheet; | ||
32 | |||
33 | function getPreferredStyleSheet() { | ||
34 | var i, a; | ||
35 | for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) { | ||
36 | if (a.getAttribute("rel").indexOf("style") !== -1 && | ||
37 | a.getAttribute("rel").indexOf("alt") === -1 && | ||
38 | a.getAttribute("title")) { | ||
39 | return a.getAttribute("title"); | ||
40 | } | ||
41 | } | ||
42 | return null; | ||
43 | } | ||
44 | exports.getPreferredStyleSheet = getPreferredStyleSheet; | ||
45 | |||
46 | function createCookie(name, value, days) { | ||
47 | var expires = ""; | ||
48 | if (days) { | ||
49 | var date = new Date(); | ||
50 | date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); | ||
51 | expires = "; expires=" + date.toGMTString(); | ||
52 | } | ||
53 | document.cookie = name + "=" + value + expires + "; path=/"; | ||
54 | } | ||
55 | |||
56 | function readCookie(name) { | ||
57 | var nameEQ = name + "="; | ||
58 | var ca = document.cookie.split(';'); | ||
59 | for (var i = 0; i < ca.length; i++) { | ||
60 | var c = ca[i]; | ||
61 | while (c.charAt(0) === ' ') { | ||
62 | c = c.substring(1, c.length); | ||
63 | } | ||
64 | if (c.indexOf(nameEQ) === 0) { | ||
65 | return c.substring(nameEQ.length, c.length); | ||
66 | } | ||
67 | } | ||
68 | return null; | ||
69 | } | ||
70 | |||
71 | function createSwitcher() { | ||
72 | var $nav = $('.related').find('ul'); | ||
73 | var styles = $('link').filter(function(i, link){ | ||
74 | return $(link).attr('rel').indexOf('style') > -1 && $(link).attr('title'); | ||
75 | }).map(function(i, link) { | ||
76 | return $(link).attr('title'); | ||
77 | }); | ||
78 | $(styles).each(function(i, style) { | ||
79 | var $link = $('<a/>').attr('href', '#') | ||
80 | .attr('title', style) | ||
81 | .addClass('style-switch') | ||
82 | .text(style); | ||
83 | $nav.prepend($('<li/>').addClass('right').append($link)); | ||
84 | }); | ||
85 | $('.style-switch').bind('click', function(event) { | ||
86 | event.preventDefault(); | ||
87 | setActiveStyleSheet($(this).attr('title')); | ||
88 | }); | ||
89 | } | ||
90 | |||
91 | exports.onload = function(e) { | ||
92 | var cookie = readCookie("style"); | ||
93 | var title = cookie ? cookie : getPreferredStyleSheet(); | ||
94 | setActiveStyleSheet(title); | ||
95 | createSwitcher(); | ||
96 | } | ||
97 | |||
98 | exports.onunload = function(e) { | ||
99 | var title = getActiveStyleSheet(); | ||
100 | createCookie("style", title, 365); | ||
101 | } | ||
102 | |||
103 | var cookie = readCookie("style"); | ||
104 | var title = cookie ? cookie : getPreferredStyleSheet(); | ||
105 | setActiveStyleSheet(title); | ||
106 | })(window, window.jQuery); |
docs/_themes/casperjs/theme.conf
0 → 100644
docs/changelog.rst
0 → 100644
docs/cli.rst
0 → 100644
1 | .. _cli: | ||
2 | |||
3 | .. index:: Command line, CLI, PhantomJS, Shell, arguments, options | ||
4 | |||
5 | ====================== | ||
6 | Using the command line | ||
7 | ====================== | ||
8 | |||
9 | 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** | ||
10 | |||
11 | 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. | ||
12 | |||
13 | Let's consider this simple casper script:: | ||
14 | |||
15 | var casper = require("casper").create(); | ||
16 | |||
17 | casper.echo("Casper CLI passed args:"); | ||
18 | require("utils").dump(casper.cli.args); | ||
19 | |||
20 | casper.echo("Casper CLI passed options:"); | ||
21 | require("utils").dump(casper.cli.options); | ||
22 | |||
23 | casper.exit(); | ||
24 | |||
25 | .. note:: | ||
26 | |||
27 | Please note the two ``casper-path`` and ``cli`` options; these are passed to the casper script through the ``casperjs`` Python executable. | ||
28 | |||
29 | Execution results:: | ||
30 | |||
31 | $ casperjs test.js arg1 arg2 arg3 --foo=bar --plop anotherarg | ||
32 | Casper CLI passed args: [ | ||
33 | "arg1", | ||
34 | "arg2", | ||
35 | "arg3", | ||
36 | "anotherarg" | ||
37 | ] | ||
38 | Casper CLI passed options: { | ||
39 | "casper-path": "/Users/niko/Sites/casperjs", | ||
40 | "cli": true, | ||
41 | "foo": "bar", | ||
42 | "plop": true | ||
43 | } | ||
44 | |||
45 | Getting, checking or dropping parameters:: | ||
46 | |||
47 | var casper = require("casper").create(); | ||
48 | casper.echo(casper.cli.has(0)); | ||
49 | casper.echo(casper.cli.get(0)); | ||
50 | casper.echo(casper.cli.has(3)); | ||
51 | casper.echo(casper.cli.get(3)); | ||
52 | casper.echo(casper.cli.has("foo")); | ||
53 | casper.echo(casper.cli.get("foo")); | ||
54 | casper.cli.drop("foo"); | ||
55 | casper.echo(casper.cli.has("foo")); | ||
56 | casper.echo(casper.cli.get("foo")); | ||
57 | casper.exit(); | ||
58 | |||
59 | Execution results: | ||
60 | |||
61 | .. code-block:: text | ||
62 | |||
63 | $ casperjs test.js arg1 arg2 arg3 --foo=bar --plop anotherarg | ||
64 | true | ||
65 | arg1 | ||
66 | true | ||
67 | anotherarg | ||
68 | true | ||
69 | bar | ||
70 | false | ||
71 | undefined | ||
72 | |||
73 | .. hint:: | ||
74 | |||
75 | What if you want to check if any arg or option has been passed to your script? Here you go:: | ||
76 | |||
77 | // removing default options passed by the Python executable | ||
78 | casper.cli.drop("cli"); | ||
79 | casper.cli.drop("casper-path"); | ||
80 | |||
81 | if (casper.cli.args.length === 0 && Object.keys(casper.cli.options).length === 0) { | ||
82 | casper.echo("No arg nor option passed").exit(); | ||
83 | } | ||
84 | |||
85 | `casperjs` native options | ||
86 | ------------------------- | ||
87 | |||
88 | .. versionadded:: 1.1 | ||
89 | |||
90 | .. index:: Logging, log levels | ||
91 | |||
92 | The `casperjs` command has two available options: | ||
93 | |||
94 | - ``--direct``: to prints out log messages to the console | ||
95 | - ``--log-level=[debug|info|warning|error]`` to set the :ref:`logging level <logging>` | ||
96 | |||
97 | Example: | ||
98 | |||
99 | .. code-block:: text | ||
100 | |||
101 | $ casperjs --direct --log-level=debug myscript.js | ||
102 | |||
103 | Last but not least, you can still use all PhantomJS standard CLI options as you would do with any other phantomjs script: | ||
104 | |||
105 | .. code-block:: text | ||
106 | |||
107 | $ casperjs --web-security=no --cookies-file=/tmp/mycookies.txt myscript.js | ||
108 | |||
109 | .. hint:: | ||
110 | |||
111 | To remember what the native phantomjs available cli options are, run the ``phantomjs --help`` command. | ||
112 | |||
113 | |||
114 | .. index:: Raw values | ||
115 | |||
116 | Raw parameter values | ||
117 | -------------------- | ||
118 | |||
119 | .. versionadded:: 1.0 | ||
120 | |||
121 | By default, the cli object will process every passed argument & cast them to the appropriate detected type; example script:: | ||
122 | |||
123 | var casper = require('casper').create(); | ||
124 | var utils = require('utils'); | ||
125 | |||
126 | utils.dump(casper.cli.get('foo')); | ||
127 | |||
128 | casper.exit(); | ||
129 | |||
130 | If you run this script: | ||
131 | |||
132 | .. code-block:: text | ||
133 | |||
134 | $ casperjs c.js --foo=01234567 | ||
135 | 1234567 | ||
136 | |||
137 | As you can see, the ``01234567`` value has been cast to a *Number*. | ||
138 | |||
139 | 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:: | ||
140 | |||
141 | var casper = require('casper').create(); | ||
142 | var utils = require('utils'); | ||
143 | |||
144 | utils.dump(casper.cli.get('foo')); | ||
145 | utils.dump(casper.cli.raw.get('foo')); | ||
146 | |||
147 | casper.exit(); | ||
148 | |||
149 | Sample usage: | ||
150 | |||
151 | .. code-block:: text | ||
152 | |||
153 | $ casperjs c.js --foo=01234567 | ||
154 | 1234567 | ||
155 | "01234567" | ||
156 |
docs/conf.py
0 → 100644
1 | # -*- coding: utf-8 -*- | ||
2 | # | ||
3 | # CasperJS documentation | ||
4 | # | ||
5 | # If extensions (or modules to document with autodoc) are in another directory, | ||
6 | # add these directories to sys.path here. If the directory is relative to the | ||
7 | # documentation root, use os.path.abspath to make it absolute, like shown here. | ||
8 | #sys.path.insert(0, os.path.abspath('.')) | ||
9 | |||
10 | from datetime import date | ||
11 | |||
12 | # -- General configuration ----------------------------------------------------- | ||
13 | |||
14 | # If your documentation needs a minimal Sphinx version, state it here. | ||
15 | #needs_sphinx = '1.0' | ||
16 | |||
17 | # Add any Sphinx extension module names here, as strings. They can be extensions | ||
18 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. | ||
19 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.extlinks'] | ||
20 | |||
21 | # Add any paths that contain templates here, relative to this directory. | ||
22 | templates_path = ['_templates'] | ||
23 | |||
24 | highlight_language = 'javascript' | ||
25 | |||
26 | # The suffix of source filenames. | ||
27 | source_suffix = '.rst' | ||
28 | |||
29 | # Prolog | ||
30 | rst_prolog = ('.. note:: This is the documentation for the |release| version of' | ||
31 | ' CasperJS. Find docs for 1.0 stable' | ||
32 | ' `on the official website <http://casperjs.org/>`_.\n') | ||
33 | |||
34 | # The encoding of source files. | ||
35 | source_encoding = 'utf-8' | ||
36 | |||
37 | # The master toctree document. | ||
38 | master_doc = 'index' | ||
39 | |||
40 | # General information about the project. | ||
41 | project = u'CasperJS' | ||
42 | copyright = (u'2011-%d Nicolas Perriault and contributors. CasperJS logo by Jeremy Forveille' | ||
43 | % date.today().year) | ||
44 | |||
45 | # The version info for the project you're documenting, acts as replacement for | ||
46 | # |version| and |release|, also used in various other places throughout the | ||
47 | # built documents. | ||
48 | # | ||
49 | # The short X.Y version. | ||
50 | version = '1.1' | ||
51 | # The full version, including alpha/beta/rc tags. | ||
52 | release = '1.1.0-DEV' | ||
53 | |||
54 | # The language for content autogenerated by Sphinx. Refer to documentation | ||
55 | # for a list of supported languages. | ||
56 | #language = None | ||
57 | |||
58 | # There are two options for replacing |today|: either, you set today to some | ||
59 | # non-false value, then it is used: | ||
60 | #today = '' | ||
61 | # Else, today_fmt is used as the format for a strftime call. | ||
62 | #today_fmt = '%B %d, %Y' | ||
63 | |||
64 | # List of patterns, relative to source directory, that match files and | ||
65 | # directories to ignore when looking for source files. | ||
66 | exclude_patterns = ['_build', 'README.md'] | ||
67 | |||
68 | # The reST default role (used for this markup: `text`) to use for all documents. | ||
69 | #default_role = None | ||
70 | |||
71 | # If true, '()' will be appended to :func: etc. cross-reference text. | ||
72 | #add_function_parentheses = True | ||
73 | |||
74 | # If true, the current module name will be prepended to all description | ||
75 | # unit titles (such as .. function::). | ||
76 | #add_module_names = True | ||
77 | |||
78 | # If true, sectionauthor and moduleauthor directives will be shown in the | ||
79 | # output. They are ignored by default. | ||
80 | #show_authors = False | ||
81 | |||
82 | # The name of the Pygments (syntax highlighting) style to use. | ||
83 | #pygments_style = 'default' | ||
84 | |||
85 | # A list of ignored prefixes for module index sorting. | ||
86 | #modindex_common_prefix = [] | ||
87 | |||
88 | |||
89 | # -- Options for HTML output --------------------------------------------------- | ||
90 | |||
91 | # The theme to use for HTML and HTML Help pages. See the documentation for | ||
92 | # a list of builtin themes. | ||
93 | html_theme = 'casperjs' | ||
94 | |||
95 | # Theme options are theme-specific and customize the look and feel of a theme | ||
96 | # further. For a list of options available for each theme, see the | ||
97 | # documentation. | ||
98 | #html_theme_options = {} | ||
99 | |||
100 | # Add any paths that contain custom themes here, relative to this directory. | ||
101 | html_theme_path = ['_themes'] | ||
102 | |||
103 | # The name for this set of Sphinx documents. If None, it defaults to | ||
104 | # "<project> v<release> documentation". | ||
105 | #html_title = None | ||
106 | |||
107 | # A shorter title for the navigation bar. Default is the same as html_title. | ||
108 | #html_short_title = None | ||
109 | |||
110 | # The name of an image file (relative to this directory) to place at the top | ||
111 | # of the sidebar. | ||
112 | #html_logo = None | ||
113 | |||
114 | # The name of an image file (within the static path) to use as favicon of the | ||
115 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 | ||
116 | # pixels large. | ||
117 | html_favicon = 'casperjs-favicon.ico' | ||
118 | |||
119 | # Add any paths that contain custom static files (such as style sheets) here, | ||
120 | # relative to this directory. They are copied after the builtin static files, | ||
121 | # so a file named "default.css" will overwrite the builtin "default.css". | ||
122 | html_static_path = ['_static'] | ||
123 | |||
124 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | ||
125 | # using the given strftime format. | ||
126 | #html_last_updated_fmt = '%b %d, %Y' | ||
127 | |||
128 | # If true, SmartyPants will be used to convert quotes and dashes to | ||
129 | # typographically correct entities. | ||
130 | #html_use_smartypants = True | ||
131 | |||
132 | # Custom sidebar templates, maps document names to template names. | ||
133 | html_sidebars = { | ||
134 | '*': [ | ||
135 | 'globaltoc.html', | ||
136 | 'relations.html', | ||
137 | 'sourcelink.html', | ||
138 | 'searchbox.html', | ||
139 | 'addon.html' | ||
140 | ], | ||
141 | 'modules/*': [ | ||
142 | 'localtoc.html', | ||
143 | 'globaltoc.html', | ||
144 | 'relations.html', | ||
145 | 'sourcelink.html', | ||
146 | 'searchbox.html', | ||
147 | 'addon.html' | ||
148 | ], | ||
149 | } | ||
150 | |||
151 | # Additional templates that should be rendered to pages, maps page names to | ||
152 | # template names. | ||
153 | #html_additional_pages = {} | ||
154 | |||
155 | # If false, no module index is generated. | ||
156 | #html_domain_indices = True | ||
157 | |||
158 | # If false, no index is generated. | ||
159 | #html_use_index = True | ||
160 | |||
161 | # If true, the index is split into individual pages for each letter. | ||
162 | #html_split_index = False | ||
163 | |||
164 | # If true, links to the reST sources are added to the pages. | ||
165 | #html_show_sourcelink = True | ||
166 | |||
167 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | ||
168 | #html_show_sphinx = True | ||
169 | |||
170 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | ||
171 | #html_show_copyright = True | ||
172 | |||
173 | # If true, an OpenSearch description file will be output, and all pages will | ||
174 | # contain a <link> tag referring to it. The value of this option must be the | ||
175 | # base URL from which the finished HTML is served. | ||
176 | #html_use_opensearch = '' | ||
177 | |||
178 | # This is the file name suffix for HTML files (e.g. ".xhtml"). | ||
179 | #html_file_suffix = None | ||
180 | |||
181 | # Output file base name for HTML help builder. | ||
182 | htmlhelp_basename = 'casper-docs' | ||
183 | |||
184 | |||
185 | # -- Options for LaTeX output -------------------------------------------------- | ||
186 | |||
187 | latex_elements = { | ||
188 | # The paper size ('letterpaper' or 'a4paper'). | ||
189 | #'papersize': 'letterpaper', | ||
190 | |||
191 | # The font size ('10pt', '11pt' or '12pt'). | ||
192 | #'pointsize': '10pt', | ||
193 | |||
194 | # Additional stuff for the LaTeX preamble. | ||
195 | #'preamble': '', | ||
196 | } | ||
197 | |||
198 | # Grouping the document tree into LaTeX files. List of tuples | ||
199 | # (source start file, target name, title, author, documentclass [howto/manual]). | ||
200 | # latex_documents = [ | ||
201 | # (), | ||
202 | # ] | ||
203 | |||
204 | # The name of an image file (relative to this directory) to place at the top of | ||
205 | # the title page. | ||
206 | #latex_logo = None | ||
207 | |||
208 | # For "manual" documents, if this is true, then toplevel headings are parts, | ||
209 | # not chapters. | ||
210 | #latex_use_parts = False | ||
211 | |||
212 | # If true, show page references after internal links. | ||
213 | #latex_show_pagerefs = False | ||
214 | |||
215 | # If true, show URL addresses after external links. | ||
216 | #latex_show_urls = False | ||
217 | |||
218 | # Documents to append as an appendix to all manuals. | ||
219 | #latex_appendices = [] | ||
220 | |||
221 | # If false, no module index is generated. | ||
222 | #latex_domain_indices = True | ||
223 | |||
224 | |||
225 | # -- Options for manual page output -------------------------------------------- | ||
226 | |||
227 | # One entry per manual page. List of tuples | ||
228 | # (source start file, name, description, authors, manual section). | ||
229 | man_pages = [ | ||
230 | ('index', 'casperjs', u'casperjs documentation', [u'Nicolas Perriault'], 1) | ||
231 | ] | ||
232 | |||
233 | # If true, show URL addresses after external links. | ||
234 | #man_show_urls = False | ||
235 | |||
236 | |||
237 | # -- Options for Texinfo output ------------------------------------------------ | ||
238 | |||
239 | # Grouping the document tree into Texinfo files. List of tuples | ||
240 | # (source start file, target name, title, author, | ||
241 | # dir menu entry, description, category) | ||
242 | texinfo_documents = [ | ||
243 | ('index', 'CasperJS', u'CasperJS Documentation', | ||
244 | u'Nicolas Perriault', 'CasperJS', 'CasperJS docs.', 'Miscellaneous'), | ||
245 | ] | ||
246 | |||
247 | # Documents to append as an appendix to all manuals. | ||
248 | #texinfo_appendices = [] | ||
249 | |||
250 | # If false, no module index is generated. | ||
251 | #texinfo_domain_indices = True | ||
252 | |||
253 | # How to display URL addresses: 'footnote', 'no', or 'inline'. | ||
254 | #texinfo_show_urls = 'footnote' | ||
255 | |||
256 | |||
257 | extlinks = { | ||
258 | 'issue': ('https://github.com/n1k0/casperjs/issues/%s', '#'), | ||
259 | 'repo': ('https://github.com/n1k0/casperjs/%s', ''), | ||
260 | } |
docs/credits.rst
0 → 100644
1 | Credits | ||
2 | ======= | ||
3 | |||
4 | Author | ||
5 | ------ | ||
6 | |||
7 | CasperJS is mainly developed by `Nicolas Perriault <https://nicolas.perriault.net/>`_ on its free time. | ||
8 | |||
9 | If you want to thank him and/or sponsor the development of CasperJS, please consider donating (see links in the sidebar). | ||
10 | |||
11 | Contributors | ||
12 | ------------ | ||
13 | |||
14 | These people have contributed to CasperJS: | ||
15 | |||
16 | - Brikou CARRE | ||
17 | - Thomas Parisot | ||
18 | - Han Yu | ||
19 | - Chris Lorenzo | ||
20 | - Victor Yap | ||
21 | - Rob Barreca | ||
22 | - Tyler Ritchie | ||
23 | - Nick Rabinowitz | ||
24 | - Pascal Borreli | ||
25 | - Dave Lee | ||
26 | - Andrew Childs | ||
27 | - Solomon White | ||
28 | - Reina Sweet | ||
29 | - Jan Schaumann | ||
30 | - Elmar Langholz | ||
31 | - Clochix | ||
32 | - Donovan Hutchinson | ||
33 | - Julien Moulin | ||
34 | - Michael Geers | ||
35 | - Jason Funk | ||
36 | - Vladimir Chizhov | ||
37 | - Jean-Philippe Serafin | ||
38 | - snkashis | ||
39 | - Rafael | ||
40 | - Andrew de Andrade | ||
41 | - Ben Lowery | ||
42 | - Chris Winters | ||
43 | - Christophe Benz | ||
44 | - Harrison Reiser | ||
45 | - Jan Pochyla | ||
46 | - Jan-Martin Fruehwacht | ||
47 | - Julian Gruber | ||
48 | - Justin Slattery | ||
49 | - Justine Tunney | ||
50 | - KaroDidi | ||
51 | - Leandro Boscariol | ||
52 | - Maisons du monde | ||
53 | - Marcel Duran | ||
54 | - Mathieu Agopian | ||
55 | - Mehdi Kabab | ||
56 | - Mikko Peltonen | ||
57 | - Rafael Garcia | ||
58 | - Raphaël Benitte | ||
59 | - Tim Bunce | ||
60 | |||
61 | Logo | ||
62 | ---- | ||
63 | |||
64 | CasperJS logo designed by `Jeremy Forveille <http://www.forveillejeremy.com/>`_ |
docs/debugging.rst
0 → 100644
1 | .. _debugging: | ||
2 | |||
3 | .. index:: Bugs, Debugging | ||
4 | |||
5 | ========= | ||
6 | Debugging | ||
7 | ========= | ||
8 | |||
9 | .. contents:: A few tips for debugging your casper scripts: | ||
10 | :local: | ||
11 | |||
12 | |||
13 | Use the :index:`verbose` mode | ||
14 | ----------------------------- | ||
15 | |||
16 | 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`:: | ||
17 | |||
18 | var casper = require('casper').create({ | ||
19 | verbose: true, | ||
20 | logLevel: "debug" | ||
21 | }); | ||
22 | |||
23 | 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. | ||
24 | |||
25 | .. warning:: | ||
26 | |||
27 | Output will then be pretty verbose, and will potentially display sensitive informations onto the console. **Use with care on production.** | ||
28 | |||
29 | |||
30 | Hook in the deep using :index:`events` | ||
31 | -------------------------------------- | ||
32 | |||
33 | :doc:`Events <events-filters>` are a very powerful features of CasperJS, and you should probably give it a look if you haven't already. | ||
34 | |||
35 | Some interesting events you may eventually use to debug your scripts: | ||
36 | |||
37 | - 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``; | ||
38 | - The ``remote.alert`` everytime an ``alert()`` call is performed client-side; | ||
39 | - ``remote.message`` everytime a message is sent to the client-side console; | ||
40 | - ``step.added`` everytime a step is added to the stack; | ||
41 | - etc… | ||
42 | |||
43 | Listening to an event is dead easy:: | ||
44 | |||
45 | casper.on('http.status.404', function(resource) { | ||
46 | this.log('Hey, this one is 404: ' + resource.url, 'warning'); | ||
47 | }); | ||
48 | |||
49 | Ensure to check the :ref:`full list <events_list>` of all the other available events. | ||
50 | |||
51 | |||
52 | .. _debugging_dump: | ||
53 | |||
54 | Dump serialized values to the console | ||
55 | ------------------------------------- | ||
56 | |||
57 | Sometimes it's helpful to inspect a variable, especially Object contents. The :ref:`utils_dump() <utils_dump>` function can achieve just that:: | ||
58 | |||
59 | require('utils').dump({ | ||
60 | foo: { | ||
61 | bar: 42 | ||
62 | }, | ||
63 | }); | ||
64 | |||
65 | .. note:: | ||
66 | |||
67 | :ref:`utils_dump() <utils_dump>` won't be able to serialize function nor complex cyclic structures though. | ||
68 | |||
69 | |||
70 | Localize yourself in modules | ||
71 | ---------------------------- | ||
72 | |||
73 | 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). | ||
74 | |||
75 | |||
76 | Name your closures | ||
77 | ------------------ | ||
78 | |||
79 | Probably one of the most easy but effective best practice, always name your closures: | ||
80 | |||
81 | **Hard to track:** | ||
82 | |||
83 | :: | ||
84 | |||
85 | casper.start('http://foo.bar/', function() { | ||
86 | this.evaluate(function() { | ||
87 | // ... | ||
88 | }); | ||
89 | }); | ||
90 | |||
91 | **Easier:** | ||
92 | |||
93 | :: | ||
94 | |||
95 | casper.start('http://foo.bar/', function afterStart() { | ||
96 | this.evaluate(function evaluateStuffAfterStart() { | ||
97 | // ... | ||
98 | }); | ||
99 | }); | ||
100 | |||
101 | 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**. | ||
102 | |||
103 | .. note:: | ||
104 | |||
105 | This one also applies for all your other Javascript works, of course ;) |
docs/events-filters.rst
0 → 100644
1 | .. _events_filters: | ||
2 | |||
3 | Events & filters | ||
4 | ================ | ||
5 | |||
6 | 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. | ||
7 | |||
8 | |||
9 | .. index:: ! events | ||
10 | |||
11 | Events | ||
12 | ------ | ||
13 | |||
14 | Using events is pretty much straightforward if you're a node developer, or if you worked with any evented system before:: | ||
15 | |||
16 | var casper = require('casper').create(); | ||
17 | |||
18 | casper.on('resource.received', function(resource) { | ||
19 | casper.echo(resource.url); | ||
20 | }); | ||
21 | |||
22 | Emitting you own events | ||
23 | +++++++++++++++++++++++ | ||
24 | |||
25 | Of course you can emit your own events, using the ``Casper.emit()`` method:: | ||
26 | |||
27 | var casper = require('casper').create(); | ||
28 | |||
29 | // listening to a custom event | ||
30 | casper.on('google.loaded', function() { | ||
31 | this.echo('Google page title is ' + this.getTitle()); | ||
32 | }); | ||
33 | |||
34 | casper.start('http://google.com/', function() { | ||
35 | // emitting a custom event | ||
36 | this.emit('google.loaded'); | ||
37 | }); | ||
38 | |||
39 | casper.run(); | ||
40 | |||
41 | .. _events_list: | ||
42 | |||
43 | Events reference | ||
44 | ++++++++++++++++ | ||
45 | |||
46 | ``back`` | ||
47 | ~~~~~~~~ | ||
48 | |||
49 | **Arguments:** ``None`` | ||
50 | |||
51 | Emitted when the embedded browser is asked to go back a step in its history. | ||
52 | |||
53 | ``capture.saved`` | ||
54 | ~~~~~~~~~~~~~~~~~ | ||
55 | |||
56 | **Arguments:** ``targetFile`` | ||
57 | |||
58 | Emitted when a :index:`screenshot` image has been captured. | ||
59 | |||
60 | .. index:: click | ||
61 | |||
62 | ``click`` | ||
63 | ~~~~~~~~~ | ||
64 | |||
65 | **Arguments:** ``selector`` | ||
66 | |||
67 | Emitted when the ``Casper.click()`` method has been called. | ||
68 | |||
69 | ``die`` | ||
70 | ~~~~~~~ | ||
71 | |||
72 | **Arguments:** ``message, status`` | ||
73 | |||
74 | Emitted when the ``Casper.die()`` method has been called. | ||
75 | |||
76 | .. index:: download | ||
77 | |||
78 | ``downloaded.file`` | ||
79 | ~~~~~~~~~~~~~~~~~~~ | ||
80 | |||
81 | **Arguments:** ``targetPath`` | ||
82 | |||
83 | Emitted when a file has been downloaded by :ref:`Casper.download() <casper_download>`; ``target`` will contain the path to the downloaded file. | ||
84 | |||
85 | .. index:: error | ||
86 | |||
87 | ``error`` | ||
88 | ~~~~~~~~~ | ||
89 | |||
90 | **Arguments:** ``msg, backtrace`` | ||
91 | |||
92 | .. versionadded:: 0.6.9 | ||
93 | |||
94 | Emitted when an error hasn't been caught. Do basically what PhantomJS' ``onError()`` native handler does. | ||
95 | |||
96 | .. index:: exit | ||
97 | |||
98 | ``exit`` | ||
99 | ~~~~~~~~ | ||
100 | |||
101 | **Arguments:** ``status`` | ||
102 | |||
103 | Emitted when the ``Casper.exit()`` method has been called. | ||
104 | |||
105 | .. index:: fill | ||
106 | |||
107 | ``fill`` | ||
108 | ~~~~~~~~ | ||
109 | |||
110 | **Arguments:** ``selector, vals, submit`` | ||
111 | |||
112 | Emitted when a form is filled using the ``Casper.fill()`` method. | ||
113 | |||
114 | ``forward`` | ||
115 | ~~~~~~~~~~~ | ||
116 | |||
117 | **Arguments:** ``None`` | ||
118 | |||
119 | Emitted when the embedded browser is asked to go forward a step in its history. | ||
120 | |||
121 | .. index:: auth | ||
122 | |||
123 | ``http.auth`` | ||
124 | ~~~~~~~~~~~~~ | ||
125 | |||
126 | **Arguments:** ``username, password`` | ||
127 | |||
128 | Emitted when http authentication parameters are set. | ||
129 | |||
130 | .. index:: HTTP | ||
131 | |||
132 | ``http.status.[code]`` | ||
133 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
134 | |||
135 | **Arguments:** ``resource`` | ||
136 | |||
137 | Emitted when any given HTTP reponse is received with the status code specified by ``[code]``, eg.:: | ||
138 | |||
139 | casper.on('http.status.404', function(resource) { | ||
140 | casper.echo(resource.url + ' is 404'); | ||
141 | }) | ||
142 | |||
143 | ``load.started`` | ||
144 | ~~~~~~~~~~~~~~~~ | ||
145 | |||
146 | **Arguments:** ``None`` | ||
147 | |||
148 | Emitted when PhantomJS' ``WebPage.onLoadStarted`` event callback is called. | ||
149 | |||
150 | ``load.failed`` | ||
151 | ~~~~~~~~~~~~~~~ | ||
152 | |||
153 | **Arguments:** ``Object`` | ||
154 | |||
155 | Emitted when PhantomJS' ``WebPage.onLoadFinished`` event callback has been called and failed. | ||
156 | |||
157 | ``load.finished`` | ||
158 | ~~~~~~~~~~~~~~~~~ | ||
159 | |||
160 | **Arguments:** ``status`` | ||
161 | |||
162 | Emitted when PhantomJS' ``WebPage.onLoadFinished`` event callback is called. | ||
163 | |||
164 | .. index:: log | ||
165 | |||
166 | ``log`` | ||
167 | ~~~~~~~ | ||
168 | |||
169 | **Arguments:** ``entry`` | ||
170 | |||
171 | Emitted when the ``Casper.log()`` method has been called. The ``entry`` parameter is an Object like this:: | ||
172 | |||
173 | { | ||
174 | level: "debug", | ||
175 | space: "phantom", | ||
176 | message: "A message", | ||
177 | date: "a javascript Date instance" | ||
178 | } | ||
179 | |||
180 | ..index:: click | ||
181 | |||
182 | ``mouse.click`` | ||
183 | ~~~~~~~~~~~~~~~ | ||
184 | |||
185 | **Arguments:** ``args`` | ||
186 | |||
187 | Emitted when the mouse left-click something or somewhere. | ||
188 | |||
189 | ``mouse.down`` | ||
190 | ~~~~~~~~~~~~~~ | ||
191 | |||
192 | **Arguments:** ``args`` | ||
193 | |||
194 | Emitted when the mouse presses on something or somewhere with the left button. | ||
195 | |||
196 | ``mouse.move`` | ||
197 | ~~~~~~~~~~~~~~ | ||
198 | |||
199 | **Arguments:** ``args`` | ||
200 | |||
201 | Emitted when the mouse moves onto something or somewhere. | ||
202 | |||
203 | ``mouse.up`` | ||
204 | ~~~~~~~~~~~~ | ||
205 | |||
206 | **Arguments:** ``args`` | ||
207 | |||
208 | Emitted when the mouse releases the left button over something or somewhere. | ||
209 | |||
210 | ``navigation.requested`` | ||
211 | ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
212 | |||
213 | **Arguments:** ``url, navigationType, navigationLocked, isMainFrame`` | ||
214 | |||
215 | .. versionadded:: 1.0 | ||
216 | |||
217 | Emitted each time a navigation operation has been requested. Available navigation types are: ``LinkClicked``, ``FormSubmitted``, ``BackOrForward``, ``Reload``, ``FormResubmitted`` and ``Other``. | ||
218 | |||
219 | .. index:: HTTP | ||
220 | |||
221 | ``open`` | ||
222 | ~~~~~~~~ | ||
223 | |||
224 | ``location, settings`` | ||
225 | |||
226 | Emitted when an HTTP request is sent. First callback arg is the location, second one is a request settings Object of the form:: | ||
227 | |||
228 | { | ||
229 | method: "post", | ||
230 | data: "foo=42&chuck=norris" | ||
231 | } | ||
232 | |||
233 | ``page.created`` | ||
234 | ~~~~~~~~~~~~~~~~ | ||
235 | |||
236 | **Arguments:** ``page`` | ||
237 | |||
238 | Emitted when PhantomJS' ``WebPage`` object used by CasperJS has been created. | ||
239 | |||
240 | ``page.error`` | ||
241 | ~~~~~~~~~~~~~~ | ||
242 | |||
243 | **Arguments:** ``message, trace`` | ||
244 | |||
245 | Emitted when retrieved page leaved a Javascript error uncaught:: | ||
246 | |||
247 | casper.on("page.error", function(msg, trace) { | ||
248 | this.echo("Error: " + msg, "ERROR"); | ||
249 | }); | ||
250 | |||
251 | ``page.initialized`` | ||
252 | ~~~~~~~~~~~~~~~~~~~~ | ||
253 | |||
254 | **Arguments:** ``WebPage`` | ||
255 | |||
256 | Emitted when PhantomJS' ``WebPage`` object used by CasperJS has been initialized. | ||
257 | |||
258 | .. index:: HTTP | ||
259 | |||
260 | ``page.resource.received`` | ||
261 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
262 | |||
263 | **Arguments:** ``response`` | ||
264 | |||
265 | Emitted when the HTTP response corresponding to current required url has been received. | ||
266 | |||
267 | .. index:: HTTP | ||
268 | |||
269 | ``page.resource.requested`` | ||
270 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
271 | |||
272 | **Arguments:** ``request`` | ||
273 | |||
274 | Emitted when a new HTTP request is performed to open the required url. | ||
275 | |||
276 | ``popup.created`` | ||
277 | ~~~~~~~~~~~~~~~~~ | ||
278 | |||
279 | **Arguments:** ``WebPage`` | ||
280 | |||
281 | Emitted when a new window has been opened. | ||
282 | |||
283 | ``popup.loaded`` | ||
284 | ~~~~~~~~~~~~~~~~ | ||
285 | |||
286 | **Arguments:** ``WebPage`` | ||
287 | |||
288 | Emitted when a new window has been loaded. | ||
289 | |||
290 | ``popup.closed`` | ||
291 | ~~~~~~~~~~~~~~~~ | ||
292 | |||
293 | **Arguments:** ``WebPage`` | ||
294 | |||
295 | Emitted when a new opened window has been closed. | ||
296 | |||
297 | ``popup.created`` | ||
298 | ~~~~~~~~~~~~~~~~~ | ||
299 | |||
300 | **Arguments:** ``WebPage`` | ||
301 | |||
302 | Emitted when a new window has been opened. | ||
303 | |||
304 | ``remote.alert`` | ||
305 | ~~~~~~~~~~~~~~~~ | ||
306 | |||
307 | **Arguments:** ``message`` | ||
308 | |||
309 | Emitted when a remote ``alert()`` call has been performed. | ||
310 | |||
311 | ``remote.message`` | ||
312 | ~~~~~~~~~~~~~~~~~~ | ||
313 | |||
314 | **Arguments:** ``msg`` | ||
315 | |||
316 | Emitted when any remote console logging call has been performed. | ||
317 | |||
318 | ``resource.received`` | ||
319 | ~~~~~~~~~~~~~~~~~~~~~ | ||
320 | |||
321 | **Arguments:** ``resource`` | ||
322 | |||
323 | Emitted when any resource has been received. | ||
324 | |||
325 | ``resource.requested`` | ||
326 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
327 | |||
328 | **Arguments:** ``request`` | ||
329 | |||
330 | Emitted when any resource has been requested. | ||
331 | |||
332 | ``run.complete`` | ||
333 | ~~~~~~~~~~~~~~~~ | ||
334 | |||
335 | **Arguments:** ``None`` | ||
336 | |||
337 | Emitted when the whole series of steps in the stack have been executed. | ||
338 | |||
339 | ``run.start`` | ||
340 | ~~~~~~~~~~~~~ | ||
341 | |||
342 | **Arguments:** ``None`` | ||
343 | |||
344 | Emitted when ``Casper.run()`` is called. | ||
345 | |||
346 | ``starting`` | ||
347 | ~~~~~~~~~~~~ | ||
348 | |||
349 | **Arguments:** ``None`` | ||
350 | |||
351 | Emitted when ``Casper.start()`` is called. | ||
352 | |||
353 | ``started`` | ||
354 | ~~~~~~~~~~~ | ||
355 | |||
356 | **Arguments:** ``None`` | ||
357 | |||
358 | Emitted when Casper has been started using ``Casper.start()``. | ||
359 | |||
360 | ``step.added`` | ||
361 | ~~~~~~~~~~~~~~ | ||
362 | |||
363 | **Arguments:** ``step`` | ||
364 | |||
365 | Emitted when a new navigation step has been added to the stack. | ||
366 | |||
367 | ``step.complete`` | ||
368 | ~~~~~~~~~~~~~~~~~ | ||
369 | |||
370 | **Arguments:** ``stepResult`` | ||
371 | |||
372 | Emitted when a navigation step has been executed. | ||
373 | |||
374 | ``step.created`` | ||
375 | ~~~~~~~~~~~~~~~~ | ||
376 | |||
377 | **Arguments:** ``fn`` | ||
378 | |||
379 | Emitted when a new navigation step has been created. | ||
380 | |||
381 | ``step.start`` | ||
382 | ~~~~~~~~~~~~~~ | ||
383 | |||
384 | **Arguments:** ``step`` | ||
385 | |||
386 | Emitted when a navigation step has been started. | ||
387 | |||
388 | ``step.timeout`` | ||
389 | ~~~~~~~~~~~~~~~~ | ||
390 | |||
391 | **Arguments:** ``None`` | ||
392 | |||
393 | Emitted when a navigation step has been executed. | ||
394 | |||
395 | ``timeout`` | ||
396 | ~~~~~~~~~~~ | ||
397 | |||
398 | **Arguments:** ``None`` | ||
399 | |||
400 | Emitted when the execution time of the script has reached the ``Casper.options.timeout`` value. | ||
401 | |||
402 | ``url.changed`` | ||
403 | ~~~~~~~~~~~~~~~ | ||
404 | |||
405 | **Arguments:** ``url`` | ||
406 | |||
407 | .. versionadded:: 1.0 | ||
408 | |||
409 | Emitted each time the current page url changes. | ||
410 | |||
411 | .. index:: viewport | ||
412 | |||
413 | ``viewport.changed`` | ||
414 | ~~~~~~~~~~~~~~~~~~~~ | ||
415 | |||
416 | **Arguments:** ``[width, height]`` | ||
417 | |||
418 | Emitted when the viewport has been changed. | ||
419 | |||
420 | ``wait.done`` | ||
421 | ~~~~~~~~~~~~~ | ||
422 | |||
423 | **Arguments:** ``None`` | ||
424 | |||
425 | Emitted when a ``Casper.wait()``\ *operation ends.* | ||
426 | |||
427 | ``wait.start`` | ||
428 | ~~~~~~~~~~~~~~ | ||
429 | |||
430 | **Arguments:** ``None`` | ||
431 | |||
432 | Emitted when a ``Casper.wait()`` operation starts. | ||
433 | |||
434 | ``waitFor.timeout`` | ||
435 | ~~~~~~~~~~~~~~~~~~~ | ||
436 | |||
437 | **Arguments:** ``None`` | ||
438 | |||
439 | Emitted when the execution time of a ``Casper.wait*()`` operation has exceeded the value of ``Casper.options.stepTimeout``. | ||
440 | |||
441 | |||
442 | .. index:: filters | ||
443 | |||
444 | Filters | ||
445 | ------- | ||
446 | |||
447 | 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:: | ||
448 | |||
449 | var casper = require('casper').create(); | ||
450 | |||
451 | casper.setFilter('open.location', function(location) { | ||
452 | return /\?+/.test(location) ? location += "&foo=42" : location += "?foo=42"; | ||
453 | }); | ||
454 | |||
455 | 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 ;) | ||
456 | |||
457 | Here'a the list of all available filters with their expected return value: | ||
458 | |||
459 | Filters reference | ||
460 | +++++++++++++++++ | ||
461 | |||
462 | .. index:: screenshot | ||
463 | |||
464 | ``capture.target_filename`` | ||
465 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
466 | |||
467 | **Arguments:** ``args`` | ||
468 | |||
469 | **Return type:** ``String`` | ||
470 | |||
471 | Allows to alter the value of the filename where a screen capture should be stored. | ||
472 | |||
473 | ``echo.message`` | ||
474 | ~~~~~~~~~~~~~~~~ | ||
475 | |||
476 | **Arguments:** ``message`` | ||
477 | |||
478 | **Return type:** ``String`` | ||
479 | |||
480 | Allows to alter every message written onto stdout. | ||
481 | |||
482 | ``log.message`` | ||
483 | ~~~~~~~~~~~~~~~ | ||
484 | |||
485 | **Arguments:** ``message`` | ||
486 | |||
487 | **Return type:** ``String`` | ||
488 | |||
489 | Allows to alter every log message. | ||
490 | |||
491 | ``open.location`` | ||
492 | ~~~~~~~~~~~~~~~~~ | ||
493 | |||
494 | **Arguments:** ``args`` | ||
495 | |||
496 | **Return type:** ``String`` | ||
497 | |||
498 | Allows to alter every url before it being opened. | ||
499 | |||
500 | ``page.confirm`` | ||
501 | ~~~~~~~~~~~~~~~~ | ||
502 | |||
503 | **Arguments:** ``message`` | ||
504 | |||
505 | **Return type:** ``Boolean`` | ||
506 | |||
507 | .. versionadded:: 1.0 | ||
508 | |||
509 | Allows to react on a javascript ``confirm()`` call:: | ||
510 | |||
511 | casper.setFilter("page.confirm", function(msg) { | ||
512 | return msg === "Do you like vbscript?" ? false : true; | ||
513 | }); | ||
514 | |||
515 | ``page.prompt`` | ||
516 | ~~~~~~~~~~~~~~~ | ||
517 | |||
518 | **Arguments:** ``message, value`` | ||
519 | |||
520 | **Return type:** ``String`` | ||
521 | |||
522 | .. versionadded:: 1.0 | ||
523 | |||
524 | Allows to react on a javascript ``prompt()`` call:: | ||
525 | |||
526 | casper.setFilter("page.prompt", function(msg, value) { | ||
527 | if (msg === "What's your name?") { | ||
528 | return "Chuck"; | ||
529 | } | ||
530 | }); |
docs/extending.rst
0 → 100644
1 | .. _extending: | ||
2 | |||
3 | .. index:: extending, inheritance, prototype | ||
4 | |||
5 | ========= | ||
6 | Extending | ||
7 | ========= | ||
8 | |||
9 | 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:: | ||
10 | |||
11 | var casper = require('casper').create({ | ||
12 | verbose: true, | ||
13 | logLevel: "debug" | ||
14 | }); | ||
15 | |||
16 | var links = { | ||
17 | 'http://edition.cnn.com/': 0, | ||
18 | 'http://www.nytimes.com/': 0, | ||
19 | 'http://www.bbc.co.uk/': 0, | ||
20 | 'http://www.guardian.co.uk/': 0 | ||
21 | }; | ||
22 | |||
23 | casper.countLinks = function() { | ||
24 | return this.evaluate(function() { | ||
25 | return __utils__.findAll('a[href]').length; | ||
26 | }); | ||
27 | }; | ||
28 | |||
29 | casper.renderJSON = function(what) { | ||
30 | return this.echo(JSON.stringify(what, null, ' ')); | ||
31 | }; | ||
32 | |||
33 | casper.start(); | ||
34 | |||
35 | casper.each(Object.keys(links), function(casper, link) { | ||
36 | this.thenOpen(link, function() { | ||
37 | links[link] = this.countLinks(); | ||
38 | }); | ||
39 | }); | ||
40 | |||
41 | casper.run(function() { | ||
42 | this.renderJSON(links).exit(); | ||
43 | }); | ||
44 | |||
45 | 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:: | ||
46 | |||
47 | var Casper = require('casper').Casper; | ||
48 | var utils = require('utils'); | ||
49 | var links = { | ||
50 | 'http://edition.cnn.com/': 0, | ||
51 | 'http://www.nytimes.com/': 0, | ||
52 | 'http://www.bbc.co.uk/': 0, | ||
53 | 'http://www.guardian.co.uk/': 0 | ||
54 | }; | ||
55 | |||
56 | function Fantomas() { | ||
57 | Fantomas.super_.apply(this, arguments); | ||
58 | } | ||
59 | |||
60 | // Let's make our Fantomas class extending the Casper one | ||
61 | // please note that at this point, CHILD CLASS PROTOTYPE WILL BE OVERRIDEN | ||
62 | utils.inherits(Fantomas, Casper); | ||
63 | |||
64 | Fantomas.prototype.countLinks = function() { | ||
65 | return this.evaluate(function() { | ||
66 | return __utils__.findAll('a[href]').length; | ||
67 | }); | ||
68 | }; | ||
69 | |||
70 | Fantomas.prototype.renderJSON = function(what) { | ||
71 | return this.echo(JSON.stringify(what, null, ' ')); | ||
72 | }; | ||
73 | |||
74 | var fantomas = new Fantomas({ | ||
75 | verbose: true, | ||
76 | logLevel: "debug" | ||
77 | }); | ||
78 | |||
79 | fantomas.start(); | ||
80 | |||
81 | Object.keys(links).forEach(function(url) { | ||
82 | fantomas.thenOpen(url, function() { | ||
83 | links[url] = this.countLinks(); | ||
84 | }); | ||
85 | }); | ||
86 | |||
87 | fantomas.run(function() { | ||
88 | this.renderJSON(links).exit(); | ||
89 | }); | ||
90 | |||
91 | .. note:: | ||
92 | |||
93 | 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. | ||
94 | |||
95 | **Don't forget to call ``Casper``'s parent constructor!** | ||
96 | |||
97 | 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. | ||
98 | |||
99 | |||
100 | .. index:: coffeescript | ||
101 | |||
102 | Using CoffeeScript | ||
103 | ~~~~~~~~~~~~~~~~~~ | ||
104 | |||
105 | If you're writing your casper scripts using `CoffeeScript <http://coffeescript.org/>`_, extending casper is getting a bit more straightforward: | ||
106 | |||
107 | .. code-block:: coffeescript | ||
108 | |||
109 | links = | ||
110 | 'http://edition.cnn.com/': 0 | ||
111 | 'http://www.nytimes.com/': 0 | ||
112 | 'http://www.bbc.co.uk/': 0 | ||
113 | 'http://www.guardian.co.uk/': 0 | ||
114 | |||
115 | class Fantomas extends require('casper').Casper | ||
116 | countLinks: -> | ||
117 | @evaluate -> | ||
118 | __utils__.findAll('a').length | ||
119 | |||
120 | renderJSON: (what) -> | ||
121 | @echo JSON.stringify what, null, ' ' | ||
122 | |||
123 | fantomas = new Fantomas | ||
124 | loadImages: false | ||
125 | logLevel: "debug" | ||
126 | verbose: true | ||
127 | |||
128 | fantomas.start() | ||
129 | |||
130 | for url of links | ||
131 | do (url) -> | ||
132 | fantomas.thenOpen url, -> | ||
133 | links[url] = @countLinks() | ||
134 | |||
135 | fantomas.run -> | ||
136 | @renderJSON links | ||
137 | @exit() | ||
138 |
docs/faq.rst
0 → 100644
1 | .. _faq: | ||
2 | |||
3 | .. index:: FAQ, Help | ||
4 | |||
5 | === | ||
6 | FAQ | ||
7 | === | ||
8 | |||
9 | .. contents:: Here's a selection of the most frequently asked questions by CasperJS newcomers: | ||
10 | :local: | ||
11 | :backlinks: top | ||
12 | |||
13 | .. index:: Node.js | ||
14 | |||
15 | Is CasperJS a `node.js <http://nodejs.org/>`_ library? | ||
16 | ------------------------------------------------------ | ||
17 | |||
18 | **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. | ||
19 | |||
20 | .. hint:: If you want to drive CasperJS from node, try `SpookyJS <https://github.com/WaterfallEngineering/SpookyJS>`_. | ||
21 | |||
22 | |||
23 | .. index:: Bugs, Contributing, error | ||
24 | |||
25 | I'm stuck! I think there's a bug! What can I do? | ||
26 | ------------------------------------------------ | ||
27 | |||
28 | Before rage-tweeting: | ||
29 | |||
30 | 1. Read the `docs <http://casperjs.org/>`_ | ||
31 | 2. Check if an `issue <https://github.com/n1k0/casperjs/issues>`_ has been open about your problem already | ||
32 | 3. Check you're running the `latest stable tag <https://github.com/n1k0/casperjs/tags>`_ | ||
33 | 4. Check you're running the `latest version <http://code.google.com/p/phantomjs/downloads/list>`_ of PhantomJS_ | ||
34 | 5. Ask on the `project mailing list <https://groups.google.com/forum/#!forum/casperjs>`_: | ||
35 | |||
36 | a. try to post a reproducible, minimal test case | ||
37 | b. compare casperjs results with native phantomjs ones | ||
38 | c. if the problem also occurs with native phantomjs, ask on `phantomjs mailing list <https://groups.google.com/forum/#!forum/phantomjs>`_ | ||
39 | |||
40 | 6. Eventually, `file an issue <https://github.com/n1k0/casperjs/issues/new>`_. | ||
41 | |||
42 | |||
43 | .. index:: Testing | ||
44 | |||
45 | The ``casper.test`` property is undefined, I can't write any test! | ||
46 | ------------------------------------------------------------------ | ||
47 | |||
48 | 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. | ||
49 | |||
50 | You may want to read the :doc:`testing documentation <testing>` for more information. | ||
51 | |||
52 | |||
53 | .. index:: Code reuse | ||
54 | |||
55 | I keep copy and pasting stuff in my test scripts, that's boring | ||
56 | --------------------------------------------------------------- | ||
57 | |||
58 | Have a look at `this gist <https://gist.github.com/3813361>`_, it might help. | ||
59 | |||
60 | Also, don't forget that CasperJS supports a `CommonJS-compliant module pattern <http://wiki.commonjs.org/wiki/Modules/1.1>`_ implementation. | ||
61 | |||
62 | .. note:: | ||
63 | |||
64 | CasperJS' implementation of ``require()`` differs a bit from the one provided by PhantomJS_, but I personnaly never really encountered any functional difference. | ||
65 | |||
66 | |||
67 | .. index:: Versionning | ||
68 | |||
69 | What is the versioning policy of CasperJS? | ||
70 | ------------------------------------------ | ||
71 | |||
72 | Releases will follow the `SemVer standard <http://semver.org/>`_; they | ||
73 | will be numbered with the follow format: | ||
74 | |||
75 | .. code-block:: text | ||
76 | |||
77 | <major>.<minor>.<patch>[-<identifier>] | ||
78 | |||
79 | And constructed with the following guidelines: | ||
80 | |||
81 | - Breaking backwards compatibility bumps the major | ||
82 | - New additions without breaking backwards compatibility bumps the minor | ||
83 | - Bug fixes and misc changes bump the patch | ||
84 | - Unstable, special and trunk versions will have a proper identifier | ||
85 | |||
86 | |||
87 | .. index:: jQuery | ||
88 | |||
89 | Can I use jQuery with CasperJS? | ||
90 | ------------------------------- | ||
91 | |||
92 | Sure, you can use `jQuery <http://jquery.com/>`_, as every single other javascript library on Earth. | ||
93 | |||
94 | A first solution is to inject it into the remote DOM environment by hand using the standard ``WebPage.injectJs()`` method:: | ||
95 | |||
96 | casper.page.injectJs('/path/to/jquery.js'); | ||
97 | |||
98 | 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:: | ||
99 | |||
100 | var casper = require('casper').create({ | ||
101 | clientScripts: ["includes/jquery.min.js"] | ||
102 | }); | ||
103 | |||
104 | .. note:: | ||
105 | |||
106 | You can't *inject* scripts using the HTTP protocol, you actually have to use a relative/absolute filesystem path to the script resource. | ||
107 | |||
108 | |||
109 | .. index:: Windows, Python, Ruby | ||
110 | |||
111 | Can I use CasperJS without using the ``casperjs`` executable? | ||
112 | ------------------------------------------------------------- | ||
113 | |||
114 | Yes, you can call a CasperJS script directly with the ``phantomjs`` | ||
115 | executable, but if you do so, you must set the ``phantom.casperPath`` | ||
116 | property to the path where the library root is located on your system:: | ||
117 | |||
118 | // casperscript.js | ||
119 | phantom.casperPath = '/path/to/casperjs'; | ||
120 | phantom.injectJs(phantom.casperPath + '/bin/bootstrap.js'); | ||
121 | |||
122 | var casper = require('casper').create(); | ||
123 | // ... | ||
124 | |||
125 | You can run such a script like any other standard PhantomJS_ script:: | ||
126 | |||
127 | $ phantomjs casperscript.js | ||
128 | |||
129 | **If you're on Windows**, this is the way you may manage to get casper | ||
130 | working the most easily:: | ||
131 | |||
132 | phantom.casperPath = 'C:\\path\\to\\your\\repo\\lib\\casperjs-0.6.X'; | ||
133 | phantom.injectJs(phantom.casperPath + '\\bin\\bootstrap.js'); | ||
134 | |||
135 | var casper = require('casper').create(); | ||
136 | |||
137 | // do stuff | ||
138 | |||
139 | |||
140 | .. index:: HTTP | ||
141 | |||
142 | How can I catch HTTP 404 and other status codes? | ||
143 | ------------------------------------------------ | ||
144 | |||
145 | You can define your own `HTTP status | ||
146 | code <http://en.wikipedia.org/wiki/List_of_HTTP_status_codes>`_ handlers | ||
147 | by using the ``httpStatusHandlers`` option of the Casper object. You can | ||
148 | also catch other HTTP status codes as well, as demoed below:: | ||
149 | |||
150 | var casper = require('casper').create(); | ||
151 | |||
152 | casper.on('http.status.404', function(resource) { | ||
153 | this.echo('wait, this url is 404: ' + resource.url); | ||
154 | }); | ||
155 | |||
156 | casper.on('http.status.500', function(resource) { | ||
157 | this.echo('woops, 500 error: ' + resource.url); | ||
158 | }); | ||
159 | |||
160 | casper.start('http://mywebsite/404', function() { | ||
161 | this.echo('We suppose this url return an HTTP 404'); | ||
162 | }); | ||
163 | |||
164 | casper.thenOpen('http://mywebsite/500', function() { | ||
165 | this.echo('We suppose this url return an HTTP 500'); | ||
166 | }); | ||
167 | |||
168 | casper.run(function() { | ||
169 | this.echo('Done.').exit(); | ||
170 | }); | ||
171 | |||
172 | .. hint:: | ||
173 | |||
174 | Check out all the other cool :doc:`events <events-filters>` you may use as well. | ||
175 | |||
176 | |||
177 | .. index:: log, Logging | ||
178 | |||
179 | Where does CasperJS write its logfile? | ||
180 | -------------------------------------- | ||
181 | |||
182 | Nowhere. CasperJS doesn't write logs on the filesystem. You have to implement this by yourself if needed. | ||
183 | |||
184 | |||
185 | .. index:: __utils__, AJAX | ||
186 | |||
187 | What's this mysterious ``__utils__`` object? | ||
188 | -------------------------------------------- | ||
189 | |||
190 | 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. | ||
191 | |||
192 | So everytime to perform an :ref:`evaluate() <casper_evaluate>` call, you have this instance available to perform common operation like: | ||
193 | |||
194 | - fetching nodes using CSS3 or XPath selectors, | ||
195 | - retrieving information about element properties (attributes, size, bounds, etc.), | ||
196 | - sending AJAX requests, | ||
197 | - triggering DOM events | ||
198 | |||
199 | 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! | ||
200 | |||
201 | .. note:: | ||
202 | |||
203 | 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. | ||
204 | |||
205 | |||
206 | .. index:: Step stack, Asynchronicity | ||
207 | |||
208 | How does ``then()`` and the step stack work? | ||
209 | -------------------------------------------- | ||
210 | |||
211 | Disclaimer This entry is based on an `answer I made on Stack Overflow <http://stackoverflow.com/a/11957919/330911>`_. | ||
212 | |||
213 | The ``then()`` method basically adds a new navigation step in a stack. A step is a javascript function which can do two different things: | ||
214 | |||
215 | 1. waiting for the previous step - if any - being executed | ||
216 | 2. waiting for a requested url and related page to load | ||
217 | |||
218 | Let's take a simple navigation scenario:: | ||
219 | |||
220 | var casper = require('casper').create(); | ||
221 | |||
222 | casper.start(); | ||
223 | |||
224 | casper.then(function step1() { | ||
225 | this.echo('this is step one'); | ||
226 | }); | ||
227 | |||
228 | casper.then(function step2() { | ||
229 | this.echo('this is step two'); | ||
230 | }); | ||
231 | |||
232 | casper.thenOpen('http://google.com/', function step3() { | ||
233 | this.echo('this is step 3 (google.com is loaded)'); | ||
234 | }); | ||
235 | |||
236 | You can print out all the created steps within the stack like this:: | ||
237 | |||
238 | require('utils').dump(casper.steps.map(function(step) { | ||
239 | return step.toString(); | ||
240 | })); | ||
241 | |||
242 | That gives:: | ||
243 | |||
244 | $ casperjs test-steps.js | ||
245 | [ | ||
246 | "function step1() { this.echo('this is step one'); }", | ||
247 | "function step2() { this.echo('this is step two'); }", | ||
248 | "function _step() { this.open(location, settings); }", | ||
249 | "function step3() { this.echo('this is step 3 (google.com is loaded)'); }" | ||
250 | ] | ||
251 | |||
252 | 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. | ||
253 | |||
254 | When you have defined your navigation steps, ``run()`` executes them one by one sequentially:: | ||
255 | |||
256 | casper.run(); | ||
257 | |||
258 | .. note:: The callback/listener stuff is an implementation of the `Promise pattern <http://blog.thepete.net/blog/2011/07/02/javascript-promises/>`_. | ||
259 | |||
260 | |||
261 | Is it possible to achieve parallel browsing using CasperJS? | ||
262 | ----------------------------------------------------------- | ||
263 | |||
264 | `Officially no <https://groups.google.com/d/topic/casperjs/Scx4Cjqp7hE/discussion>`_, but you may want to try. | ||
265 | |||
266 | |||
267 | Can I access & manipulate DOM elements directly from the CasperJS environment? | ||
268 | ------------------------------------------------------------------------------ | ||
269 | |||
270 | No. Like in PhantomJS, you have to use :ref:`Casper#evaluate() <casper_evaluate>` to access actual page DOM and manipulate elements. | ||
271 | |||
272 | For example, you **can't** do this:: | ||
273 | |||
274 | // this won't work | ||
275 | casper.then(function() { | ||
276 | var titleNode = document.querySelector('h1'); | ||
277 | this.echo('Title is: ' + titleNode.textContent); | ||
278 | titleNode.textContent = 'New title'; | ||
279 | this.echo('Title is now: ' + titleNode.textContent); | ||
280 | }); | ||
281 | |||
282 | You have to use the :ref:`Casper#evaluate() <casper_evaluate>` method in order to communicate with the page DOM:: | ||
283 | |||
284 | // this will | ||
285 | casper.then(function() { | ||
286 | var titleText = this.evaluate(function() { | ||
287 | return document.querySelector('h1').textContent; | ||
288 | }); | ||
289 | this.echo('Title is: ' + titleText); | ||
290 | this.evaluate(function() { | ||
291 | document.querySelector('h1').textContent = 'New title'; | ||
292 | }); | ||
293 | this.echo('Title is now: ' + this.evaluate(function() { | ||
294 | return document.querySelector('h1').textContent; | ||
295 | })); | ||
296 | }); | ||
297 | |||
298 | 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>`:: | ||
299 | |||
300 | // this will | ||
301 | casper.then(function() { | ||
302 | this.echo('Title is: ' + this.fetchText('h1')); | ||
303 | this.evaluate(function() { | ||
304 | document.querySelector('h1').textContent = 'New title'; | ||
305 | }); | ||
306 | this.echo('Element HTML is now: ' + this.getElementInfo('h1').html); | ||
307 | }); | ||
308 | |||
309 | .. _faq_javascript: | ||
310 | |||
311 | Okay, honestly, I'm stuck with Javascript. | ||
312 | ------------------------------------------ | ||
313 | |||
314 | 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. | ||
315 | |||
316 | Here are some great resources to get started efficiently with the language: | ||
317 | |||
318 | - Learn and practice Javascript online at `Code Academy <http://www.codecademy.com/tracks/javascript>`_ | ||
319 | - `Eloquent Javascript <http://eloquentjavascript.net/contents.html>`_ | ||
320 | - `JavaScript Enlightenment <http://www.javascriptenlightenment.com/JavaScript_Enlightenment.pdf>`_ (PDF) | ||
321 | - 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. | ||
322 | |||
323 | .. _PhantomJS: http://phantomjs.org/ | ||
324 | .. _Qt: http://qt.digia.com/ | ||
325 | .. _WebKit: http://www.webkit.org/ |
docs/index.rst
0 → 100644
1 | ====================== | ||
2 | CasperJS documentation | ||
3 | ====================== | ||
4 | |||
5 | CasperJS_ is a navigation scripting & testing utility for PhantomJS_, written in Javascript. | ||
6 | |||
7 | .. figure:: _static/images/casperjs-logo.png | ||
8 | :align: right | ||
9 | |||
10 | .. toctree:: | ||
11 | :maxdepth: 2 | ||
12 | |||
13 | installation | ||
14 | quickstart | ||
15 | cli | ||
16 | selectors | ||
17 | testing | ||
18 | modules/index | ||
19 | writing_modules | ||
20 | events-filters | ||
21 | logging | ||
22 | extending | ||
23 | debugging | ||
24 | faq | ||
25 | changelog | ||
26 | upgrading/index | ||
27 | credits | ||
28 | license | ||
29 | |||
30 | You can also search the :ref:`genindex` if you're looking for something particular. | ||
31 | |||
32 | .. index:: Community, Contributing, Help, Support | ||
33 | |||
34 | Community | ||
35 | --------- | ||
36 | |||
37 | - `get the code <https://github.com/n1k0/casperjs>`_ and `contribute <https://github.com/n1k0/casperjs/blob/master/CONTRIBUTING.md#contribution-guide>`_ | ||
38 | - join the `mailing list <https://groups.google.com/forum/#!forum/casperjs>`_ | ||
39 | - check out `the ecosystem <https://github.com/casperjs>`_ | ||
40 | - follow `@casperjs\_org <https://twitter.com/casperjs_org>`_ on Twitter | ||
41 | - there's also a `Google+ account <https://plus.google.com/106641872690063476159>`_ (not much updated though) | ||
42 | |||
43 | |||
44 | .. _CasperJS: http://casperjs.org/ | ||
45 | .. _PhantomJS: http://phantomjs.org/ |
docs/installation.rst
0 → 100644
1 | .. _installation: | ||
2 | .. index:: Installation | ||
3 | |||
4 | ============ | ||
5 | Installation | ||
6 | ============ | ||
7 | |||
8 | CasperJS can be installed on most Linuxes, OSX and Windows. | ||
9 | |||
10 | Prerequisites | ||
11 | ------------- | ||
12 | |||
13 | .. index:: PhantomJS, Python | ||
14 | |||
15 | - PhantomJS_ 1.8.1 or greater. Installation instructions can be found `here <http://phantomjs.org/download.html>`_ | ||
16 | - Python_ 2.6 or greater | ||
17 | |||
18 | .. note:: | ||
19 | |||
20 | .. versionadded:: 1.0 | ||
21 | |||
22 | 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: | ||
23 | |||
24 | .. code-block:: text | ||
25 | |||
26 | $ ln -sf `pwd`/rubybin/casperjs /usr/local/bin/casperjs | ||
27 | |||
28 | Or using the ruby interpreter: | ||
29 | |||
30 | .. code-block:: text | ||
31 | |||
32 | $ ruby /path/to/casperjs/rubybin/casperjs | ||
33 | CasperJS version 1.1-DEV at /path/to/casperjs/rubybin/casperjs, using PhantomJS version 1.7.0 | ||
34 | ... | ||
35 | |||
36 | .. index:: Homebrew | ||
37 | |||
38 | Installing from Homebrew (OSX) | ||
39 | ------------------------------ | ||
40 | |||
41 | Installation of both PhantomJS and CasperJS can be achieved through `Homebrew <http://mxcl.github.com/homebrew/>`_:: | ||
42 | |||
43 | $ brew install casperjs | ||
44 | |||
45 | .. index:: git | ||
46 | |||
47 | Installing from git | ||
48 | ------------------- | ||
49 | |||
50 | Installation can be achieved using `git <http://git-scm.com/>`_. The code is mainly hosted on `Github <https://github.com/n1k0/casperjs>`_. | ||
51 | |||
52 | From a stable tag | ||
53 | ~~~~~~~~~~~~~~~~~ | ||
54 | |||
55 | .. code-block:: text | ||
56 | |||
57 | $ git clone git://github.com/n1k0/casperjs.git | ||
58 | $ cd casperjs | ||
59 | $ git checkout tags/1.0 | ||
60 | $ ln -sf `pwd`/bin/casperjs /usr/local/bin/casperjs | ||
61 | |||
62 | Once PhantomJS and CasperJS installed on your machine, you should obtain something like this: | ||
63 | |||
64 | .. code-block:: text | ||
65 | |||
66 | $ phantomjs --version | ||
67 | 1.7 | ||
68 | $ casperjs --version | ||
69 | 1.0 | ||
70 | |||
71 | From the master branch | ||
72 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
73 | |||
74 | The ``master`` branch hosts the current development version of CasperJS. | ||
75 | |||
76 | .. code-block:: text | ||
77 | |||
78 | $ git clone git://github.com/n1k0/casperjs.git | ||
79 | $ cd casperjs | ||
80 | $ git checkout master | ||
81 | $ ln -sf `pwd`/bin/casperjs /usr/local/bin/casperjs | ||
82 | |||
83 | To check your current installed version: | ||
84 | |||
85 | .. code-block:: text | ||
86 | |||
87 | $ casperjs --version | ||
88 | 1.1-DEV | ||
89 | |||
90 | You are now ready to write your :doc:`first script <quickstart>`! | ||
91 | |||
92 | |||
93 | Installing from an archive | ||
94 | -------------------------- | ||
95 | |||
96 | You can download tagged archives of CasperJS code: | ||
97 | |||
98 | **Latest stable version:** | ||
99 | |||
100 | - https://github.com/n1k0/casperjs/zipball/1.0.0 (zip) | ||
101 | - https://github.com/n1k0/casperjs/tarball/1.0.0 (tar.gz) | ||
102 | |||
103 | **Latest development version (master branch):** | ||
104 | |||
105 | - https://github.com/n1k0/casperjs/zipball/master (zip) | ||
106 | - https://github.com/n1k0/casperjs/tarball/master (tar.gz) | ||
107 | |||
108 | Operations are then the same as with a git checkout. | ||
109 | |||
110 | |||
111 | .. index:: Windows | ||
112 | |||
113 | CasperJS on Windows | ||
114 | ------------------- | ||
115 | |||
116 | Phantomjs installation additions | ||
117 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
118 | |||
119 | - Append ``";C:\phantomjs"`` to your ``PATH`` environment variable. | ||
120 | - Modify this path appropriately if you installed PhantomJS to a different location. | ||
121 | |||
122 | Casperjs installation additions | ||
123 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
124 | |||
125 | .. versionadded:: 1.0 | ||
126 | |||
127 | CasperJS, as of 1.0.0-RC3, ships with a Batch script so you don't need Python nor Ruby to use it. | ||
128 | |||
129 | - Append ``";C:\casperjs\batchbin"`` to your ``PATH`` environment variable. | ||
130 | - Modify this path appropriately if you installed CasperJS to a different location. | ||
131 | |||
132 | You can now run any regular casper scripts that way: | ||
133 | |||
134 | .. code-block:: text | ||
135 | |||
136 | C:> casperjs.bat myscript.js | ||
137 | |||
138 | Earlier versions of CasperJS | ||
139 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
140 | |||
141 | Before 1.0.0-RC3, you had to setup your casper scripts that way:: | ||
142 | |||
143 | phantom.casperPath = 'C:\\casperjs-1.1'; | ||
144 | phantom.injectJs(phantom.casperPath + '\\bin\\bootstrap.js'); | ||
145 | |||
146 | var casper = require('casper').create(); | ||
147 | |||
148 | // do stuff | ||
149 | |||
150 | Run the script using the ``phantom.exe`` program: | ||
151 | |||
152 | .. code-block:: text | ||
153 | |||
154 | C:> phantomjs.exe myscript.js | ||
155 | |||
156 | .. note:: | ||
157 | |||
158 | There is no output coloration when running CasperJS on Microsoft platforms. | ||
159 | |||
160 | |||
161 | .. index:: Bugs, REPL | ||
162 | |||
163 | Known Bugs & Limitations | ||
164 | ------------------------ | ||
165 | |||
166 | - Due to its asynchronous nature, CasperJS doesn't work well with `PhantomJS' REPL <http://code.google.com/p/phantomjs/wiki/InteractiveModeREPL>`_. | ||
167 | |||
168 | .. _PhantomJS: http://phantomjs.org/ | ||
169 | .. _Python: http://python.org/ |
docs/license.rst
0 → 100644
1 | .. _license: | ||
2 | |||
3 | .. index:: Licensing | ||
4 | |||
5 | ======= | ||
6 | License | ||
7 | ======= | ||
8 | |||
9 | `CasperJS <http://casperjs.org>`_ is released under the terms of the | ||
10 | `MIT license <http://en.wikipedia.org/wiki/MIT_License>`_. | ||
11 | |||
12 | :: | ||
13 | |||
14 | Copyright (c) 2011-{{year}} Nicolas Perriault | ||
15 | Permission is hereby granted, free of charge, to any person obtaining a | ||
16 | copy of this software and associated documentation files (the "Software"), | ||
17 | to deal in the Software without restriction, including without limitation | ||
18 | the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
19 | and/or sell copies of the Software, and to permit persons to whom the | ||
20 | Software is furnished to do so, subject to the following conditions: | ||
21 | The above copyright notice and this permission notice shall be included | ||
22 | in all copies or substantial portions of the Software. | ||
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
24 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
26 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
29 | DEALINGS IN THE SOFTWARE. |
docs/logging.rst
0 → 100644
1 | .. _logging: | ||
2 | |||
3 | .. index:: Logging, log levels | ||
4 | |||
5 | ======= | ||
6 | Logging | ||
7 | ======= | ||
8 | |||
9 | CasperJS allows logging using the :ref:`casper.log() <casper_log>` method and these standard event levels: | ||
10 | |||
11 | - ``debug`` | ||
12 | - ``info`` | ||
13 | - ``warning`` | ||
14 | - ``error`` | ||
15 | |||
16 | Sample use:: | ||
17 | |||
18 | var casper = require('casper').create(); | ||
19 | casper.log('plop', 'debug'); | ||
20 | casper.log('plip', 'warning'); | ||
21 | |||
22 | .. index:: verbose | ||
23 | |||
24 | 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:: | ||
25 | |||
26 | var casper = require('casper').create({ | ||
27 | verbose: true | ||
28 | }); | ||
29 | |||
30 | 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:: | ||
31 | |||
32 | var casper = require('casper').create({ | ||
33 | verbose: true, | ||
34 | logLevel: 'debug' | ||
35 | }); | ||
36 | |||
37 | You can also dump a JSON log of your Casper suite just by rendering the contents of the ``Casper.logs`` property:: | ||
38 | |||
39 | var casper = require('casper').create({ | ||
40 | // ... | ||
41 | casper.run(function() { | ||
42 | require('utils').dump(this.logs); | ||
43 | this.exit(); | ||
44 | }); | ||
45 | |||
46 | Last, if you print log messages to the standard output using the ``verbose`` option, you'll get some fancy colors:: | ||
47 | |||
48 | var casper = require('casper').create({ | ||
49 | verbose: true, | ||
50 | logLevel: 'debug' | ||
51 | }) | ||
52 | casper.log('this is a debug message', 'debug'); | ||
53 | casper.log('and an informative one', 'info'); | ||
54 | casper.log('and a warning', 'warning'); | ||
55 | casper.log('and an error', 'error'); | ||
56 | casper.exit(); | ||
57 | |||
58 | This will give the following output: | ||
59 | |||
60 | .. figure:: _static/images/logoutput.png | ||
61 | :align: center | ||
62 | :alt: image | ||
63 | |||
64 | image | ||
65 | |||
66 | |||
67 | .. hint:: | ||
68 | |||
69 | CasperJS doesn't write logs on the filesystem. You have to implement this by yourself if needed. |
docs/modules/casper.rst
0 → 100644
1 | .. _casper_module: | ||
2 | |||
3 | ===================== | ||
4 | The ``casper`` module | ||
5 | ===================== | ||
6 | |||
7 | .. index:: Casper | ||
8 | |||
9 | The ``Casper`` class | ||
10 | ++++++++++++++++++++ | ||
11 | |||
12 | The easiest way to get a casper instance is to use the module's ``create()`` method:: | ||
13 | |||
14 | var casper = require('casper').create(); | ||
15 | |||
16 | But you can also retrieve the main Function and instantiate it by yourself:: | ||
17 | |||
18 | var casper = new require('casper').Casper(); | ||
19 | |||
20 | .. hint:: | ||
21 | |||
22 | Also, check out :doc:`how to extend Casper with your own methods <../extending>`. | ||
23 | |||
24 | Both the ``Casper`` constructor and the ``create()`` function accept a single ``options`` argument which is a standard javascript object:: | ||
25 | |||
26 | var casper = require('casper').create({ | ||
27 | verbose: true, | ||
28 | logLevel: "debug" | ||
29 | }); | ||
30 | |||
31 | .. _casper_options: | ||
32 | |||
33 | .. index:: Casper options, options | ||
34 | |||
35 | ``Casper.options`` | ||
36 | ++++++++++++++++++ | ||
37 | |||
38 | An ``options`` object can be passed to the ``Casper`` constructor, eg.:: | ||
39 | |||
40 | var casper = require('casper').create({ | ||
41 | clientScripts: [ | ||
42 | 'includes/jquery.js', // These two scripts will be injected in remote | ||
43 | 'includes/underscore.js' // DOM on every request | ||
44 | ], | ||
45 | pageSettings: { | ||
46 | loadImages: false, // The WebPage instance used by Casper will | ||
47 | loadPlugins: false // use these settings | ||
48 | }, | ||
49 | logLevel: "info", // Only "info" level messages will be logged | ||
50 | verbose: true // log messages will be printed out to the console | ||
51 | }); | ||
52 | |||
53 | You can also alter options at runtime:: | ||
54 | |||
55 | var casper = require('casper').create(); | ||
56 | casper.options.waitTimeout = 1000; | ||
57 | |||
58 | The whole list of available options is detailed below. | ||
59 | |||
60 | .. index:: Client scripts | ||
61 | |||
62 | .. _casper_option_clientscripts: | ||
63 | |||
64 | ``clientScripts`` | ||
65 | ------------------------------------------------------------------------------- | ||
66 | |||
67 | **Type:** ``Array`` | ||
68 | |||
69 | **Default:** ``[]`` | ||
70 | |||
71 | A collection of script filepaths to include in every page loaded | ||
72 | |||
73 | .. index:: exit, error | ||
74 | |||
75 | ``exitOnError`` | ||
76 | ------------------------------------------------------------------------------- | ||
77 | |||
78 | **Type:** ``Boolean`` | ||
79 | |||
80 | **Default:** ``true`` | ||
81 | |||
82 | Sets if CasperJS must exit when an uncaught error has been thrown by the script. | ||
83 | |||
84 | .. index:: HTTP | ||
85 | |||
86 | ``httpStatusHandlers`` | ||
87 | ------------------------------------------------------------------------------- | ||
88 | |||
89 | **Type:** ``Object`` | ||
90 | |||
91 | **Default:** ``{}`` | ||
92 | |||
93 | 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. | ||
94 | |||
95 | .. index:: Logging | ||
96 | |||
97 | ``logLevel`` | ||
98 | ------------------------------------------------------------------------------- | ||
99 | |||
100 | **Type:** ``String`` | ||
101 | |||
102 | **Default:** ``"error"`` | ||
103 | |||
104 | Logging level (see the logging section for more information) | ||
105 | |||
106 | ``onAlert`` | ||
107 | ------------------------------------------------------------------------------- | ||
108 | |||
109 | **Type:** ``Function`` | ||
110 | |||
111 | **Default:** ``null`` | ||
112 | |||
113 | A function to be called when a javascript alert() is triggered | ||
114 | |||
115 | ``onDie`` | ||
116 | ------------------------------------------------------------------------------- | ||
117 | |||
118 | **Type:** ``Function`` | ||
119 | |||
120 | **Default:** ``null`` | ||
121 | |||
122 | A function to be called when Casper#die() is called | ||
123 | |||
124 | .. index:: error, Error handling | ||
125 | |||
126 | ``onError`` | ||
127 | ------------------------------------------------------------------------------- | ||
128 | |||
129 | **Type:** ``Function`` | ||
130 | |||
131 | **Default:** ``null`` | ||
132 | |||
133 | A function to be called when an "error" level event occurs | ||
134 | |||
135 | .. index:: error, Error handling | ||
136 | |||
137 | ``onLoadError`` | ||
138 | ------------------------------------------------------------------------------- | ||
139 | |||
140 | **Type:** ``Function`` | ||
141 | |||
142 | **Default:** ``null`` | ||
143 | |||
144 | A function to be called when a requested resource cannot be loaded | ||
145 | |||
146 | ``onPageInitialized`` | ||
147 | ------------------------------------------------------------------------------- | ||
148 | |||
149 | **Type:** ``Function`` | ||
150 | |||
151 | **Default:** ``null`` | ||
152 | |||
153 | A function to be called after ``WebPage`` instance has been initialized | ||
154 | |||
155 | .. index:: HTTP | ||
156 | |||
157 | ``onResourceReceived`` | ||
158 | ------------------------------------------------------------------------------- | ||
159 | |||
160 | **Type:** ``Function`` | ||
161 | |||
162 | **Default:** ``null`` | ||
163 | |||
164 | Proxy method for PhantomJS' ``WebPage#onResourceReceived()`` callback, but the current Casper instance is passed as first argument. | ||
165 | |||
166 | .. index:: HTTP | ||
167 | |||
168 | ``onResourceRequested`` | ||
169 | ------------------------------------------------------------------------------- | ||
170 | |||
171 | **Type:** ``Function`` | ||
172 | |||
173 | **Default:** ``null`` | ||
174 | |||
175 | Proxy method for PhantomJS' WebPage#onResourceRequested() callback, but the current Casper instance is passed as first argument. | ||
176 | |||
177 | .. index:: Step stack | ||
178 | |||
179 | ``onStepComplete`` | ||
180 | ------------------------------------------------------------------------------- | ||
181 | |||
182 | **Type:** ``Function`` | ||
183 | |||
184 | **Default:** ``null`` | ||
185 | |||
186 | A function to be executed when a step function execution is finished. | ||
187 | |||
188 | .. index:: Step stack, Error handling, timeout | ||
189 | |||
190 | ``onStepTimeout`` | ||
191 | ------------------------------------------------------------------------------- | ||
192 | |||
193 | **Type:** ``Function`` | ||
194 | |||
195 | **Default:** ``Function`` | ||
196 | |||
197 | A function to be executed when a step function execution time exceeds the value of the stepTimeout option, if any has been set. | ||
198 | |||
199 | 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. | ||
200 | |||
201 | .. index:: Error handling, timeout | ||
202 | |||
203 | ``onTimeout`` | ||
204 | ------------------------------------------------------------------------------- | ||
205 | |||
206 | **Type:** ``Function`` | ||
207 | |||
208 | **Default:** ``Function`` | ||
209 | |||
210 | A function to be executed when script execution time exceeds the value of the timeout option, if any has been set. | ||
211 | |||
212 | 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. | ||
213 | |||
214 | .. index:: Error handling, timeout | ||
215 | |||
216 | ``onWaitTimeout`` | ||
217 | ------------------------------------------------------------------------------- | ||
218 | |||
219 | **Type:** ``Function`` | ||
220 | |||
221 | **Default:** ``Function`` | ||
222 | |||
223 | A function to be executed when a ``waitFor*`` function execution time exceeds the value of the waitTimeout option, if any has been set. | ||
224 | |||
225 | 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. | ||
226 | |||
227 | ``page`` | ||
228 | ------------------------------------------------------------------------------- | ||
229 | |||
230 | **Type:** ``WebPage`` | ||
231 | |||
232 | **Default:** ``null`` | ||
233 | |||
234 | An existing PhantomJS ``WebPage`` instance | ||
235 | |||
236 | .. index:: settings, PhantomJS, SSL, auth, XSS | ||
237 | |||
238 | ``pageSettings`` | ||
239 | ------------------------------------------------------------------------------- | ||
240 | |||
241 | **Type:** ``Object`` | ||
242 | |||
243 | **Default:** ``{}`` | ||
244 | |||
245 | PhantomJS's WebPage settings object. Available settings are: | ||
246 | |||
247 | - ``javascriptEnabled`` defines whether to execute the script in the page or not (default to ``true``) | ||
248 | - ``loadImages`` defines whether to load the inlined images or not | ||
249 | - ``loadPlugins`` defines whether to load NPAPI plugins (Flash, Silverlight, …) or not | ||
250 | - ``localToRemoteUrlAccessEnabled`` defines whether local resource (e.g. from file) can access remote URLs or not (default to ``false``) | ||
251 | - ``userAgent`` defines the user agent sent to server when the web page requests resources | ||
252 | - ``userName`` sets the user name used for HTTP authentication | ||
253 | - ``password`` sets the password used for HTTP authentication | ||
254 | - ``XSSAuditingEnabled`` defines whether load requests should be monitored for cross-site scripting attempts (default to ``false``) | ||
255 | |||
256 | .. index:: Remote scripts | ||
257 | |||
258 | ``remoteScripts`` | ||
259 | ------------------------------------------------------------------------------- | ||
260 | |||
261 | **Type:** ``Array`` | ||
262 | |||
263 | **Default:** ``[]`` | ||
264 | |||
265 | .. versionadded:: 1.0 | ||
266 | |||
267 | A collection of remote script urls to include in every page loaded | ||
268 | |||
269 | .. index:: Logging | ||
270 | |||
271 | ``safeLogs`` | ||
272 | ------------------------------------------------------------------------------- | ||
273 | |||
274 | **Type:** ``Boolean`` | ||
275 | |||
276 | **Default:** ``true`` | ||
277 | |||
278 | .. versionadded:: 1.0 | ||
279 | |||
280 | 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). | ||
281 | |||
282 | .. index:: Step stack, timeout | ||
283 | |||
284 | ``stepTimeout`` | ||
285 | ------------------------------------------------------------------------------- | ||
286 | |||
287 | **Type:** ``Number`` | ||
288 | |||
289 | **Default:** ``null`` | ||
290 | |||
291 | 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. | ||
292 | |||
293 | .. index:: timeout | ||
294 | |||
295 | ``timeout`` | ||
296 | ------------------------------------------------------------------------------- | ||
297 | |||
298 | **Type:** ``Number`` | ||
299 | |||
300 | **Default:** ``null`` | ||
301 | |||
302 | Max timeout in milliseconds | ||
303 | |||
304 | .. index:: verbose | ||
305 | |||
306 | ``verbose`` | ||
307 | ------------------------------------------------------------------------------- | ||
308 | |||
309 | **Type:** ``Boolean`` | ||
310 | |||
311 | **Default:** ``false`` | ||
312 | |||
313 | Realtime output of log messages | ||
314 | |||
315 | .. index:: viewport | ||
316 | |||
317 | ``viewportSize`` | ||
318 | ------------------------------------------------------------------------------- | ||
319 | |||
320 | **Type:** ``Object`` | ||
321 | |||
322 | **Default:** ``null`` | ||
323 | |||
324 | Viewport size, eg. ``{width: 800, height: 600}`` | ||
325 | |||
326 | .. note:: | ||
327 | |||
328 | PhantomJS ships with a default viewport of 400x300, and CasperJS won't override it by default. | ||
329 | |||
330 | .. index:: timeout | ||
331 | |||
332 | ``waitTimeout`` | ||
333 | ------------------------------------------------------------------------------- | ||
334 | |||
335 | **Type:** ``Number`` | ||
336 | |||
337 | **Default:** ``5000`` | ||
338 | |||
339 | Default wait timeout, for ``wait*`` family functions. | ||
340 | |||
341 | |||
342 | ``Casper`` prototype | ||
343 | ++++++++++++++++++++ | ||
344 | |||
345 | ``back()`` | ||
346 | ------------------------------------------------------------------------------- | ||
347 | |||
348 | **Signature:** ``back()`` | ||
349 | |||
350 | Moves back a step in browser's history:: | ||
351 | |||
352 | casper.start('http://foo.bar/1') | ||
353 | casper.thenOpen('http://foo.bar/2'); | ||
354 | casper.thenOpen('http://foo.bar/3'); | ||
355 | casper.back(); | ||
356 | casper.run(function() { | ||
357 | console.log(this.getCurrentUrl()); // 'http://foo.bar/2' | ||
358 | }); | ||
359 | |||
360 | Also have a look at ``Casper.forward()``. | ||
361 | |||
362 | .. _casper_base64encode: | ||
363 | |||
364 | .. index:: Base64 | ||
365 | |||
366 | ``base64encode()`` | ||
367 | ------------------------------------------------------------------------------- | ||
368 | |||
369 | **Signature:** ``base64encode(String url [, String method, Object data])`` | ||
370 | |||
371 | Encodes a resource using the base64 algorithm synchronously using | ||
372 | client-side XMLHttpRequest. | ||
373 | |||
374 | .. note:: | ||
375 | |||
376 | We cannot use ``window.btoa()`` because it fails miserably in the version of WebKit shipping with PhantomJS. | ||
377 | |||
378 | Example: retrieving google logo image encoded in base64:: | ||
379 | |||
380 | var base64logo = null; | ||
381 | casper.start('http://www.google.fr/', function() { | ||
382 | base64logo = this.base64encode('http://www.google.fr/images/srpr/logo3w.png'); | ||
383 | }); | ||
384 | |||
385 | casper.run(function() { | ||
386 | this.echo(base64logo).exit(); | ||
387 | }); | ||
388 | |||
389 | You can also perform an HTTP POST request to retrieve the contents to | ||
390 | encode:: | ||
391 | |||
392 | var base46contents = null; | ||
393 | casper.start('http://domain.tld/download.html', function() { | ||
394 | base46contents = this.base64encode('http://domain.tld/', 'POST', { | ||
395 | param1: 'foo', | ||
396 | param2: 'bar' | ||
397 | }); | ||
398 | }); | ||
399 | |||
400 | casper.run(function() { | ||
401 | this.echo(base46contents).exit(); | ||
402 | }); | ||
403 | |||
404 | .. index:: bypass, Step stack | ||
405 | |||
406 | ``bypass()`` | ||
407 | ------------------------------------------------------------------------------- | ||
408 | |||
409 | **Signature:** ``bypass(Numbr nb)`` | ||
410 | |||
411 | Bypasses a given number of defined navigation steps:: | ||
412 | |||
413 | casper.start(); | ||
414 | casper.then(function() { | ||
415 | // This step will be executed | ||
416 | }); | ||
417 | casper.then(function() { | ||
418 | this.bypass(2); | ||
419 | }); | ||
420 | casper.then(function() { | ||
421 | // This test won't be executed | ||
422 | }); | ||
423 | casper.then(function() { | ||
424 | // Nor this one | ||
425 | }); | ||
426 | casper.run(); | ||
427 | |||
428 | .. _casper_click: | ||
429 | |||
430 | .. index:: click | ||
431 | |||
432 | ``click()`` | ||
433 | ------------------------------------------------------------------------------- | ||
434 | |||
435 | **Signature:** ``click(String selector)`` | ||
436 | |||
437 | Performs a click on the element matching the provided :doc:`selector expression <../selectors>`. The method tries two strategies sequentially: | ||
438 | |||
439 | 1. trying to trigger a MouseEvent in Javascript | ||
440 | 2. using native QtWebKit event if the previous attempt failed | ||
441 | |||
442 | Example:: | ||
443 | |||
444 | casper.start('http://google.fr/'); | ||
445 | |||
446 | casper.thenEvaluate(function(term) { | ||
447 | document.querySelector('input[name="q"]').setAttribute('value', term); | ||
448 | document.querySelector('form[name="f"]').submit(); | ||
449 | }, 'CasperJS'); | ||
450 | |||
451 | casper.then(function() { | ||
452 | // Click on 1st result link | ||
453 | this.click('h3.r a'); | ||
454 | }); | ||
455 | |||
456 | casper.then(function() { | ||
457 | console.log('clicked ok, new location is ' + this.getCurrentUrl()); | ||
458 | }); | ||
459 | |||
460 | casper.run(); | ||
461 | |||
462 | .. index:: click | ||
463 | |||
464 | ``clickLabel()`` | ||
465 | ------------------------------------------------------------------------------- | ||
466 | |||
467 | **Signature:** ``clickLabel(String label[, String tag])`` | ||
468 | |||
469 | .. versionadded:: 0.6.1 | ||
470 | |||
471 | Clicks on the first DOM element found containing ``label`` text. Optionaly ensures that the element node name is ``tag``:: | ||
472 | |||
473 | // <a href="...">My link is beautiful</a> | ||
474 | casper.then(function() { | ||
475 | this.clickLabel('My link is beautiful', 'a'); | ||
476 | }); | ||
477 | |||
478 | // <button type="submit">But my button is sexier</button> | ||
479 | casper.then(function() { | ||
480 | this.clickLabel('But my button is sexier', 'button'); | ||
481 | }); | ||
482 | |||
483 | .. index:: screenshot | ||
484 | |||
485 | ``capture()`` | ||
486 | ------------------------------------------------------------------------------- | ||
487 | |||
488 | **Signature:** ``capture(String targetFilepath, Object clipRect)`` | ||
489 | |||
490 | Proxy method for PhantomJS' ``WebPage#render``. Adds a ``clipRect`` parameter for automatically setting page ``clipRect`` setting and reverts it back once done:: | ||
491 | |||
492 | casper.start('http://www.google.fr/', function() { | ||
493 | this.capture('google.png', { | ||
494 | top: 100, | ||
495 | left: 100, | ||
496 | width: 500, | ||
497 | height: 400 | ||
498 | }); | ||
499 | }); | ||
500 | |||
501 | casper.run(); | ||
502 | |||
503 | .. index:: screenshot, Base64 | ||
504 | |||
505 | ``captureBase64()`` | ||
506 | ------------------------------------------------------------------------------- | ||
507 | |||
508 | **Signature:** ``captureBase64(String format[, Mixed area])`` | ||
509 | |||
510 | .. versionadded:: 0.6.5 | ||
511 | |||
512 | 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. | ||
513 | |||
514 | Supported image formats are ``bmp``, ``jpg``, ``jpeg``, ``png``, ``ppm``, ``tiff``, ``xbm`` and ``xpm``. | ||
515 | |||
516 | The ``area`` argument can be either of the following types: | ||
517 | |||
518 | - ``String``: area is a CSS3 selector string, eg. ``div#plop form[name="form"] input[type="submit"]`` | ||
519 | - ``clipRect``: area is a clipRect object, eg. ``{"top":0,"left":0,"width":320,"height":200}`` | ||
520 | - ``Object``: area is a :doc:`selector object <../selectors>`, eg. an XPath selector | ||
521 | |||
522 | Example:: | ||
523 | |||
524 | casper.start('http://google.com', function() { | ||
525 | // selector capture | ||
526 | console.log(this.captureBase64('png', '#lga')); | ||
527 | // clipRect capture | ||
528 | console.log(this.captureBase64('png', { | ||
529 | top: 0, | ||
530 | left: 0, | ||
531 | width: 320, | ||
532 | height: 200 | ||
533 | })); | ||
534 | // whole page capture | ||
535 | console.log(this.captureBase64('png')); | ||
536 | }); | ||
537 | |||
538 | casper.run(); | ||
539 | |||
540 | .. _casper_captureselector: | ||
541 | |||
542 | .. index:: screenshot | ||
543 | |||
544 | ``captureSelector()`` | ||
545 | ------------------------------------------------------------------------------- | ||
546 | |||
547 | **Signature:** ``captureSelector(String targetFile, String selector)`` | ||
548 | |||
549 | Captures the page area containing the provided selector and saves it to ``targetFile``:: | ||
550 | |||
551 | casper.start('http://www.weather.com/', function() { | ||
552 | this.captureSelector('weather.png', '#wx-main'); | ||
553 | }); | ||
554 | |||
555 | casper.run(); | ||
556 | |||
557 | ``clear()`` | ||
558 | ------------------------------------------------------------------------------- | ||
559 | |||
560 | **Signature:** ``clear()`` | ||
561 | |||
562 | .. versionadded:: 0.6.5 | ||
563 | |||
564 | Clears the current page execution environment context. Useful to avoid having previously loaded DOM contents being still active. | ||
565 | |||
566 | Think of it as a way to stop javascript execution within the remote DOM environment:: | ||
567 | |||
568 | casper.start('http://www.google.fr/', function() { | ||
569 | this.clear(); // javascript execution in this page has been stopped | ||
570 | }); | ||
571 | |||
572 | casper.then(function() { | ||
573 | // ... | ||
574 | }); | ||
575 | |||
576 | casper.run(); | ||
577 | |||
578 | .. index:: Debugging | ||
579 | |||
580 | ``debugHTML()`` | ||
581 | ------------------------------------------------------------------------------- | ||
582 | |||
583 | **Signature:** ``debugHTML([String selector, Boolean outer])`` | ||
584 | |||
585 | Outputs the results of `getHTML()`_ directly to the console. It takes the same arguments as ``getHTML()``. | ||
586 | |||
587 | .. index:: Debugging | ||
588 | |||
589 | ``debugPage()`` | ||
590 | ------------------------------------------------------------------------------- | ||
591 | |||
592 | **Signature:** ``debugPage()`` | ||
593 | |||
594 | Logs the textual contents of the current page directly to the standard output, for debugging purpose:: | ||
595 | |||
596 | casper.start('http://www.google.fr/', function() { | ||
597 | this.debugPage(); | ||
598 | }); | ||
599 | |||
600 | casper.run(); | ||
601 | |||
602 | ``die()`` | ||
603 | ------------------------------------------------------------------------------- | ||
604 | |||
605 | **Signature:** ``die(String message[, int status])`` | ||
606 | |||
607 | Exits phantom with a logged error message and an optional exit status code:: | ||
608 | |||
609 | casper.start('http://www.google.fr/', function() { | ||
610 | this.die("Fail.", 1); | ||
611 | }); | ||
612 | |||
613 | casper.run(); | ||
614 | |||
615 | .. _casper_download: | ||
616 | |||
617 | .. index:: download | ||
618 | |||
619 | ``download()`` | ||
620 | ------------------------------------------------------------------------------- | ||
621 | |||
622 | **Signature:** ``download(String url, String target[, String method, Object data])`` | ||
623 | |||
624 | 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()`_):: | ||
625 | |||
626 | casper.start('http://www.google.fr/', function() { | ||
627 | var url = 'http://www.google.fr/intl/fr/about/corporate/company/'; | ||
628 | this.download(url, 'google_company.html'); | ||
629 | }); | ||
630 | |||
631 | casper.run(function() { | ||
632 | this.echo('Done.').exit(); | ||
633 | }); | ||
634 | |||
635 | ``each()`` | ||
636 | ------------------------------------------------------------------------------- | ||
637 | |||
638 | **Signature:** ``each(Array array, Function fn)`` | ||
639 | |||
640 | Iterates over provided array items and execute a callback:: | ||
641 | |||
642 | var links = [ | ||
643 | 'http://google.com/', | ||
644 | 'http://yahoo.com/', | ||
645 | 'http://bing.com/' | ||
646 | ]; | ||
647 | |||
648 | casper.start().each(links, function(self, link) { | ||
649 | self.thenOpen(link, function() { | ||
650 | this.echo(this.getTitle()); | ||
651 | }); | ||
652 | }); | ||
653 | |||
654 | casper.run(); | ||
655 | |||
656 | .. hint:: | ||
657 | |||
658 | Have a look at the `googlematch.js <https://github.com/n1k0/casperjs/blob/master/samples/googlematch.js>`_ sample script for a concrete use case. | ||
659 | |||
660 | .. _casper_echo: | ||
661 | |||
662 | .. index:: echo, Printing | ||
663 | |||
664 | ``echo()`` | ||
665 | ------------------------------------------------------------------------------- | ||
666 | |||
667 | **Signature:** ``echo(String message[, String style])`` | ||
668 | |||
669 | Prints something to stdout, optionally with some fancy color (see the :ref:`colorizer module <colorizer_module>` for more information):: | ||
670 | |||
671 | casper.start('http://www.google.fr/', function() { | ||
672 | this.echo('Page title is: ' + this.evaluate(function() { | ||
673 | return document.title; | ||
674 | }), 'INFO'); // Will be printed in green on the console | ||
675 | }); | ||
676 | |||
677 | casper.run(); | ||
678 | |||
679 | .. index:: evaluate, DOM | ||
680 | |||
681 | .. _casper_evaluate: | ||
682 | |||
683 | ``evaluate()`` | ||
684 | ------------------------------------------------------------------------------- | ||
685 | |||
686 | **Signature:** ``evaluate(Function fn[, arg1[, arg2[, …]]])`` | ||
687 | |||
688 | 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**:: | ||
689 | |||
690 | casper.evaluate(function(username, password) { | ||
691 | document.querySelector('#username').value = username; | ||
692 | document.querySelector('#password').value = password; | ||
693 | document.querySelector('#submit').click(); | ||
694 | }, 'sheldon.cooper', 'b4z1ng4'); | ||
695 | |||
696 | .. note:: | ||
697 | |||
698 | For filling and submitting forms, rather use the `fill()`_ method. | ||
699 | |||
700 | .. warning:: | ||
701 | |||
702 | 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. | ||
703 | |||
704 | .. topic:: Understanding ``evaluate()`` | ||
705 | |||
706 | 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. | ||
707 | |||
708 | Here's a quickly drafted diagram trying to basically explain the separation of concerns: | ||
709 | |||
710 | .. figure:: ../_static/images/evaluate-diagram.png | ||
711 | :align: center | ||
712 | |||
713 | ``evaluateOrDie()`` | ||
714 | ------------------------------------------------------------------------------- | ||
715 | |||
716 | **Signature:** ``evaluateOrDie(Function fn[, String message])`` | ||
717 | |||
718 | Evaluates an expression within the current page DOM and ``die()`` if it returns anything but ``true``:: | ||
719 | |||
720 | casper.start('http://foo.bar/home', function() { | ||
721 | this.evaluateOrDie(function() { | ||
722 | return /logged in/.match(document.title); | ||
723 | }, 'not authenticated'); | ||
724 | }); | ||
725 | |||
726 | casper.run(); | ||
727 | |||
728 | .. index:: exit | ||
729 | |||
730 | ``exit()`` | ||
731 | ------------------------------------------------------------------------------- | ||
732 | |||
733 | **Signature:** ``exit([int status])`` | ||
734 | |||
735 | Exits PhantomJS with an optional exit status code. | ||
736 | |||
737 | .. index:: DOM | ||
738 | |||
739 | ``exists()`` | ||
740 | ------------------------------------------------------------------------------- | ||
741 | |||
742 | **Signature:** ``exists(String selector)`` | ||
743 | |||
744 | Checks if any element within remote DOM matches the provided :doc:`selector <../selectors>`:: | ||
745 | |||
746 | casper.start('http://foo.bar/home', function() { | ||
747 | if (this.exists('#my_super_id')) { | ||
748 | this.echo('found #my_super_id', 'INFO'); | ||
749 | } else { | ||
750 | this.echo('#my_super_id not found', 'ERROR'); | ||
751 | } | ||
752 | }); | ||
753 | |||
754 | casper.run(); | ||
755 | |||
756 | .. _casper_fetchtext: | ||
757 | |||
758 | ``fetchText()`` | ||
759 | ------------------------------------------------------------------------------- | ||
760 | |||
761 | **Signature:** ``fetchText(String selector)`` | ||
762 | |||
763 | 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:: | ||
764 | |||
765 | casper.start('http://google.com/search?q=foo', function() { | ||
766 | this.echo(this.fetchText('h3')); | ||
767 | }).run(); | ||
768 | |||
769 | ``forward()`` | ||
770 | ------------------------------------------------------------------------------- | ||
771 | |||
772 | **Signature:** ``forward()`` | ||
773 | |||
774 | Moves a step forward in browser's history:: | ||
775 | |||
776 | casper.start('http://foo.bar/1') | ||
777 | casper.thenOpen('http://foo.bar/2'); | ||
778 | casper.thenOpen('http://foo.bar/3'); | ||
779 | casper.back(); // http://foo.bar/2 | ||
780 | casper.back(); // http://foo.bar/1 | ||
781 | casper.forward(); // http://foo.bar/2 | ||
782 | casper.run(); | ||
783 | |||
784 | Also have a look at `back()`_. | ||
785 | |||
786 | .. _casper_log: | ||
787 | |||
788 | .. index:: Logging | ||
789 | |||
790 | ``log()`` | ||
791 | ------------------------------------------------------------------------------- | ||
792 | |||
793 | **Signature:** ``log(String message[, String level, String space])`` | ||
794 | |||
795 | 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:: | ||
796 | |||
797 | casper.start('http://www.google.fr/', function() { | ||
798 | this.log("I'm logging an error", "error"); | ||
799 | }); | ||
800 | |||
801 | casper.run(); | ||
802 | |||
803 | .. _casper_fill: | ||
804 | |||
805 | .. index:: Form | ||
806 | |||
807 | ``fill()`` | ||
808 | ------------------------------------------------------------------------------- | ||
809 | |||
810 | **Signature:** ``fill(String selector, Object values[, Boolean submit])`` | ||
811 | |||
812 | Fills the fields of a form with given values and optionally submits it. | ||
813 | |||
814 | Example with this sample html form: | ||
815 | |||
816 | .. code-block :: html | ||
817 | |||
818 | <form action="/contact" id="contact-form" enctype="multipart/form-data"> | ||
819 | <input type="text" name="subject"/> | ||
820 | <textearea name="content"></textearea> | ||
821 | <input type="radio" name="civility" value="Mr"/> Mr | ||
822 | <input type="radio" name="civility" value="Mrs"/> Mrs | ||
823 | <input type="text" name="name"/> | ||
824 | <input type="email" name="email"/> | ||
825 | <input type="file" name="attachment"/> | ||
826 | <input type="checkbox" name="cc"/> Receive a copy | ||
827 | <input type="submit"/> | ||
828 | </form> | ||
829 | |||
830 | A script to fill and submit this form:: | ||
831 | |||
832 | casper.start('http://some.tld/contact.form', function() { | ||
833 | this.fill('form#contact-form', { | ||
834 | 'subject': 'I am watching you', | ||
835 | 'content': 'So be careful.', | ||
836 | 'civility': 'Mr', | ||
837 | 'name': 'Chuck Norris', | ||
838 | 'email': 'chuck@norris.com', | ||
839 | 'cc': true, | ||
840 | 'attachment': '/Users/chuck/roundhousekick.doc' | ||
841 | }, true); | ||
842 | }); | ||
843 | |||
844 | casper.then(function() { | ||
845 | this.evaluateOrDie(function() { | ||
846 | return /message sent/.test(document.body.innerText); | ||
847 | }, 'sending message failed'); | ||
848 | }); | ||
849 | |||
850 | casper.run(function() { | ||
851 | this.echo('message sent').exit(); | ||
852 | }); | ||
853 | |||
854 | .. warning:: | ||
855 | |||
856 | 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. | ||
857 | 2. Please Don't use CasperJS nor PhantomJS to send spam, or I'll be calling the Chuck. More seriously, please just don't. | ||
858 | |||
859 | .. index:: URL | ||
860 | |||
861 | ``getCurrentUrl()`` | ||
862 | ------------------------------------------------------------------------------- | ||
863 | |||
864 | **Signature:** ``getCurrentUrl()`` | ||
865 | |||
866 | Retrieves current page URL. Note that the url will be url-decoded:: | ||
867 | |||
868 | casper.start('http://www.google.fr/', function() { | ||
869 | this.echo(this.getCurrentUrl()); // "http://www.google.fr/" | ||
870 | }); | ||
871 | |||
872 | casper.run(); | ||
873 | |||
874 | .. index:: DOM | ||
875 | |||
876 | ``getElementAttribute()`` | ||
877 | ------------------------------------------------------------------------------- | ||
878 | |||
879 | **Signature:** ``getElementAttribute(String selector, String attribute)`` | ||
880 | |||
881 | .. versionadded:: 1.0 | ||
882 | |||
883 | Retrieves the value of an attribute on the first element matching the provided :doc:`selector <../selectors>`:: | ||
884 | |||
885 | var casper = require('casper').create(); | ||
886 | |||
887 | casper.start('http://www.google.fr/', function() { | ||
888 | require('utils').dump(this.getElementAttribute('div[title="Google"]', 'title')); // "Google" | ||
889 | }); | ||
890 | |||
891 | casper.run(); | ||
892 | |||
893 | .. index:: DOM | ||
894 | |||
895 | ``getElementBounds()`` | ||
896 | ------------------------------------------------------------------------------- | ||
897 | |||
898 | **Signature:** ``getElementBounds(String selector)`` | ||
899 | |||
900 | Retrieves boundaries for a DOM element matching the provided :doc:`selector <../selectors>`. | ||
901 | |||
902 | It returns an Object with four keys: ``top``, ``left``, ``width`` and ``height``, or ``null`` if the selector doesn't exist:: | ||
903 | |||
904 | var casper = require('casper').create(); | ||
905 | |||
906 | casper.start('http://www.google.fr/', function() { | ||
907 | require('utils').dump(this.getElementBounds('div[title="Google"]')); | ||
908 | }); | ||
909 | |||
910 | casper.run(); | ||
911 | |||
912 | This will output something like:: | ||
913 | |||
914 | { | ||
915 | "height": 95, | ||
916 | "left": 352, | ||
917 | "top": 16, | ||
918 | "width": 275 | ||
919 | } | ||
920 | |||
921 | .. index:: DOM | ||
922 | |||
923 | ``getElementsBounds()`` | ||
924 | ------------------------------------------------------------------------------- | ||
925 | |||
926 | **Signature:** ``getElementsBounds(String selector)`` | ||
927 | |||
928 | .. versionadded:: 1.0 | ||
929 | |||
930 | Retrieves a list of boundaries for all DOM elements matching the provided :doc:`selector <../selectors>`. | ||
931 | |||
932 | It returns an array of objects with four keys: ``top``, ``left``, ``width`` and ``height`` (see `getElementBounds()`_). | ||
933 | |||
934 | .. _casper_getelementinfo: | ||
935 | |||
936 | .. index:: DOM | ||
937 | |||
938 | ``getElementInfo()`` | ||
939 | ------------------------------------------------------------------------------- | ||
940 | |||
941 | **Signature:** ``getElementInfo(String selector)`` | ||
942 | |||
943 | .. versionadded:: 1.0 | ||
944 | |||
945 | Retrieves information about the first element matching the provided :doc:`selector <../selectors>`:: | ||
946 | |||
947 | casper.start('http://google.com/', function() { | ||
948 | require('utils').dump(this.getElementInfo('#hplogo')); | ||
949 | }); | ||
950 | |||
951 | Gives something like:: | ||
952 | |||
953 | { | ||
954 | "nodeName": "div", | ||
955 | "attributes": { | ||
956 | "dir": "ltr", | ||
957 | "title": "Google", | ||
958 | "align": "left", | ||
959 | "id": "hplogo", | ||
960 | "onload": "window.lol&&lol()", | ||
961 | "style": "background:url(images/srpr/logo3w.png) no-repeat;background-size:275px 95px;height:95px;width:275px" | ||
962 | }, | ||
963 | "tag": "<div 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\"><div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div></div>", | ||
964 | "html": "<div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div>", | ||
965 | "text": "France\n", | ||
966 | "x": 582.5, | ||
967 | "y": 192, | ||
968 | "width": 275, | ||
969 | "height": 95, | ||
970 | "visible": true | ||
971 | } | ||
972 | |||
973 | .. index:: Form | ||
974 | |||
975 | ``getFormValues()`` | ||
976 | ------------------------------------------------------------------------------- | ||
977 | |||
978 | **Signature:** ``getFormValues(String selector)`` | ||
979 | |||
980 | .. versionadded:: 1.0 | ||
981 | |||
982 | Retrieves a given form all of its field values:: | ||
983 | |||
984 | casper.start('http://www.google.fr/', function() { | ||
985 | this.fill('form', {q: 'plop'}, false); | ||
986 | this.echo(this.getFormValues('form').q); // 'plop' | ||
987 | }); | ||
988 | |||
989 | casper.run(); | ||
990 | |||
991 | .. index:: Globals, window | ||
992 | |||
993 | ``getGlobal()`` | ||
994 | ------------------------------------------------------------------------------- | ||
995 | |||
996 | **Signature:** ``getGlobal(String name)`` | ||
997 | |||
998 | 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:: | ||
999 | |||
1000 | casper.start('http://www.google.fr/', function() { | ||
1001 | this.echo(this.getGlobal('innerWidth')); // 1024 | ||
1002 | }); | ||
1003 | |||
1004 | casper.run(); | ||
1005 | |||
1006 | .. index:: Debugging | ||
1007 | |||
1008 | ``getHTML()`` | ||
1009 | ------------------------------------------------------------------------------- | ||
1010 | |||
1011 | **Signature:** ``getHTML([String selector, Boolean outer])`` | ||
1012 | |||
1013 | .. versionadded:: 1.0 | ||
1014 | |||
1015 | Retrieves HTML code from the current page. By default, it outputs the whole page HTML contents:: | ||
1016 | |||
1017 | casper.start('http://www.google.fr/', function() { | ||
1018 | this.echo(this.getHTML()); | ||
1019 | }); | ||
1020 | |||
1021 | casper.run(); | ||
1022 | |||
1023 | The ``getHTML()`` method can also dump HTML contents matching a given :doc:`selector <../selectors>`; for example with this HTML code: | ||
1024 | |||
1025 | .. code-block:: html | ||
1026 | |||
1027 | <html> | ||
1028 | <body> | ||
1029 | <h1 id="foobar">Plop</h1> | ||
1030 | </body> | ||
1031 | </html> | ||
1032 | |||
1033 | You can fetch those contents using:: | ||
1034 | |||
1035 | casper.start('http://www.site.tld/', function() { | ||
1036 | this.echo(this.getHTML('h1#foobar')); // => 'Plop' | ||
1037 | }); | ||
1038 | |||
1039 | The ``outer`` argument allows to retrieve the outer HTML contents of the matching element:: | ||
1040 | |||
1041 | casper.start('http://www.site.tld/', function() { | ||
1042 | this.echo(this.getHTML('h1#foobar', true)); // => '<h1 id="foobar">Plop</h1>' | ||
1043 | }); | ||
1044 | |||
1045 | ``getPageContent()`` | ||
1046 | ------------------------------------------------------------------------------- | ||
1047 | |||
1048 | **Signature:** ``getPageContent()`` | ||
1049 | |||
1050 | .. versionadded:: 1.0 | ||
1051 | |||
1052 | Retrieves current page contents, dealing with exotic other content types than HTML:: | ||
1053 | |||
1054 | var casper = require('casper').create(); | ||
1055 | |||
1056 | casper.start().then(function() { | ||
1057 | this.open('http://search.twitter.com/search.json?q=casperjs', { | ||
1058 | method: 'get', | ||
1059 | headers: { | ||
1060 | 'Accept': 'application/json' | ||
1061 | } | ||
1062 | }); | ||
1063 | }); | ||
1064 | |||
1065 | casper.run(function() { | ||
1066 | require('utils').dump(JSON.parse(this.getPageContent())); | ||
1067 | this.exit(); | ||
1068 | }); | ||
1069 | |||
1070 | .. index:: DOM | ||
1071 | |||
1072 | ``getTitle()`` | ||
1073 | ------------------------------------------------------------------------------- | ||
1074 | |||
1075 | **Signature:** ``getTitle()`` | ||
1076 | |||
1077 | Retrieves current page title:: | ||
1078 | |||
1079 | casper.start('http://www.google.fr/', function() { | ||
1080 | this.echo(this.getTitle()); // "Google" | ||
1081 | }); | ||
1082 | |||
1083 | casper.run(); | ||
1084 | |||
1085 | .. _casper_mouseevent: | ||
1086 | |||
1087 | .. index:: events | ||
1088 | |||
1089 | ``mouseEvent()`` | ||
1090 | ------------------------------------------------------------------------------- | ||
1091 | |||
1092 | **Signature:** ``mouseEvent(String type, String selector)`` | ||
1093 | |||
1094 | .. versionadded:: 0.6.9 | ||
1095 | |||
1096 | Triggers a mouse event on the first element found matching the provided selector. | ||
1097 | |||
1098 | Supported events are ``mouseup``, ``mousedown``, ``click``, ``mousemove``, ``mouseover`` and ``mouseout``:: | ||
1099 | |||
1100 | casper.start('http://www.google.fr/', function() { | ||
1101 | this.mouseEvent('click', 'h2 a'); | ||
1102 | }); | ||
1103 | |||
1104 | casper.run(); | ||
1105 | |||
1106 | .. index:: HTTP, HTTP Request, HTTP Method, HTTP Headers | ||
1107 | |||
1108 | ``open()`` | ||
1109 | ------------------------------------------------------------------------------- | ||
1110 | |||
1111 | **Signature:** ``open(String location, Object Settings)`` | ||
1112 | |||
1113 | Performs an HTTP request for opening a given location. You can forge ``GET``, ``POST``, ``PUT``, ``DELETE`` and ``HEAD`` requests. | ||
1114 | |||
1115 | Example for a standard ``GET`` request:: | ||
1116 | |||
1117 | casper.start(); | ||
1118 | |||
1119 | casper.open('http://www.google.com/').then(function() { | ||
1120 | this.echo('GOT it.'); | ||
1121 | }); | ||
1122 | |||
1123 | casper.run(); | ||
1124 | |||
1125 | Example for a ``POST`` request:: | ||
1126 | |||
1127 | casper.start(); | ||
1128 | |||
1129 | casper.open('http://some.testserver.com/post.php', { | ||
1130 | method: 'post', | ||
1131 | data: { | ||
1132 | 'title': 'Plop', | ||
1133 | 'body': 'Wow.' | ||
1134 | } | ||
1135 | }); | ||
1136 | |||
1137 | casper.then(function() { | ||
1138 | this.echo('POSTED it.'); | ||
1139 | }); | ||
1140 | |||
1141 | casper.run(); | ||
1142 | |||
1143 | To pass nested parameters arrays:: | ||
1144 | |||
1145 | casper.open('http://some.testserver.com/post.php', { | ||
1146 | method: 'post', | ||
1147 | data: { | ||
1148 | 'standard_param': 'foo', | ||
1149 | 'nested_param[]': [ // please note the use of square brackets! | ||
1150 | 'Something', | ||
1151 | 'Something else' | ||
1152 | ] | ||
1153 | } | ||
1154 | }); | ||
1155 | |||
1156 | .. versionadded:: 1.0 | ||
1157 | |||
1158 | You can also set custom request headers to send when performing an outgoing request, passing the ``headers`` option:: | ||
1159 | |||
1160 | casper.open('http://some.testserver.com/post.php', { | ||
1161 | method: 'post', | ||
1162 | data: { | ||
1163 | 'title': 'Plop', | ||
1164 | 'body': 'Wow.' | ||
1165 | }, | ||
1166 | headers: { | ||
1167 | 'Accept-Language': 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' | ||
1168 | } | ||
1169 | }); | ||
1170 | |||
1171 | ``reload()`` | ||
1172 | ------------------------------------------------------------------------------- | ||
1173 | |||
1174 | **Signature:** ``reload([Function then])`` | ||
1175 | |||
1176 | .. versionadded:: 1.0 | ||
1177 | |||
1178 | Reloads current page location:: | ||
1179 | |||
1180 | casper.start('http://google.com', function() { | ||
1181 | this.echo("loaded"); | ||
1182 | this.reload(function() { | ||
1183 | this.echo("loaded again"); | ||
1184 | }); | ||
1185 | }); | ||
1186 | |||
1187 | casper.run(); | ||
1188 | |||
1189 | ``repeat()`` | ||
1190 | ------------------------------------------------------------------------------- | ||
1191 | |||
1192 | **Signature:** ``repeat(int times, Function then)`` | ||
1193 | |||
1194 | Repeats a navigation step a given number of times:: | ||
1195 | |||
1196 | casper.start().repeat(3, function() { | ||
1197 | this.echo("Badger"); | ||
1198 | }); | ||
1199 | |||
1200 | casper.run(); | ||
1201 | |||
1202 | .. _casper_resourceexists: | ||
1203 | |||
1204 | .. index:: HTTP | ||
1205 | |||
1206 | ``resourceExists()`` | ||
1207 | ------------------------------------------------------------------------------- | ||
1208 | |||
1209 | **Signature:** ``resourceExists(Mixed test)`` | ||
1210 | |||
1211 | Checks if a resource has been loaded. You can pass either a function or a string to perform the test:: | ||
1212 | |||
1213 | casper.start('http://www.google.com/', function() { | ||
1214 | if (this.resourceExists('logo3w.png')) { | ||
1215 | this.echo('Google logo loaded'); | ||
1216 | } else { | ||
1217 | this.echo('Google logo not loaded', 'ERROR'); | ||
1218 | } | ||
1219 | }); | ||
1220 | |||
1221 | casper.run(); | ||
1222 | |||
1223 | .. note:: | ||
1224 | |||
1225 | If you want to wait for a resource to be loaded, use the `waitForResource()`_ method. | ||
1226 | |||
1227 | .. index:: Step stack, run | ||
1228 | |||
1229 | ``run()`` | ||
1230 | ------------------------------------------------------------------------------- | ||
1231 | |||
1232 | **Signature:** ``run(fn onComplete[, int time])`` | ||
1233 | |||
1234 | 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. | ||
1235 | |||
1236 | Casper suite **won't run**:: | ||
1237 | |||
1238 | casper.start('http://foo.bar/home', function() { | ||
1239 | // ... | ||
1240 | }); | ||
1241 | |||
1242 | // hey, it's missing .run() here! | ||
1243 | |||
1244 | Casper suite **will run**:: | ||
1245 | |||
1246 | casper.start('http://foo.bar/home', function() { | ||
1247 | // ... | ||
1248 | }); | ||
1249 | |||
1250 | casper.run(); | ||
1251 | |||
1252 | ``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!:: | ||
1253 | |||
1254 | casper.start('http://foo.bar/home', function() { | ||
1255 | // ... | ||
1256 | }); | ||
1257 | |||
1258 | casper.then(function() { | ||
1259 | // ... | ||
1260 | }); | ||
1261 | |||
1262 | casper.run(function() { | ||
1263 | this.echo('So the whole suite ended.'); | ||
1264 | this.exit(); // <--- don't forget me! | ||
1265 | }); | ||
1266 | |||
1267 | .. index:: Form | ||
1268 | |||
1269 | ``sendKeys()`` | ||
1270 | ------------------------------------------------------------------------------- | ||
1271 | |||
1272 | **Signature:** ``sendKeys(Selector selector, String keys[, Object options])`` | ||
1273 | |||
1274 | .. versionadded:: 1.0 | ||
1275 | |||
1276 | Sends native keyboard events to the element matching the provided :doc:`selector <../selectors>`:: | ||
1277 | |||
1278 | casper.then(function() { | ||
1279 | this.sendKeys('form.contact input#name', 'Duke'); | ||
1280 | this.sendKeys('form.contact textarea#message', "Damn, I'm looking good."); | ||
1281 | this.click('form.contact input[type="submit"]'); | ||
1282 | }); | ||
1283 | |||
1284 | .. index:: auth | ||
1285 | |||
1286 | ``setHttpAuth()`` | ||
1287 | ------------------------------------------------------------------------------- | ||
1288 | |||
1289 | **Signature:** ``setHttpAuth(String username, String password)`` | ||
1290 | |||
1291 | Sets ``HTTP_AUTH_USER`` and ``HTTP_AUTH_PW`` values for HTTP based authentication systems:: | ||
1292 | |||
1293 | casper.start(); | ||
1294 | |||
1295 | casper.setHttpAuth('sheldon.cooper', 'b4z1ng4'); | ||
1296 | |||
1297 | casper.thenOpen('http://password-protected.domain.tld/', function() { | ||
1298 | this.echo("I'm in. Bazinga."); | ||
1299 | }) | ||
1300 | casper.run(); | ||
1301 | |||
1302 | Of course you can directly pass the auth string in the url to open:: | ||
1303 | |||
1304 | var url = 'http://sheldon.cooper:b4z1ng4@password-protected.domain.tld/'; | ||
1305 | |||
1306 | casper.start(url, function() { | ||
1307 | this.echo("I'm in. Bazinga."); | ||
1308 | }) | ||
1309 | |||
1310 | casper.run(); | ||
1311 | |||
1312 | .. index:: start, initialization | ||
1313 | |||
1314 | ``start()`` | ||
1315 | ------------------------------------------------------------------------------- | ||
1316 | |||
1317 | **Signature:** ``start(String url[, Function then])`` | ||
1318 | |||
1319 | Configures and starts Casper, then open the provided ``url`` and optionally adds the step provided by the ``then`` argument:: | ||
1320 | |||
1321 | casper.start('http://google.fr/', function() { | ||
1322 | this.echo("I'm loaded."); | ||
1323 | }); | ||
1324 | |||
1325 | casper.run(); | ||
1326 | |||
1327 | Alternatively:: | ||
1328 | |||
1329 | casper.start('http://google.fr/'); | ||
1330 | |||
1331 | casper.then(function() { | ||
1332 | this.echo("I'm loaded."); | ||
1333 | }); | ||
1334 | |||
1335 | casper.run(); | ||
1336 | |||
1337 | Or alternatively:: | ||
1338 | |||
1339 | casper.start('http://google.fr/'); | ||
1340 | |||
1341 | casper.then(function() { | ||
1342 | casper.echo("I'm loaded."); | ||
1343 | }); | ||
1344 | |||
1345 | casper.run(); | ||
1346 | |||
1347 | Matter of taste! | ||
1348 | |||
1349 | .. note:: | ||
1350 | |||
1351 | 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. | ||
1352 | |||
1353 | ``status()`` | ||
1354 | ------------------------------------------------------------------------------- | ||
1355 | |||
1356 | **Signature:** ``status(Boolean asString)`` | ||
1357 | |||
1358 | .. versionadded:: 1.0 | ||
1359 | |||
1360 | Returns the status of current Casper instance:: | ||
1361 | |||
1362 | casper.start('http://google.fr/', function() { | ||
1363 | this.echo(this.status(true)); | ||
1364 | }); | ||
1365 | |||
1366 | casper.run(); | ||
1367 | |||
1368 | .. index:: Step stack, Asynchronicity | ||
1369 | |||
1370 | ``then()`` | ||
1371 | ------------------------------------------------------------------------------- | ||
1372 | |||
1373 | **Signature:** ``then(Function then)`` | ||
1374 | |||
1375 | This method is the standard way to add a new navigation step to the stack, by providing a simple function:: | ||
1376 | |||
1377 | casper.start('http://google.fr/'); | ||
1378 | |||
1379 | casper.then(function() { | ||
1380 | this.echo("I'm in your google."); | ||
1381 | }); | ||
1382 | |||
1383 | casper.then(function() { | ||
1384 | this.echo('Now, let me write something'); | ||
1385 | }); | ||
1386 | |||
1387 | casper.then(function() { | ||
1388 | this.echo('Oh well.'); | ||
1389 | }); | ||
1390 | |||
1391 | casper.run(); | ||
1392 | |||
1393 | 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. | ||
1394 | |||
1395 | To run all the steps you defined, call the `run()`_ method, and voila. | ||
1396 | |||
1397 | .. index:: HTTP Response | ||
1398 | |||
1399 | .. note:: | ||
1400 | |||
1401 | You must `start()`_ the casper instance in order to use the ``then()`` method. | ||
1402 | |||
1403 | .. topic:: Accessing the current HTTP response | ||
1404 | |||
1405 | .. versionadded:: 1.0 | ||
1406 | |||
1407 | You can access the current HTTP response object using the first parameter of your step callback:: | ||
1408 | |||
1409 | casper.start('http://www.google.fr/', function(response) { | ||
1410 | require('utils').dump(response); | ||
1411 | }); | ||
1412 | |||
1413 | That gives: | ||
1414 | |||
1415 | .. code-block:: text | ||
1416 | |||
1417 | $ casperjs dump-headers.js | ||
1418 | { | ||
1419 | "contentType": "text/html; charset=UTF-8", | ||
1420 | "headers": [ | ||
1421 | { | ||
1422 | "name": "Date", | ||
1423 | "value": "Thu, 18 Oct 2012 08:17:29 GMT" | ||
1424 | }, | ||
1425 | { | ||
1426 | "name": "Expires", | ||
1427 | "value": "-1" | ||
1428 | }, | ||
1429 | // ... lots of other headers | ||
1430 | ], | ||
1431 | "id": 1, | ||
1432 | "redirectURL": null, | ||
1433 | "stage": "end", | ||
1434 | "status": 200, | ||
1435 | "statusText": "OK", | ||
1436 | "time": "2012-10-18T08:17:37.068Z", | ||
1437 | "url": "http://www.google.fr/" | ||
1438 | } | ||
1439 | |||
1440 | So to fetch a particular header by its name:: | ||
1441 | |||
1442 | casper.start('http://www.google.fr/', function(response) { | ||
1443 | this.echo(response.headers.get('Date')); | ||
1444 | }); | ||
1445 | |||
1446 | That gives: | ||
1447 | |||
1448 | .. code-block:: text | ||
1449 | |||
1450 | $ casperjs dump-headers.js | ||
1451 | Thu, 18 Oct 2012 08:26:34 GMT | ||
1452 | |||
1453 | .. index:: bypass, Step stack | ||
1454 | |||
1455 | ``thenBypass()`` | ||
1456 | ------------------------------------------------------------------------------- | ||
1457 | |||
1458 | **Signature:** ``thenBypass(Number nb)`` | ||
1459 | |||
1460 | Adds a navigation step which will bypass a given number of following steps:: | ||
1461 | |||
1462 | casper.start('http://foo.bar/'); | ||
1463 | casper.thenBypass(2); | ||
1464 | casper.then(function() { | ||
1465 | // This test won't be executed | ||
1466 | }); | ||
1467 | casper.then(function() { | ||
1468 | // Nor this one | ||
1469 | }); | ||
1470 | casper.then(function() { | ||
1471 | // While this one will | ||
1472 | }); | ||
1473 | casper.run(); | ||
1474 | |||
1475 | ``thenBypassIf()`` | ||
1476 | ------------------------------------------------------------------------------- | ||
1477 | |||
1478 | **Signature:** ``thenBypassIf(Mixed condition, Number nb)`` | ||
1479 | |||
1480 | Bypass a given number of navigation steps if the provided condition is truthy or is a function that returns a truthy value:: | ||
1481 | |||
1482 | var universe = { | ||
1483 | answer: 42 | ||
1484 | }; | ||
1485 | casper.start('http://foo.bar/'); | ||
1486 | casper.thenBypassIf(function() { | ||
1487 | return universe && universe.answer === 42; | ||
1488 | }, 2); | ||
1489 | casper.then(function() { | ||
1490 | // This step won't be executed as universe.answer is 42 | ||
1491 | }); | ||
1492 | casper.then(function() { | ||
1493 | // Nor this one | ||
1494 | }); | ||
1495 | casper.then(function() { | ||
1496 | // While this one will | ||
1497 | }); | ||
1498 | casper.run(); | ||
1499 | |||
1500 | ``thenBypassUnless()`` | ||
1501 | ------------------------------------------------------------------------------- | ||
1502 | |||
1503 | **Signature:** ``thenBypassUnless(Mixed condition, Number nb)`` | ||
1504 | |||
1505 | Opposite of `thenBypassIf()`_. | ||
1506 | |||
1507 | ``thenClick()`` | ||
1508 | ------------------------------------------------------------------------------- | ||
1509 | |||
1510 | **Signature:** ``thenClick(String selector[, Function then])`` | ||
1511 | |||
1512 | Adds a new navigation step to click a given selector and optionally add a new navigation step in a single operation:: | ||
1513 | |||
1514 | // Querying for "Chuck Norris" on Google | ||
1515 | casper.start('http://casperjs.org/').thenClick('a', function() { | ||
1516 | this.echo("I clicked on first link found, the page is now loaded."); | ||
1517 | }); | ||
1518 | |||
1519 | casper.run(); | ||
1520 | |||
1521 | This method is basically a convenient a shortcut for chaining a `then()`_ and an `evaluate()`_ calls. | ||
1522 | |||
1523 | ``thenEvaluate()`` | ||
1524 | ------------------------------------------------------------------------------- | ||
1525 | |||
1526 | **Signature:** ``thenEvaluate(Function fn[, arg1[, arg2[, …]]])`` | ||
1527 | |||
1528 | Adds a new navigation step to perform code evaluation within the current retrieved page DOM:: | ||
1529 | |||
1530 | // Querying for "Chuck Norris" on Google | ||
1531 | casper.start('http://google.fr/').thenEvaluate(function(term) { | ||
1532 | document.querySelector('input[name="q"]').setAttribute('value', term); | ||
1533 | document.querySelector('form[name="f"]').submit(); | ||
1534 | }, 'Chuck Norris'); | ||
1535 | |||
1536 | casper.run(); | ||
1537 | |||
1538 | This method is basically a convenient a shortcut for chaining a `then()`_ and an `evaluate()`_ calls. | ||
1539 | |||
1540 | ``thenOpen()`` | ||
1541 | ------------------------------------------------------------------------------- | ||
1542 | |||
1543 | **Signature:** ``thenOpen(String location[, mixed options])`` | ||
1544 | |||
1545 | Adds a new navigation step for opening a new location, and optionally add a next step when its loaded:: | ||
1546 | |||
1547 | casper.start('http://google.fr/').then(function() { | ||
1548 | this.echo("I'm in your google."); | ||
1549 | }); | ||
1550 | |||
1551 | casper.thenOpen('http://yahoo.fr/', function() { | ||
1552 | this.echo("Now I'm in your yahoo.") | ||
1553 | }); | ||
1554 | |||
1555 | casper.run(); | ||
1556 | |||
1557 | .. versionadded:: 1.0 | ||
1558 | |||
1559 | You can also specify request settings by passing a setting object (see `open()`_) as the second argument:: | ||
1560 | |||
1561 | casper.start().thenOpen('http://url.to/some/uri', { | ||
1562 | method: "post", | ||
1563 | data: { | ||
1564 | username: 'chuck', | ||
1565 | password: 'n0rr15' | ||
1566 | } | ||
1567 | }, function() { | ||
1568 | this.echo("POST request has been sent.") | ||
1569 | }); | ||
1570 | |||
1571 | casper.run(); | ||
1572 | |||
1573 | ``thenOpenAndEvaluate()`` | ||
1574 | ------------------------------------------------------------------------------- | ||
1575 | |||
1576 | **Signature:** ``thenOpenAndEvaluate(String location[, Function then[, arg1[, arg2[, …]]])`` | ||
1577 | |||
1578 | Basically a shortcut for opening an url and evaluate code against remote DOM environment:: | ||
1579 | |||
1580 | casper.start('http://google.fr/').then(function() { | ||
1581 | this.echo("I'm in your google."); | ||
1582 | }); | ||
1583 | |||
1584 | casper.thenOpenAndEvaluate('http://yahoo.fr/', function() { | ||
1585 | var f = document.querySelector('form'); | ||
1586 | f.querySelector('input[name=q]').value = 'chuck norris'; | ||
1587 | f.submit(); | ||
1588 | }); | ||
1589 | |||
1590 | casper.run(function() { | ||
1591 | this.debugPage(); | ||
1592 | this.exit(); | ||
1593 | }); | ||
1594 | |||
1595 | ``toString()`` | ||
1596 | ------------------------------------------------------------------------------- | ||
1597 | |||
1598 | **Signature:** ``toString()`` | ||
1599 | |||
1600 | .. versionadded:: 1.0 | ||
1601 | |||
1602 | Returns a string representation of current Casper instance:: | ||
1603 | |||
1604 | casper.start('http://google.fr/', function() { | ||
1605 | this.echo(this); // [object Casper], currently at http://google.fr/ | ||
1606 | }); | ||
1607 | |||
1608 | casper.run(); | ||
1609 | |||
1610 | .. index:: User Agent | ||
1611 | |||
1612 | ``userAgent()`` | ||
1613 | ------------------------------------------------------------------------------- | ||
1614 | |||
1615 | **Signature:** ``userAgent(String agent)`` | ||
1616 | |||
1617 | .. versionadded:: 1.0 | ||
1618 | |||
1619 | Sets the `User-Agent string <http://en.wikipedia.org/wiki/User-Agent>`_ to send through headers when performing requests:: | ||
1620 | |||
1621 | casper.start(); | ||
1622 | |||
1623 | casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)'); | ||
1624 | |||
1625 | casper.thenOpen('http://google.com/', function() { | ||
1626 | this.echo("I'm a Mac."); | ||
1627 | }); | ||
1628 | |||
1629 | casper.userAgent('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'); | ||
1630 | |||
1631 | casper.thenOpen('http://google.com/', function() { | ||
1632 | this.echo("I'm a PC."); | ||
1633 | }); | ||
1634 | |||
1635 | casper.run(); | ||
1636 | |||
1637 | .. index:: viewport | ||
1638 | |||
1639 | ``viewport()`` | ||
1640 | ------------------------------------------------------------------------------- | ||
1641 | |||
1642 | **Signature:** ``viewport(Number width, Number height[, Function then])`` | ||
1643 | |||
1644 | Changes current viewport size:: | ||
1645 | |||
1646 | casper.viewport(1024, 768); | ||
1647 | |||
1648 | To be sure page reflowing has occured, you have to use it asynchronously:: | ||
1649 | |||
1650 | casper.viewport(1024, 768).then(function() { | ||
1651 | // new view port is now effective | ||
1652 | }); | ||
1653 | |||
1654 | .. versionadded:: 1.1 | ||
1655 | |||
1656 | As of 1.1 you can pass a `then` step function directly to ``viewport()``:: | ||
1657 | |||
1658 | casper.viewport(1024, 768, function() { | ||
1659 | // new view port is effective | ||
1660 | }); | ||
1661 | |||
1662 | .. note:: | ||
1663 | |||
1664 | PhantomJS comes with a default viewport size of 400x300, and CasperJS doesn't override it by default. | ||
1665 | |||
1666 | .. index:: DOM | ||
1667 | |||
1668 | ``visible()`` | ||
1669 | ------------------------------------------------------------------------------- | ||
1670 | |||
1671 | **Signature:** ``visible(String selector)`` | ||
1672 | |||
1673 | Checks if the DOM element matching the provided :doc:`selector expression <../selectors>` is visible in remote page:: | ||
1674 | |||
1675 | casper.start('http://google.com/', function() { | ||
1676 | if (this.visible('#hplogo')) { | ||
1677 | this.echo("I can see the logo"); | ||
1678 | } else { | ||
1679 | this.echo("I can't see the logo"); | ||
1680 | } | ||
1681 | }); | ||
1682 | |||
1683 | .. index:: wait, sleep | ||
1684 | |||
1685 | ``wait()`` | ||
1686 | ------------------------------------------------------------------------------- | ||
1687 | |||
1688 | **Signature:** ``wait(Number timeout[, Function then])`` | ||
1689 | |||
1690 | Pause steps suite execution for a given amount of time, and optionally execute a step on done:: | ||
1691 | |||
1692 | casper.start('http://yoursite.tld/', function() { | ||
1693 | this.wait(1000, function() { | ||
1694 | this.echo("I've waited for a second."); | ||
1695 | }); | ||
1696 | }); | ||
1697 | |||
1698 | casper.run(); | ||
1699 | |||
1700 | You can also write the same thing like this:: | ||
1701 | |||
1702 | casper.start('http://yoursite.tld/'); | ||
1703 | |||
1704 | casper.wait(1000, function() { | ||
1705 | this.echo("I've waited for a second."); | ||
1706 | }); | ||
1707 | |||
1708 | casper.run(); | ||
1709 | |||
1710 | .. index:: Asynchronicity | ||
1711 | |||
1712 | ``waitFor()`` | ||
1713 | ------------------------------------------------------------------------------- | ||
1714 | |||
1715 | **Signature:** ``waitFor(Function testFx[, Function then, Function onTimeout, Number timeout])`` | ||
1716 | |||
1717 | Waits until a function returns true to process any next step. | ||
1718 | |||
1719 | 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:: | ||
1720 | |||
1721 | casper.start('http://yoursite.tld/'); | ||
1722 | |||
1723 | casper.waitFor(function check() { | ||
1724 | return this.evaluate(function() { | ||
1725 | return document.querySelectorAll('ul.your-list li').length > 2; | ||
1726 | }); | ||
1727 | }, function then() { | ||
1728 | this.captureSelector('yoursitelist.png', 'ul.your-list'); | ||
1729 | }); | ||
1730 | |||
1731 | casper.run(); | ||
1732 | |||
1733 | Example using the ``onTimeout`` callback:: | ||
1734 | |||
1735 | casper.start('http://yoursite.tld/'); | ||
1736 | |||
1737 | casper.waitFor(function check() { | ||
1738 | return this.evaluate(function() { | ||
1739 | return document.querySelectorAll('ul.your-list li').length > 2; | ||
1740 | }); | ||
1741 | }, function then() { // step to execute when check() is ok | ||
1742 | this.captureSelector('yoursitelist.png', 'ul.your-list'); | ||
1743 | }, function timeout() { // step to execute if check has failed | ||
1744 | this.echo("I can't haz my screenshot.").exit(); | ||
1745 | }); | ||
1746 | |||
1747 | casper.run(); | ||
1748 | |||
1749 | .. _casper_waitforpopup: | ||
1750 | |||
1751 | .. index:: Popups, New window, window.open, Tabs | ||
1752 | |||
1753 | ``waitForPopup()`` | ||
1754 | ------------------------------------------------------------------------------- | ||
1755 | |||
1756 | **Signature:** ``waitForPopup(String|RegExp urlPattern[, Function then, Function onTimeout, Number timeout])`` | ||
1757 | |||
1758 | .. versionadded:: 1.0 | ||
1759 | |||
1760 | Waits for a popup having its url matching the provided pattern to be opened and loaded. | ||
1761 | |||
1762 | The currently loaded popups are available in the ``Casper.popups`` array-like property:: | ||
1763 | |||
1764 | casper.start('http://foo.bar/').then(function() { | ||
1765 | this.test.assertTitle('Main page title'); | ||
1766 | this.clickLabel('Open me a popup'); | ||
1767 | }); | ||
1768 | |||
1769 | // this will wait for the popup to be opened and loaded | ||
1770 | casper.waitForPopup(/popup\.html$/, function() { | ||
1771 | this.test.assertEquals(this.popups.length, 1); | ||
1772 | }); | ||
1773 | |||
1774 | // this will set the popup DOM as the main active one only for time the | ||
1775 | // step closure being executed | ||
1776 | casper.withPopup(/popup\.html$/, function() { | ||
1777 | this.test.assertTitle('Popup title'); | ||
1778 | }); | ||
1779 | |||
1780 | // next step will automatically revert the current page to the initial one | ||
1781 | casper.then(function() { | ||
1782 | this.test.assertTitle('Main page title'); | ||
1783 | }); | ||
1784 | |||
1785 | .. index:: HTTP, Asynchronicity | ||
1786 | |||
1787 | ``waitForResource()`` | ||
1788 | ------------------------------------------------------------------------------- | ||
1789 | |||
1790 | **Signature:** ``waitForResource(Function testFx[, Function then, Function onTimeout, Number timeout])`` | ||
1791 | |||
1792 | Wait until a resource that matches the given ``testFx`` is loaded to process a next step. Uses `waitFor()`_:: | ||
1793 | |||
1794 | casper.start('http://foo.bar/'); | ||
1795 | |||
1796 | casper.waitForResource("foobar.png", function() { | ||
1797 | this.echo('foobar.png has been loaded.'); | ||
1798 | }); | ||
1799 | |||
1800 | casper.run(); | ||
1801 | |||
1802 | .. index:: selector | ||
1803 | |||
1804 | ``waitForSelector()`` | ||
1805 | ------------------------------------------------------------------------------- | ||
1806 | |||
1807 | **Signature:** ``waitForSelector(String selector[, Function then, Function onTimeout, Number timeout])`` | ||
1808 | |||
1809 | Waits until an element matching the provided :doc:`selector expression <../selectors>` exists in remote DOM to process any next step. Uses `waitFor()`_:: | ||
1810 | |||
1811 | casper.start('https://twitter.com/#!/n1k0'); | ||
1812 | |||
1813 | casper.waitForSelector('.tweet-row', function() { | ||
1814 | this.captureSelector('twitter.png', 'html'); | ||
1815 | }); | ||
1816 | |||
1817 | casper.run(); | ||
1818 | |||
1819 | .. index:: selector | ||
1820 | |||
1821 | ``waitWhileSelector()`` | ||
1822 | ------------------------------------------------------------------------------- | ||
1823 | |||
1824 | **Signature:** ``waitWhileSelector(String selector[, Function then, Function onTimeout, Number timeout])`` | ||
1825 | |||
1826 | Waits until an element matching the provided :doc:`selector expression <../selectors>` does not exist in remote DOM to process a next step. Uses `waitFor()`_:: | ||
1827 | |||
1828 | casper.start('http://foo.bar/'); | ||
1829 | |||
1830 | casper.waitWhileSelector('.selector', function() { | ||
1831 | this.echo('.selector is no more!'); | ||
1832 | }); | ||
1833 | |||
1834 | casper.run(); | ||
1835 | |||
1836 | ``waitForSelectorTextChange()`` | ||
1837 | ------------------------------------------------------------------------------- | ||
1838 | |||
1839 | **Signature:** ``waitForSelectorTextChange(String selectors[, Function then, Function onTimeout, Number timeout])`` | ||
1840 | |||
1841 | Waits until the text on an element matching the provided :doc:`selector expression <../selectors>` | ||
1842 | is changed to a different value before processing the next step. Uses `waitFor()`_:: | ||
1843 | |||
1844 | casper.start('http://foo.bar/'); | ||
1845 | |||
1846 | casper.waitForSelectorTextChange('.selector', function() { | ||
1847 | this.echo('The text on .selector has been changed.); | ||
1848 | }); | ||
1849 | |||
1850 | casper.run(); | ||
1851 | |||
1852 | ``waitForText()`` | ||
1853 | ------------------------------------------------------------------------------- | ||
1854 | |||
1855 | **Signature:** ``waitForText(String text[, Function then, Function onTimeout, Number timeout])`` | ||
1856 | .. versionadded:: 1.0 | ||
1857 | |||
1858 | Waits until the passed text is present in the page contents before processing the immediate next step. Uses `waitFor()`_:: | ||
1859 | |||
1860 | casper.start('http://why.univer.se/').waitForText("42", function() { | ||
1861 | this.echo('Found the answer.'); | ||
1862 | }); | ||
1863 | |||
1864 | casper.run(); | ||
1865 | |||
1866 | ``waitUntilVisible()`` | ||
1867 | ------------------------------------------------------------------------------- | ||
1868 | |||
1869 | **Signature:** ``waitUntilVisible(String selector[, Function then, Function onTimeout, Number timeout])`` | ||
1870 | |||
1871 | Waits until an element matching the provided :doc:`selector expression <../selectors>` is visible in the remote DOM to process a next step. Uses `waitFor()`_. | ||
1872 | |||
1873 | ``waitWhileVisible()`` | ||
1874 | ------------------------------------------------------------------------------- | ||
1875 | |||
1876 | **Signature:** ``waitWhileVisible(String selector[, Function then, Function onTimeout, Number timeout])`` | ||
1877 | |||
1878 | 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()`_. | ||
1879 | |||
1880 | ``warn()`` | ||
1881 | ------------------------------------------------------------------------------- | ||
1882 | |||
1883 | **Signature:** ``warn(String message)`` | ||
1884 | |||
1885 | Logs and prints a warning message to the standard output:: | ||
1886 | |||
1887 | casper.warn("I'm a warning message."); | ||
1888 | |||
1889 | .. note:: | ||
1890 | |||
1891 | Calling ``warn()`` will trigger the ``warn`` :ref:`event <events_filters>`. | ||
1892 | |||
1893 | .. index:: Frames, Iframes, Framesets | ||
1894 | |||
1895 | ``withFrame()`` | ||
1896 | ------------------------------------------------------------------------------- | ||
1897 | |||
1898 | **Signature:** ``withFrame(String|Number frameInfo, Function then)`` | ||
1899 | |||
1900 | .. versionadded:: 1.0 | ||
1901 | |||
1902 | Switches the main page to the frame having the name or frame index number matching the passed argument, and processes a step. | ||
1903 | |||
1904 | The page context switch only lasts until the step execution is finished:: | ||
1905 | |||
1906 | casper.start('tests/site/frames.html', function() { | ||
1907 | this.test.assertTitle('FRAMESET TITLE'); | ||
1908 | }); | ||
1909 | |||
1910 | casper.withFrame('frame1', function() { | ||
1911 | this.test.assertTitle('FRAME TITLE'); | ||
1912 | }); | ||
1913 | |||
1914 | casper.withFrame(0, function() { | ||
1915 | this.test.assertTitle('FRAME TITLE'); | ||
1916 | }); | ||
1917 | |||
1918 | casper.then(function() { | ||
1919 | this.test.assertTitle('FRAMESET TITLE'); | ||
1920 | }); | ||
1921 | |||
1922 | .. _casper_withpopup: | ||
1923 | |||
1924 | .. index:: Popups, New window, window.open, Tabs | ||
1925 | |||
1926 | ``withPopup()`` | ||
1927 | ------------------------------------------------------------------------------- | ||
1928 | |||
1929 | **Signature:** ``withPopup(Mixed popupInfo, Function then)`` | ||
1930 | |||
1931 | .. versionadded:: 1.0 | ||
1932 | |||
1933 | 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:: | ||
1934 | |||
1935 | casper.start('http://foo.bar/').then(function() { | ||
1936 | this.test.assertTitle('Main page title'); | ||
1937 | this.clickLabel('Open me a popup'); | ||
1938 | }); | ||
1939 | |||
1940 | // this will wait for the popup to be opened and loaded | ||
1941 | casper.waitForPopup(/popup\.html$/, function() { | ||
1942 | this.test.assertEquals(this.popups.length, 1); | ||
1943 | }); | ||
1944 | |||
1945 | // this will set the popup DOM as the main active one only for time the | ||
1946 | // step closure being executed | ||
1947 | casper.withPopup(/popup\.html$/, function() { | ||
1948 | this.test.assertTitle('Popup title'); | ||
1949 | }); | ||
1950 | |||
1951 | // next step will automatically revert the current page to the initial one | ||
1952 | casper.then(function() { | ||
1953 | this.test.assertTitle('Main page title'); | ||
1954 | }); | ||
1955 | |||
1956 | .. note:: | ||
1957 | |||
1958 | The currently loaded popups are available in the ``Casper.popups`` array-like property. | ||
1959 | |||
1960 | .. index:: Zoom | ||
1961 | |||
1962 | ``zoom()`` | ||
1963 | ------------------------------------------------------------------------------- | ||
1964 | |||
1965 | **Signature:** ``zoom(Number factor)`` | ||
1966 | |||
1967 | .. versionadded:: 1.0 | ||
1968 | |||
1969 | Sets the current page zoom factor:: | ||
1970 | |||
1971 | var casper = require('casper').create(); | ||
1972 | |||
1973 | casper.start().zoom(2).thenOpen('http://google.com', function() { | ||
1974 | this.capture('big-google.png'); | ||
1975 | }); | ||
1976 | |||
1977 | casper.run(); | ||
1978 |
docs/modules/clientutils.rst
0 → 100644
1 | .. _clientutils_module: | ||
2 | |||
3 | .. index:: Client utils, __utils__, DOM | ||
4 | |||
5 | ========================== | ||
6 | The ``clientutils`` module | ||
7 | ========================== | ||
8 | |||
9 | 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. | ||
10 | |||
11 | .. note:: | ||
12 | |||
13 | 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. | ||
14 | |||
15 | .. _bookmarklet: | ||
16 | |||
17 | .. index:: bookmarklet, DOM, Debugging | ||
18 | |||
19 | Bookmarklet | ||
20 | +++++++++++ | ||
21 | |||
22 | A bookmarklet is also available to help injecting Casper's client-side utilities in the DOM of your favorite browser. | ||
23 | |||
24 | Just drag the link above onto your favorites toobar; when clicking, a ``__utils__`` object will be available within the console of your browser: | ||
25 | |||
26 | .. raw:: html | ||
27 | |||
28 | <div class="bookmarklet"> | ||
29 | <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> | ||
30 | </div> | ||
31 | |||
32 | .. note:: | ||
33 | |||
34 | 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…) | ||
35 | |||
36 | |||
37 | .. _clientutils_prototype: | ||
38 | |||
39 | ``ClientUtils`` prototype | ||
40 | +++++++++++++++++++++++++ | ||
41 | |||
42 | .. index:: echo | ||
43 | |||
44 | ``echo()`` | ||
45 | ------------------------------------------------------------------------------- | ||
46 | |||
47 | **Signature:** ``echo(String message)`` | ||
48 | |||
49 | .. versionadded:: 1.0 | ||
50 | |||
51 | Print a message out to the casper console from the remote page DOM environment:: | ||
52 | |||
53 | casper.start('http://foo.ner/').thenEvaluate(function() { | ||
54 | __utils__.echo('plop'); // this will be printed to your shell at runtime | ||
55 | }); | ||
56 | |||
57 | .. index:: Base64 | ||
58 | |||
59 | ``encode()`` | ||
60 | ------------------------------------------------------------------------------- | ||
61 | |||
62 | **Signature:** ``encode(String contents)`` | ||
63 | |||
64 | 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:: | ||
65 | |||
66 | var base64; | ||
67 | casper.start('http://foo.bar/', function() { | ||
68 | base64 = this.evaluate(function() { | ||
69 | return __utils__.encode("I've been a bit cryptic recently"); | ||
70 | }); | ||
71 | }); | ||
72 | |||
73 | casper.run(function() { | ||
74 | this.echo(base64).exit(); | ||
75 | }); | ||
76 | |||
77 | .. index:: DOM | ||
78 | |||
79 | ``exists()`` | ||
80 | ------------------------------------------------------------------------------- | ||
81 | |||
82 | **Signature:** ``exists(String selector)`` | ||
83 | |||
84 | Checks if a DOM element matching a given :ref:`selector expression <selectors>` exists:: | ||
85 | |||
86 | var exists; | ||
87 | casper.start('http://foo.bar/', function() { | ||
88 | exists = this.evaluate(function() { | ||
89 | return __utils__.exists('#some_id'); | ||
90 | }); | ||
91 | }); | ||
92 | |||
93 | casper.run(function() { | ||
94 | this.echo(exists).exit(); | ||
95 | }); | ||
96 | |||
97 | ``findAll()`` | ||
98 | ------------------------------------------------------------------------------- | ||
99 | |||
100 | **Signature:** ``findAll(String selector)`` | ||
101 | |||
102 | Retrieves all DOM elements matching a given :ref:`selector expression <selectors>`:: | ||
103 | |||
104 | var links; | ||
105 | casper.start('http://foo.bar/', function() { | ||
106 | links = this.evaluate(function() { | ||
107 | var elements = __utils__.findAll('a.menu'); | ||
108 | return Array.prototype.forEach.call(elements, function(e) { | ||
109 | return e.getAttribute('href'); | ||
110 | }); | ||
111 | }); | ||
112 | }); | ||
113 | |||
114 | casper.run(function() { | ||
115 | this.echo(JSON.stringify(links)).exit(); | ||
116 | }); | ||
117 | |||
118 | ``findOne()`` | ||
119 | ------------------------------------------------------------------------------- | ||
120 | |||
121 | **Signature:** ``findOne(String selector)`` | ||
122 | |||
123 | Retrieves a single DOM element by a :ref:`selector expression <selectors>`:: | ||
124 | |||
125 | var href; | ||
126 | casper.start('http://foo.bar/', function() { | ||
127 | href = this.evaluate(function() { | ||
128 | return __utils__.findOne('#my_id').getAttribute('href'); | ||
129 | }); | ||
130 | }); | ||
131 | |||
132 | casper.run(function() { | ||
133 | this.echo(href).exit(); | ||
134 | }); | ||
135 | |||
136 | .. index:: Base64 | ||
137 | |||
138 | ``getBase64()`` | ||
139 | ------------------------------------------------------------------------------- | ||
140 | |||
141 | **Signature:** ``getBase64(String url[, String method, Object data])`` | ||
142 | |||
143 | 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:: | ||
144 | |||
145 | var logo = null; | ||
146 | casper.start('http://foo.bar/', function() { | ||
147 | logo = this.evaluate(function() { | ||
148 | var imgUrl = document.querySelector('img.logo').getAttribute('src'); | ||
149 | return __utils__.getBase64(imgUrl); | ||
150 | }); | ||
151 | }); | ||
152 | |||
153 | casper.run(function() { | ||
154 | this.echo(logo).exit(); | ||
155 | }); | ||
156 | |||
157 | .. index:: Binary | ||
158 | |||
159 | ``getBinary()`` | ||
160 | ------------------------------------------------------------------------------- | ||
161 | |||
162 | **Signature:** ``getBinary(String url[, String method, Object data])`` | ||
163 | |||
164 | 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:: | ||
165 | |||
166 | casper.start('http://foo.bar/', function() { | ||
167 | this.evaluate(function() { | ||
168 | var imgUrl = document.querySelector('img.logo').getAttribute('src'); | ||
169 | console.log(__utils__.getBinary(imgUrl)); | ||
170 | }); | ||
171 | }); | ||
172 | |||
173 | casper.run(); | ||
174 | |||
175 | ``getDocumentHeight()`` | ||
176 | ------------------------------------------------------------------------------- | ||
177 | |||
178 | **Signature:** ``getDocumentHeight()`` | ||
179 | |||
180 | .. versionadded:: 1.0 | ||
181 | |||
182 | Retrieves current document height:: | ||
183 | |||
184 | var documentHeight; | ||
185 | |||
186 | casper.start('http://google.com/', function() { | ||
187 | documentHeight = this.evaluate(function() { | ||
188 | return __utils__.getDocumentHeight(); | ||
189 | }); | ||
190 | this.echo('Document height is ' + documentHeight + 'px'); | ||
191 | }); | ||
192 | |||
193 | casper.run(); | ||
194 | |||
195 | ``getElementBounds()`` | ||
196 | ------------------------------------------------------------------------------- | ||
197 | |||
198 | **Signature:** ``getElementBounds(String selector)`` | ||
199 | |||
200 | Retrieves boundaries for a DOM elements matching the provided :ref:`selector <selectors>`. | ||
201 | |||
202 | It returns an Object with four keys: ``top``, ``left``, ``width`` and ``height``, or ``null`` if the selector doesn't exist. | ||
203 | |||
204 | ``getElementsBounds()`` | ||
205 | ------------------------------------------------------------------------------- | ||
206 | |||
207 | **Signature:** ``getElementsBounds(String selector)`` | ||
208 | |||
209 | Retrieves boundaries for all DOM element matching the provided :ref:`selector <selectors>`. | ||
210 | |||
211 | It returns an array of objects each having four keys: ``top``, ``left``, ``width`` and ``height``. | ||
212 | |||
213 | .. index:: XPath | ||
214 | |||
215 | ``getElementByXPath()`` | ||
216 | ------------------------------------------------------------------------------- | ||
217 | |||
218 | **Signature:** ``getElementByXPath(String expression [, HTMLElement scope])`` | ||
219 | |||
220 | Retrieves a single DOM element matching a given :ref:`XPath expression <selectors>`. | ||
221 | |||
222 | .. versionadded:: 1.0 | ||
223 | |||
224 | The ``scope`` argument allow to set the context for executing the XPath query:: | ||
225 | |||
226 | // will be performed against the whole document | ||
227 | __utils__.getElementByXPath('.//a'); | ||
228 | |||
229 | // will be performed against a given DOM element | ||
230 | __utils__.getElementByXPath('.//a', __utils__.findOne('div.main')); | ||
231 | |||
232 | .. index:: XPath | ||
233 | |||
234 | ``getElementsByXPath()`` | ||
235 | ------------------------------------------------------------------------------- | ||
236 | |||
237 | **Signature:** ``getElementsByXPath(String expression [, HTMLElement scope])`` | ||
238 | |||
239 | Retrieves all DOM elements matching a given :ref:`XPath expression <selectors>`, if any. | ||
240 | |||
241 | .. versionadded:: 1.0 | ||
242 | |||
243 | The ``scope`` argument allows to set the context for executing the XPath query. | ||
244 | |||
245 | .. index:: Form | ||
246 | |||
247 | ``getFieldValue()`` | ||
248 | ------------------------------------------------------------------------------- | ||
249 | |||
250 | **Signature:** ``getFieldValue(String inputName)`` | ||
251 | |||
252 | .. versionadded:: 1.0 | ||
253 | |||
254 | Retrieves the value from the field named against the ``inputNamed`` argument: | ||
255 | |||
256 | .. code-block:: html | ||
257 | |||
258 | <form> | ||
259 | <input type="text" name="plop" value="42"> | ||
260 | </form> | ||
261 | |||
262 | Using the ``getFieldValue()`` method for ``plop``:: | ||
263 | |||
264 | __utils__.getFieldValue('plop'); // 42 | ||
265 | |||
266 | .. index:: Form | ||
267 | |||
268 | ``getFormValues()`` | ||
269 | ------------------------------------------------------------------------------- | ||
270 | |||
271 | **Signature:** ``getFormValues(String selector)`` | ||
272 | |||
273 | .. versionadded:: 1.0 | ||
274 | |||
275 | Retrieves a given form and all of its field values: | ||
276 | |||
277 | .. code-block:: html | ||
278 | |||
279 | <form id="login" action="/login"> | ||
280 | <input type="text" name="username" value="foo"> | ||
281 | <input type="text" name="password" value="bar"> | ||
282 | <input type="submit"> | ||
283 | </form> | ||
284 | |||
285 | To get the form values:: | ||
286 | |||
287 | __utils__.getFormValues('form#login'); // {username: 'foo', password: 'bar'} | ||
288 | |||
289 | ``mouseEvent()`` | ||
290 | ------------------------------------------------------------------------------- | ||
291 | |||
292 | **Signature:** ``mouseEvent(String type, String selector)`` | ||
293 | |||
294 | Dispatches a mouse event to the DOM element behind the provided selector. | ||
295 | |||
296 | Supported events are ``mouseup``, ``mousedown``, ``click``, ``mousemove``, ``mouseover`` and ``mouseout``. | ||
297 | |||
298 | .. index:: XPath | ||
299 | |||
300 | ``removeElementsByXPath()`` | ||
301 | ------------------------------------------------------------------------------- | ||
302 | |||
303 | **Signature:** ``removeElementsByXPath(String expression)`` | ||
304 | |||
305 | Removes all DOM elements matching a given :ref:`XPath expression <selectors>`. | ||
306 | |||
307 | .. index:: AJAX | ||
308 | |||
309 | ``sendAJAX()`` | ||
310 | ----------------------------------------------------------------------------- | ||
311 | |||
312 | **Signature:** ``sendAJAX(String url[, String method, Object data, Boolean async])`` | ||
313 | |||
314 | .. versionadded:: 1.0 | ||
315 | |||
316 | Sends an AJAX request, using the following parameters: | ||
317 | |||
318 | - ``url``: The url to request. | ||
319 | - ``method``: The HTTP method (default: ``GET``). | ||
320 | - ``data``: Request parameters (default: ``null``). | ||
321 | - ``async``: Flag for an asynchroneous request? (default: ``false``) | ||
322 | |||
323 | .. warning:: | ||
324 | |||
325 | Don't forget to pass the ``--web-security=no`` option in your CLI call in order to perform cross-domains requests when needed:: | ||
326 | |||
327 | var data, wsurl = 'http://api.site.com/search.json'; | ||
328 | |||
329 | casper.start('http://my.site.com/', function() { | ||
330 | data = this.evaluate(function(wsurl) { | ||
331 | return JSON.parse(__utils__.sendAJAX(wsurl, 'GET', null, false)); | ||
332 | }, {wsurl: wsurl}); | ||
333 | }); | ||
334 | |||
335 | casper.then(function() { | ||
336 | require('utils').dump(data); | ||
337 | }); | ||
338 | |||
339 | ``visible()`` | ||
340 | ------------------------------------------------------------------------------- | ||
341 | |||
342 | **Signature:** ``visible(String selector)`` | ||
343 | |||
344 | Checks if an element is visible:: | ||
345 | |||
346 | var logoIsVisible = casper.evaluate(function() { | ||
347 | return __utils__.visible('h1'); | ||
348 | }); | ||
349 |
docs/modules/colorizer.rst
0 → 100644
1 | .. _colorizer_module: | ||
2 | |||
3 | .. index:: Colors, colorizer | ||
4 | |||
5 | ======================== | ||
6 | The ``colorizer`` module | ||
7 | ======================== | ||
8 | |||
9 | The ``colorizer`` module contains a ``Colorizer`` class which can generate ANSI colored strings:: | ||
10 | |||
11 | var colorizer = require('colorizer').create('Colorizer'); | ||
12 | console.log(colorizer.colorize("Hello World", "INFO")); | ||
13 | |||
14 | Though most of the times you will use it transparently using the :ref:`Casper.echo() <casper_echo>` method:: | ||
15 | |||
16 | casper.echo('an informative message', 'INFO'); // printed in green | ||
17 | casper.echo('an error message', 'ERROR'); // printed in red | ||
18 | |||
19 | Skipping CasperJS styling operations | ||
20 | ------------------------------------ | ||
21 | |||
22 | If you wish to skip the whole coloration operation and get uncolored plain text, just set the ``colorizerType`` casper option to ``Dummy``:: | ||
23 | |||
24 | var casper = require('casper').create({ | ||
25 | colorizerType: 'Dummy' | ||
26 | }); | ||
27 | |||
28 | casper.echo("Hello", "INFO"); | ||
29 | |||
30 | .. index:: Windows | ||
31 | |||
32 | .. note:: | ||
33 | |||
34 | That's especially useful if you're using CasperJS on the Windows platform, as there's no support for colored output on this platform. | ||
35 | |||
36 | .. _colorizer_styles: | ||
37 | |||
38 | .. index:: Printing styles | ||
39 | |||
40 | Available predefined styles | ||
41 | --------------------------- | ||
42 | |||
43 | Available predefined styles are: | ||
44 | |||
45 | - ``ERROR``: white text on red background | ||
46 | - ``INFO``: green text | ||
47 | - ``TRACE``: green text | ||
48 | - ``PARAMETER``: cyan text | ||
49 | - ``COMMENT``: yellow text | ||
50 | - ``WARNING``: red text | ||
51 | - ``GREEN_BAR``: white text on green background | ||
52 | - ``RED_BAR``: white text on red background | ||
53 | - ``INFO_BAR``: cyan text | ||
54 | - ``WARN_BAR``: white text on orange background | ||
55 | |||
56 | Here's a sample output of what it can look like: | ||
57 | |||
58 | .. figure:: ../_static/images/colorizer.png | ||
59 | :align: center | ||
60 | |||
61 | ``colorize()`` | ||
62 | ------------------------------------------------------------------------------- | ||
63 | |||
64 | **Signature:** ``colorize(String text, String styleName)`` | ||
65 | |||
66 | Computes a colored version of the provided text string using a given predefined style:: | ||
67 | |||
68 | var colorizer = require('colorizer').create(); | ||
69 | console.log(colorizer.colorize("I'm a red error", "ERROR")); | ||
70 | |||
71 | .. note:: | ||
72 | |||
73 | Most of the time you won't have to use a ``Colorizer`` instance directly as CasperJS provides all the necessary methods. | ||
74 | |||
75 | See the list of the :ref:`predefined styles available <colorizer_styles>`. | ||
76 | |||
77 | ``format()`` | ||
78 | ------------------------------------------------------------------------------- | ||
79 | |||
80 | **Signature:** ``format(String text, Object style)`` | ||
81 | |||
82 | Formats a text string using the provided style definition. A style definition is a standard javascript ``Object`` instance which can define the following properties: | ||
83 | |||
84 | - String ``bg``: background color name | ||
85 | - String ``fg``: foreground color name | ||
86 | - Boolean ``bold``: apply bold formatting | ||
87 | - Boolean ``underscore``: apply underline formatting | ||
88 | - Boolean ``blink``: apply blink formatting | ||
89 | - Boolean ``reverse``: apply reverse formatting | ||
90 | - Boolean ``conceal``: apply conceal formatting | ||
91 | |||
92 | .. note:: | ||
93 | |||
94 | Available color names are ``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan`` and ``white``:: | ||
95 | |||
96 | var colorizer = require('colorizer').create(); | ||
97 | colorizer.format("We all live in a yellow submarine", { | ||
98 | bg: 'yellow', | ||
99 | fg: 'blue', | ||
100 | bold: true | ||
101 | }); | ||
102 |
docs/modules/index.rst
0 → 100644
1 | .. _modules_index: | ||
2 | |||
3 | .. index:: modules | ||
4 | |||
5 | ================= | ||
6 | API Documentation | ||
7 | ================= | ||
8 | |||
9 | 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>`_. | ||
10 | |||
11 | .. toctree:: | ||
12 | :glob: | ||
13 | |||
14 | * |
docs/modules/tester.rst
0 → 100644
1 | .. _tester_module: | ||
2 | |||
3 | .. index:: Testing | ||
4 | |||
5 | ===================== | ||
6 | The ``tester`` module | ||
7 | ===================== | ||
8 | |||
9 | 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. | ||
10 | |||
11 | .. note:: | ||
12 | |||
13 | 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/>`_. | ||
14 | |||
15 | |||
16 | The ``Tester`` prototype | ||
17 | ++++++++++++++++++++++++ | ||
18 | |||
19 | ``assert()`` | ||
20 | ------------------------------------------------------------------------------- | ||
21 | |||
22 | **Signature:** ``assert(Boolean condition[, String message])`` | ||
23 | |||
24 | Asserts that the provided condition strictly resolves to a boolean ``true``:: | ||
25 | |||
26 | casper.test.assert(true, "true's true"); | ||
27 | casper.test.assert(!false, "truth is out"); | ||
28 | |||
29 | .. seealso:: `assertNot()`_ | ||
30 | |||
31 | .. index:: DOM | ||
32 | |||
33 | ``assertDoesntExist()`` | ||
34 | ------------------------------------------------------------------------------- | ||
35 | |||
36 | **Signature:** ``assertDoesntExist(String selector[, String message])`` | ||
37 | |||
38 | Asserts that an element matching the provided :ref:`selector expression <selectors>` doesn't exists within the remote DOM environment:: | ||
39 | |||
40 | casper.test.begin('assertDoesntExist() tests', 1, function(test) { | ||
41 | casper.start().then(function() { | ||
42 | this.setContent('<div class="heaven"></div>'); | ||
43 | test.assertDoesntExist('.taxes'); | ||
44 | }).run(function() { | ||
45 | test.done(); | ||
46 | }); | ||
47 | }); | ||
48 | |||
49 | .. seealso:: `assertExists()`_ | ||
50 | |||
51 | ``assertEquals()`` | ||
52 | ------------------------------------------------------------------------------- | ||
53 | |||
54 | **Signature:** ``assertEquals(mixed testValue, mixed expected[, String message])`` | ||
55 | |||
56 | Asserts that two values are strictly equivalent:: | ||
57 | |||
58 | casper.test.begin('assertEquals() tests', 3, function(test) { | ||
59 | test.assertEquals(1 + 1, 2); | ||
60 | test.assertEquals([1, 2, 3], [1, 2, 3]); | ||
61 | test.assertEquals({a: 1, b: 2}, {a: 1, b: 2}); | ||
62 | test.done(); | ||
63 | }); | ||
64 | |||
65 | .. seealso:: `assertNotEquals()`_ | ||
66 | |||
67 | .. index:: evaluate | ||
68 | |||
69 | ``assertEval()`` | ||
70 | ------------------------------------------------------------------------------- | ||
71 | |||
72 | **Signature:** ``assertEval(Function fn[, String message, Mixed arguments])`` | ||
73 | |||
74 | Asserts that a :ref:`code evaluation in remote DOM <casper_evaluate>` strictly resolves to a boolean ``true``:: | ||
75 | |||
76 | casper.test.begin('assertEval() tests', 1, function(test) { | ||
77 | casper.start().then(function() { | ||
78 | this.setContent('<div class="heaven">beer</div>'); | ||
79 | test.assertEval(function() { | ||
80 | return __utils__.findOne('.heaven').textContent === 'beer'; | ||
81 | }); | ||
82 | }).run(function() { | ||
83 | test.done(); | ||
84 | }); | ||
85 | }); | ||
86 | |||
87 | ``assertEvalEquals()`` | ||
88 | ------------------------------------------------------------------------------- | ||
89 | |||
90 | **Signature:** ``assertEvalEquals(Function fn, mixed expected[, String message, Mixed arguments])`` | ||
91 | |||
92 | Asserts that the result of a :ref:`code evaluation in remote DOM <casper_evaluate>` strictly equals to the expected value:: | ||
93 | |||
94 | casper.test.begin('assertEvalEquals() tests', 1, function(test) { | ||
95 | casper.start().then(function() { | ||
96 | this.setContent('<div class="heaven">beer</div>'); | ||
97 | test.assertEvalEquals(function() { | ||
98 | return __utils__.findOne('.heaven').textContent; | ||
99 | }, 'beer'); | ||
100 | }).run(function() { | ||
101 | test.done(); | ||
102 | }); | ||
103 | }); | ||
104 | |||
105 | .. _tester_assertelementcount: | ||
106 | |||
107 | ``assertElementCount()`` | ||
108 | ------------------------------------------------------------------------------- | ||
109 | |||
110 | **Signature:** ``assertElementCount(String selector, Number count[, String message])`` | ||
111 | |||
112 | Asserts that a :ref:`selector expression <selectors>` matches a given number of elements:: | ||
113 | |||
114 | casper.test.begin('assertElementCount() tests', 3, function(test) { | ||
115 | casper.start().then(function() { | ||
116 | this.page.content = '<ul><li>1</li><li>2</li><li>3</li></ul>'; | ||
117 | test.assertElementCount('ul', 1); | ||
118 | test.assertElementCount('li', 3); | ||
119 | test.assertElementCount('address', 0); | ||
120 | }).run(function() { | ||
121 | test.done(); | ||
122 | }); | ||
123 | }); | ||
124 | |||
125 | .. index:: DOM | ||
126 | |||
127 | ``assertExists()`` | ||
128 | ------------------------------------------------------------------------------- | ||
129 | |||
130 | **Signature:** ``assertExists(String selector[, String message])`` | ||
131 | |||
132 | Asserts that an element matching the provided :ref:`selector expression <selectors>` exists in remote DOM environment:: | ||
133 | |||
134 | casper.test.begin('assertExists() tests', 1, function(test) { | ||
135 | casper.start().then(function() { | ||
136 | this.setContent('<div class="heaven">beer</div>'); | ||
137 | test.assertExists('.heaven'); | ||
138 | }).run(function() { | ||
139 | test.done(); | ||
140 | }); | ||
141 | }); | ||
142 | |||
143 | .. seealso:: `assertDoesntExist()`_ | ||
144 | |||
145 | .. index:: falsiness | ||
146 | |||
147 | ``assertFalsy()`` | ||
148 | ------------------------------------------------------------------------------- | ||
149 | |||
150 | **Signature:** ``assertFalsy(Mixed subject[, String message])`` | ||
151 | |||
152 | .. versionadded:: 1.0 | ||
153 | |||
154 | Asserts that a given subject is `falsy <http://11heavens.com/falsy-and-truthy-in-javascript>`_. | ||
155 | |||
156 | .. seealso:: `assertTruthy()`_ | ||
157 | |||
158 | .. index:: Form | ||
159 | |||
160 | ``assertField()`` | ||
161 | ------------------------------------------------------------------------------- | ||
162 | |||
163 | **Signature:** ``assertField(String inputName, String expected[, String message])`` | ||
164 | |||
165 | Asserts that a given form field has the provided value:: | ||
166 | |||
167 | casper.test.begin('assertField() tests', 1, function(test) { | ||
168 | casper.start('http://www.google.fr/', function() { | ||
169 | this.fill('form[name="gs"]', { q: 'plop' }, false); | ||
170 | test.assertField('q', 'plop'); | ||
171 | }).run(function() { | ||
172 | test.done(); | ||
173 | }); | ||
174 | }); | ||
175 | |||
176 | .. versionadded:: 1.0 | ||
177 | |||
178 | This also works with any input type: ``select``, ``textarea``, etc. | ||
179 | |||
180 | .. index:: HTTP, HTTP Status Code | ||
181 | |||
182 | ``assertHttpStatus()`` | ||
183 | ------------------------------------------------------------------------------- | ||
184 | |||
185 | **Signature:** ``assertHttpStatus(Number status[, String message])`` | ||
186 | |||
187 | Asserts that current `HTTP status code <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ is the same as the one passed as argument:: | ||
188 | |||
189 | casper.test.begin('casperjs.org is up and running', 1, function(test) { | ||
190 | casper.start('http://casperjs.org/', function() { | ||
191 | test.assertHttpStatus(200); | ||
192 | }).run(function() { | ||
193 | test.done(); | ||
194 | }); | ||
195 | }); | ||
196 | |||
197 | ``assertMatch()`` | ||
198 | ------------------------------------------------------------------------------- | ||
199 | |||
200 | **Signature:** ``assertMatch(mixed subject, RegExp pattern[, String message])`` | ||
201 | |||
202 | Asserts that a provided string matches a provided javascript ``RegExp`` pattern:: | ||
203 | |||
204 | casper.test.assertMatch('Chuck Norris', /^chuck/i, 'Chuck Norris' first name is Chuck'); | ||
205 | |||
206 | .. seealso:: | ||
207 | |||
208 | - `assertUrlMatch()`_ | ||
209 | - `assertTitleMatch()`_ | ||
210 | |||
211 | ``assertNot()`` | ||
212 | ------------------------------------------------------------------------------- | ||
213 | |||
214 | **Signature:** ``assertNot(mixed subject[, String message])`` | ||
215 | |||
216 | Asserts that the passed subject resolves to some `falsy value <http://11heavens.com/falsy-and-truthy-in-javascript>`_:: | ||
217 | |||
218 | casper.test.assertNot(false, "Universe is still operational"); | ||
219 | |||
220 | .. seealso:: `assert()`_ | ||
221 | |||
222 | ``assertNotEquals()`` | ||
223 | ------------------------------------------------------------------------------- | ||
224 | |||
225 | **Signature:** ``assertNotEquals(mixed testValue, mixed expected[, String message])`` | ||
226 | |||
227 | .. versionadded:: 0.6.7 | ||
228 | |||
229 | Asserts that two values are **not** strictly equals:: | ||
230 | |||
231 | casper.test.assertNotEquals(true, "true"); | ||
232 | |||
233 | .. seealso:: `assertEquals()`_ | ||
234 | |||
235 | ``assertNotVisible()`` | ||
236 | ------------------------------------------------------------------------------- | ||
237 | |||
238 | **Signature:** ``assertNotVisible(String selector[, String message])`` | ||
239 | |||
240 | Asserts that the element matching the provided :ref:`selector expression <selectors>` is not visible:: | ||
241 | |||
242 | casper.test.begin('assertNotVisible() tests', 1, function(test) { | ||
243 | casper.start().then(function() { | ||
244 | this.setContent('<div class=".foo" style="display:none>boo</div>'); | ||
245 | test.assertNotVisible('.foo'); | ||
246 | }).run(function() { | ||
247 | test.done(); | ||
248 | }); | ||
249 | }); | ||
250 | |||
251 | .. seealso:: `assertVisible()`_ | ||
252 | |||
253 | .. index:: error | ||
254 | |||
255 | ``assertRaises()`` | ||
256 | ------------------------------------------------------------------------------- | ||
257 | |||
258 | **Signature:** ``assertRaises(Function fn, Array args[, String message])`` | ||
259 | |||
260 | Asserts that the provided function called with the given parameters raises a javascript ``Error``:: | ||
261 | |||
262 | casper.test.assertRaises(function(throwIt) { | ||
263 | if (throwIt) { | ||
264 | throw new Error('thrown'); | ||
265 | } | ||
266 | }, [true], 'Error has been raised.'); | ||
267 | |||
268 | casper.test.assertRaises(function(throwIt) { | ||
269 | if (throwIt) { | ||
270 | throw new Error('thrown'); | ||
271 | } | ||
272 | }, [false], 'Error has been raised.'); // fails | ||
273 | |||
274 | ``assertSelectorDoesntHaveText()`` | ||
275 | ------------------------------------------------------------------------------- | ||
276 | |||
277 | **Signature:** ``assertSelectorDoesntHaveText(String selector, String text[, String message])`` | ||
278 | |||
279 | Asserts that given text does not exist in all the elements matching the provided :ref:`selector expression <selectors>`:: | ||
280 | |||
281 | casper.test.begin('assertSelectorDoesntHaveText() tests', 1, function(test) { | ||
282 | casper.start('http://google.com/', function() { | ||
283 | test.assertSelectorDoesntHaveText('title', 'Yahoo!'); | ||
284 | }).run(function() { | ||
285 | test.done(); | ||
286 | }); | ||
287 | }); | ||
288 | |||
289 | .. seealso:: `assertSelectorHasText()`_ | ||
290 | |||
291 | .. index:: selector, DOM | ||
292 | |||
293 | ``assertSelectorHasText()`` | ||
294 | ------------------------------------------------------------------------------- | ||
295 | |||
296 | **Signature:** ``assertSelectorHasText(String selector, String text[, String message])`` | ||
297 | |||
298 | Asserts that given text exists in elements matching the provided :ref:`selector expression <selectors>`:: | ||
299 | |||
300 | casper.test.begin('assertSelectorHasText() tests', 1, function(test) { | ||
301 | casper.start('http://google.com/', function() { | ||
302 | test.assertSelectorDoesntHaveText('title', 'Google'); | ||
303 | }).run(function() { | ||
304 | test.done(); | ||
305 | }); | ||
306 | }); | ||
307 | |||
308 | .. seealso:: `assertSelectorDoesntHaveText()`_ | ||
309 | |||
310 | .. index:: HTTP | ||
311 | |||
312 | ``assertResourceExists()`` | ||
313 | ------------------------------------------------------------------------------- | ||
314 | |||
315 | **Signature:** ``assertResourceExists(Function testFx[, String message])`` | ||
316 | |||
317 | The ``testFx`` function is executed against all loaded assets and the test passes when at least one resource matches:: | ||
318 | |||
319 | casper.test.begin('assertResourceExists() tests', 1, function(test) { | ||
320 | casper.start('http://www.google.fr/', function() { | ||
321 | test.assertResourceExists(function(resource) { | ||
322 | return resource.url.match('logo3w.png'); | ||
323 | }); | ||
324 | }).run(function() { | ||
325 | test.done(); | ||
326 | }); | ||
327 | }); | ||
328 | |||
329 | Shorter:: | ||
330 | |||
331 | casper.test.begin('assertResourceExists() tests', 1, function(test) { | ||
332 | casper.start('http://www.google.fr/', function() { | ||
333 | test.assertResourceExists('logo3w.png'); | ||
334 | }).run(function() { | ||
335 | test.done(); | ||
336 | }); | ||
337 | }); | ||
338 | |||
339 | .. hint:: | ||
340 | |||
341 | Check the documentation for :ref:`Casper.resourceExists() <casper_resourceexists>`. | ||
342 | |||
343 | ``assertTextExists()`` | ||
344 | ------------------------------------------------------------------------------- | ||
345 | |||
346 | **Signature:** ``assertTextExists(String expected[, String message])`` | ||
347 | |||
348 | Asserts that body **plain text content** contains the given string:: | ||
349 | |||
350 | casper.test.begin('assertTextExists() tests', 1, function(test) { | ||
351 | casper.start('http://www.google.fr/', function() { | ||
352 | test.assertTextExists('google', 'page body contains "google"'); | ||
353 | }).run(function() { | ||
354 | test.done(); | ||
355 | }); | ||
356 | }); | ||
357 | |||
358 | .. seealso:: `assertTextDoesntExist()`_ | ||
359 | |||
360 | ``assertTextDoesntExist()`` | ||
361 | ------------------------------------------------------------------------------- | ||
362 | |||
363 | **Signature:** ``assertTextDoesntExist(String unexpected[, String message])`` | ||
364 | |||
365 | .. versionadded:: 1.0 | ||
366 | |||
367 | Asserts that body **plain text content** doesn't contain the given string:: | ||
368 | |||
369 | casper.test.begin('assertTextDoesntExist() tests', 1, function(test) { | ||
370 | casper.start('http://www.google.fr/', function() { | ||
371 | test.assertTextDoesntExist('bing', 'page body does not contain "bing"'); | ||
372 | }).run(function() { | ||
373 | test.done(); | ||
374 | }); | ||
375 | }); | ||
376 | |||
377 | .. seealso:: `assertTextExists()`_ | ||
378 | |||
379 | ``assertTitle()`` | ||
380 | ------------------------------------------------------------------------------- | ||
381 | |||
382 | **Signature:** ``assertTitle(String expected[, String message])`` | ||
383 | |||
384 | Asserts that title of the remote page equals to the expected one:: | ||
385 | |||
386 | casper.test.begin('assertTitle() tests', 1, function(test) { | ||
387 | casper.start('http://www.google.fr/', function() { | ||
388 | test.assertTitle('Google', 'google.fr has the correct title'); | ||
389 | }).run(function() { | ||
390 | test.done(); | ||
391 | }); | ||
392 | }); | ||
393 | |||
394 | .. seealso:: `assertTitleMatch()`_ | ||
395 | |||
396 | ``assertTitleMatch()`` | ||
397 | ------------------------------------------------------------------------------- | ||
398 | |||
399 | **Signature:** ``assertTitleMatch(RegExp pattern[, String message])`` | ||
400 | |||
401 | Asserts that title of the remote page matches the provided RegExp pattern:: | ||
402 | |||
403 | casper.test.begin('assertTitleMatch() tests', 1, function(test) { | ||
404 | casper.start('http://www.google.fr/', function() { | ||
405 | test.assertTitleMatch(/Google/, 'google.fr has a quite predictable title'); | ||
406 | }).run(function() { | ||
407 | test.done(); | ||
408 | }); | ||
409 | }); | ||
410 | |||
411 | .. seealso:: `assertTitle()`_ | ||
412 | |||
413 | .. index:: truthiness | ||
414 | |||
415 | ``assertTruthy()`` | ||
416 | ------------------------------------------------------------------------------- | ||
417 | |||
418 | **Signature:** ``assertTruthy(Mixed subject[, String message])`` | ||
419 | |||
420 | .. versionadded:: 1.0 | ||
421 | |||
422 | Asserts that a given subject is `truthy <http://11heavens.com/falsy-and-truthy-in-javascript>`_. | ||
423 | |||
424 | .. seealso:: `assertFalsy()`_ | ||
425 | |||
426 | .. index:: Type | ||
427 | |||
428 | ``assertType()`` | ||
429 | ------------------------------------------------------------------------------- | ||
430 | |||
431 | **Signature:** ``assertType(mixed input, String type[, String message])`` | ||
432 | |||
433 | Asserts that the provided input is of the given type:: | ||
434 | |||
435 | casper.test.begin('assertType() tests', 1, function suite(test) { | ||
436 | test.assertType(42, "number", "Okay, 42 is a number"); | ||
437 | test.assertType([1, 2, 3], "array", "We can test for arrays too!"); | ||
438 | test.done(); | ||
439 | }); | ||
440 | |||
441 | .. note:: Type names are always expressed in lower case. | ||
442 | |||
443 | .. index:: URL | ||
444 | |||
445 | ``assertUrlMatch()`` | ||
446 | ------------------------------------------------------------------------------- | ||
447 | |||
448 | **Signature:** ``assertUrlMatch(Regexp pattern[, String message])`` | ||
449 | |||
450 | Asserts that the current page url matches the provided RegExp pattern:: | ||
451 | |||
452 | casper.test.begin('assertUrlMatch() tests', 1, function(test) { | ||
453 | casper.start('http://www.google.fr/', function() { | ||
454 | test.assertUrlMatch(/^http:\/\//', 'google.fr is served in http://'); | ||
455 | }).run(function() { | ||
456 | test.done(); | ||
457 | }); | ||
458 | }); | ||
459 | |||
460 | .. index:: DOM | ||
461 | |||
462 | ``assertVisible()`` | ||
463 | ------------------------------------------------------------------------------- | ||
464 | |||
465 | **Signature:** ``assertVisible(String selector[, String message])`` | ||
466 | |||
467 | Asserts that the element matching the provided :ref:`selector expression <selectors>` is visible:: | ||
468 | |||
469 | casper.test.begin('assertVisible() tests', 1, function(test) { | ||
470 | casper.start('http://www.google.fr/', function() { | ||
471 | test.assertVisible('h1'); | ||
472 | }).run(function() { | ||
473 | test.done(); | ||
474 | }); | ||
475 | }); | ||
476 | |||
477 | .. seealso:: `assertNotVisible()`_ | ||
478 | |||
479 | .. _tester_begin: | ||
480 | |||
481 | .. index:: Test suite, planned tests, Asynchronicity, Termination | ||
482 | |||
483 | ``begin()`` | ||
484 | ------------------------------------------------------------------------------- | ||
485 | |||
486 | **Signatures:** | ||
487 | |||
488 | - ``begin(String description, Number planned, Function suite)`` | ||
489 | - ``begin(String description, Function suite)`` | ||
490 | - ``begin(String description, Number planned, Object config)`` | ||
491 | - ``begin(String description, Object config)`` | ||
492 | |||
493 | .. versionadded:: 1.1 | ||
494 | |||
495 | Starts a suite of ``<planned>`` tests (if defined). The ``suite`` callback will get the current ``Tester`` instance as its first argument:: | ||
496 | |||
497 | function Cow() { | ||
498 | this.mowed = false; | ||
499 | this.moo = function moo() { | ||
500 | this.mowed = true; // mootable state: don't do that | ||
501 | return 'moo!'; | ||
502 | }; | ||
503 | } | ||
504 | |||
505 | // unit style synchronous test case | ||
506 | casper.test.begin('Cow can moo', 2, function suite(test) { | ||
507 | var cow = new Cow(); | ||
508 | test.assertEquals(cow.moo(), 'moo!'); | ||
509 | test.assert(cow.mowed); | ||
510 | test.done(); | ||
511 | }); | ||
512 | |||
513 | .. note:: | ||
514 | |||
515 | 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. | ||
516 | |||
517 | A more asynchronous example:: | ||
518 | |||
519 | casper.test.begin('Casperjs.org is navigable', 2, function suite(test) { | ||
520 | casper.start('http://casperjs.org/', function() { | ||
521 | test.assertTitleMatches(/casperjs/i); | ||
522 | this.clickLabel('Testing'); | ||
523 | }); | ||
524 | |||
525 | casper.then(function() { | ||
526 | test.assertUrlMatches(/testing\.html$/); | ||
527 | }); | ||
528 | |||
529 | casper.run(function() { | ||
530 | test.done(); | ||
531 | }); | ||
532 | }); | ||
533 | |||
534 | .. important:: | ||
535 | |||
536 | `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. | ||
537 | |||
538 | .. seealso:: `done()`_ | ||
539 | |||
540 | ``Tester#begin()`` also accepts a test configuration object, so you can add ``setUp()`` and ``tearDown()`` methods:: | ||
541 | |||
542 | // cow-test.js | ||
543 | casper.test.begin('Cow can moo', 2, { | ||
544 | setUp: function(test) { | ||
545 | this.cow = new Cow(); | ||
546 | }, | ||
547 | |||
548 | tearDown: function(test) { | ||
549 | this.cow.destroy(); | ||
550 | }, | ||
551 | |||
552 | test: function(test) { | ||
553 | test.assertEquals(this.cow.moo(), 'moo!'); | ||
554 | test.assert(this.cow.mowed); | ||
555 | test.done(); | ||
556 | } | ||
557 | }); | ||
558 | |||
559 | .. index:: Colors | ||
560 | |||
561 | ``colorize()`` | ||
562 | ------------------------------------------------------------------------------- | ||
563 | |||
564 | **Signature:** ``colorize(String message, String style)`` | ||
565 | |||
566 | Render a colorized output. Basically a proxy method for ``Casper.Colorizer#colorize()``. | ||
567 | |||
568 | ``comment()`` | ||
569 | ------------------------------------------------------------------------------- | ||
570 | |||
571 | **Signature:** ``comment(String message)`` | ||
572 | |||
573 | Writes a comment-style formatted message to stdout:: | ||
574 | |||
575 | casper.test.comment("Hi, I'm a comment"); | ||
576 | |||
577 | .. _tester_done: | ||
578 | |||
579 | .. index:: Test suite, Asynchronicity, Termination, done() | ||
580 | |||
581 | ``done()`` | ||
582 | ------------------------------------------------------------------------------- | ||
583 | |||
584 | **Signature:** ``done()`` | ||
585 | |||
586 | .. versionchanged:: 1.1 ``planned`` parameter is deprecated | ||
587 | |||
588 | Flag a test suite started with `begin()`_ as processed:: | ||
589 | |||
590 | casper.test.begin('my test suite', 2, function(test) { | ||
591 | test.assert(true); | ||
592 | test.assertNot(false); | ||
593 | test.done(); | ||
594 | }); | ||
595 | |||
596 | More asynchronously:: | ||
597 | |||
598 | casper.test.begin('Casperjs.org is navigable', 2, function suite(test) { | ||
599 | casper.start('http://casperjs.org/', function() { | ||
600 | test.assertTitleMatches(/casperjs/i); | ||
601 | this.clickLabel('Testing'); | ||
602 | }); | ||
603 | |||
604 | casper.then(function() { | ||
605 | test.assertUrlMatches(/testing\.html$/); | ||
606 | }); | ||
607 | |||
608 | casper.run(function() { | ||
609 | test.done(); | ||
610 | }); | ||
611 | }); | ||
612 | |||
613 | .. seealso:: `begin()`_ | ||
614 | |||
615 | ``error()`` | ||
616 | ------------------------------------------------------------------------------- | ||
617 | |||
618 | **Signature:** ``error(String message)`` | ||
619 | |||
620 | Writes an error-style formatted message to stdout:: | ||
621 | |||
622 | casper.test.error("Hi, I'm an error"); | ||
623 | |||
624 | .. index:: Test failure | ||
625 | |||
626 | ``fail()`` | ||
627 | ------------------------------------------------------------------------------- | ||
628 | |||
629 | **Signature:** ``fail(String message)`` | ||
630 | |||
631 | Adds a failed test entry to the stack:: | ||
632 | |||
633 | casper.test.fail("Georges W. Bush"); | ||
634 | |||
635 | .. seealso:: `pass()`_ | ||
636 | |||
637 | ``formatMessage()`` | ||
638 | ------------------------------------------------------------------------------- | ||
639 | |||
640 | **Signature:** ``formatMessage(String message, String style)`` | ||
641 | |||
642 | Formats a message to highlight some parts of it. Only used internally by the tester. | ||
643 | |||
644 | ``getFailures()`` | ||
645 | ------------------------------------------------------------------------------- | ||
646 | |||
647 | **Signature:** ``getFailures()`` | ||
648 | |||
649 | .. versionadded:: 1.0 | ||
650 | |||
651 | Retrieves failures for current test suite:: | ||
652 | |||
653 | casper.test.assertEquals(true, false); | ||
654 | require('utils').dump(casper.test.getFailures()); | ||
655 | casper.test.done(); | ||
656 | |||
657 | That will give something like this: | ||
658 | |||
659 | .. code-block:: text | ||
660 | |||
661 | $ casperjs test test-getFailures.js | ||
662 | Test file: test-getFailures.js | ||
663 | FAIL Subject equals the expected value | ||
664 | # type: assertEquals | ||
665 | # subject: true | ||
666 | # expected: false | ||
667 | { | ||
668 | "length": 1, | ||
669 | "cases": [ | ||
670 | { | ||
671 | "success": false, | ||
672 | "type": "assertEquals", | ||
673 | "standard": "Subject equals the expected value", | ||
674 | "file": "test-getFailures.js", | ||
675 | "values": { | ||
676 | "subject": true, | ||
677 | "expected": false | ||
678 | } | ||
679 | } | ||
680 | ] | ||
681 | } | ||
682 | FAIL 1 tests executed, 0 passed, 1 failed. | ||
683 | |||
684 | Details for the 1 failed test: | ||
685 | |||
686 | In c.js:0 | ||
687 | assertEquals: Subject equals the expected value | ||
688 | |||
689 | ``getPasses()`` | ||
690 | ------------------------------------------------------------------------------- | ||
691 | |||
692 | **Signature:** ``getPasses()`` | ||
693 | |||
694 | .. versionadded:: 1.0 | ||
695 | |||
696 | Retrieves a report for successful test cases in the current test suite:: | ||
697 | |||
698 | casper.test.assertEquals(true, true); | ||
699 | require('utils').dump(casper.test.getPasses()); | ||
700 | casper.test.done(); | ||
701 | |||
702 | That will give something like this:: | ||
703 | |||
704 | $ casperjs test test-getPasses.js | ||
705 | Test file: test-getPasses.js | ||
706 | PASS Subject equals the expected value | ||
707 | { | ||
708 | "length": 1, | ||
709 | "cases": [ | ||
710 | { | ||
711 | "success": true, | ||
712 | "type": "assertEquals", | ||
713 | "standard": "Subject equals the expected value", | ||
714 | "file": "test-getPasses.js", | ||
715 | "values": { | ||
716 | "subject": true, | ||
717 | "expected": true | ||
718 | } | ||
719 | } | ||
720 | ] | ||
721 | } | ||
722 | PASS 1 tests executed, 1 passed, 0 failed. | ||
723 | |||
724 | ``info()`` | ||
725 | ------------------------------------------------------------------------------- | ||
726 | |||
727 | **Signature:** ``info(String message)`` | ||
728 | |||
729 | Writes an info-style formatted message to stdout:: | ||
730 | |||
731 | casper.test.info("Hi, I'm an informative message."); | ||
732 | |||
733 | .. index:: Test success | ||
734 | |||
735 | ``pass()`` | ||
736 | ------------------------------------------------------------------------------- | ||
737 | |||
738 | **Signature:** ``pass(String message)`` | ||
739 | |||
740 | Adds a successful test entry to the stack:: | ||
741 | |||
742 | casper.test.pass("Barrack Obama"); | ||
743 | |||
744 | .. seealso:: `fail()`_ | ||
745 | |||
746 | ``renderResults()`` | ||
747 | ------------------------------------------------------------------------------- | ||
748 | |||
749 | **Signature:** ``renderResults(Boolean exit, Number status, String save)`` | ||
750 | |||
751 | Render test results, save results in an XUnit formatted file, and optionally exits phantomjs:: | ||
752 | |||
753 | casper.test.renderResults(true, 0, 'test-results.xml'); | ||
754 | |||
755 | .. note:: | ||
756 | |||
757 | 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. | ||
758 | |||
759 | ``skip()`` | ||
760 | ------------------------------------------------------------------------------- | ||
761 | |||
762 | **Signature:** ``skip(Number nb, String message)`` | ||
763 | |||
764 | Skips a given number of planned tests:: | ||
765 | |||
766 | casper.test.begin('Skip tests', 4, function(test) { | ||
767 | test.assert(true, 'First test executed'); | ||
768 | test.assert(true, 'Second test executed'); | ||
769 | test.skip(2, 'Two tests skipped'); | ||
770 | test.done(); | ||
771 | }); |
docs/modules/utils.rst
0 → 100644
1 | .. _utils_module: | ||
2 | |||
3 | .. index:: Utilities, Helpers | ||
4 | |||
5 | ==================== | ||
6 | The ``utils`` module | ||
7 | ==================== | ||
8 | |||
9 | This module provides simple helper functions, some of them being very specific to CasperJS though. | ||
10 | |||
11 | Functions reference | ||
12 | +++++++++++++++++++ | ||
13 | |||
14 | Usage is pretty much straightforward:: | ||
15 | |||
16 | var utils = require('utils'); | ||
17 | |||
18 | utils.dump({plop: 42}); | ||
19 | |||
20 | ``betterTypeOf()`` | ||
21 | ------------------------------------------------------------------------------- | ||
22 | |||
23 | **Signature:** ``betterTypeOf(input)`` | ||
24 | |||
25 | Provides a better ``typeof`` operator equivalent, eg. able to retrieve the ``Array`` type. | ||
26 | |||
27 | .. index:: dump, Serialization, Debugging, JSON | ||
28 | |||
29 | .. _utils_dump: | ||
30 | |||
31 | ``dump()`` | ||
32 | ------------------------------------------------------------------------------- | ||
33 | |||
34 | **Signature:** ``dump(value)`` | ||
35 | |||
36 | Dumps a JSON_ representation of passed argument to the standard output. Useful for :ref:`debugging your scripts <debugging_dump>`. | ||
37 | |||
38 | ``fileExt()`` | ||
39 | ------------------------------------------------------------------------------- | ||
40 | |||
41 | **Signature:** ``fileExt(file)`` | ||
42 | |||
43 | Retrieves the extension of passed filename. | ||
44 | |||
45 | ``fillBlanks()`` | ||
46 | ------------------------------------------------------------------------------- | ||
47 | |||
48 | **Signature:** ``fillBlanks(text, pad)`` | ||
49 | |||
50 | Fills a string with trailing spaces to match ``pad`` length. | ||
51 | |||
52 | .. index:: String formatting | ||
53 | |||
54 | ``format()`` | ||
55 | ------------------------------------------------------------------------------- | ||
56 | |||
57 | **Signature:** ``format(f)`` | ||
58 | |||
59 | Formats a string against passed args. ``sprintf`` equivalent. | ||
60 | |||
61 | .. note:: | ||
62 | |||
63 | This is a port of nodejs ``util.format()``. | ||
64 | |||
65 | ``getPropertyPath()`` | ||
66 | ------------------------------------------------------------------------------- | ||
67 | |||
68 | **Signature:** ``getPropertyPath(Object obj, String path)`` | ||
69 | |||
70 | .. versionadded:: 1.0 | ||
71 | |||
72 | Retrieves the value of an Object foreign property using a dot-separated path string:: | ||
73 | |||
74 | var account = { | ||
75 | username: 'chuck', | ||
76 | skills: { | ||
77 | kick: { | ||
78 | roundhouse: true | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | utils.getPropertyPath(account, 'skills.kick.roundhouse'); // true | ||
83 | |||
84 | .. warning:: | ||
85 | |||
86 | This function doesn't handle object key names containing a dot. | ||
87 | |||
88 | .. index:: inheritance | ||
89 | |||
90 | ``inherits()`` | ||
91 | ------------------------------------------------------------------------------- | ||
92 | |||
93 | **Signature:** ``inherits(ctor, superCtor)`` | ||
94 | |||
95 | Makes a constructor inheriting from another. Useful for subclassing and :doc:`extending <../extending>`. | ||
96 | |||
97 | .. note:: | ||
98 | |||
99 | This is a port of nodejs ``util.inherits()``. | ||
100 | |||
101 | ``isArray()`` | ||
102 | ------------------------------------------------------------------------------- | ||
103 | |||
104 | **Signature:** ``isArray(value)`` | ||
105 | |||
106 | Checks if passed argument is an instance of ``Array``. | ||
107 | |||
108 | ``isCasperObject()`` | ||
109 | ------------------------------------------------------------------------------- | ||
110 | |||
111 | **Signature:** ``isCasperObject(value)`` | ||
112 | |||
113 | Checks if passed argument is an instance of ``Casper``. | ||
114 | |||
115 | ``isClipRect()`` | ||
116 | ------------------------------------------------------------------------------- | ||
117 | |||
118 | **Signature:** ``isClipRect(value)`` | ||
119 | |||
120 | Checks if passed argument is a ``cliprect`` object. | ||
121 | |||
122 | .. index:: falsiness | ||
123 | |||
124 | ``isFalsy()`` | ||
125 | ------------------------------------------------------------------------------- | ||
126 | |||
127 | **Signature:** ``isFalsy(subject)`` | ||
128 | |||
129 | .. versionadded:: 1.0 | ||
130 | |||
131 | Returns subject `falsiness <http://11heavens.com/falsy-and-truthy-in-javascript>`_. | ||
132 | |||
133 | ``isFunction()`` | ||
134 | ------------------------------------------------------------------------------- | ||
135 | |||
136 | **Signature:** ``isFunction(value)`` | ||
137 | |||
138 | Checks if passed argument is a function. | ||
139 | |||
140 | ``isJsFile()`` | ||
141 | ------------------------------------------------------------------------------- | ||
142 | |||
143 | **Signature:** ``isJsFile(file)`` | ||
144 | |||
145 | Checks if passed filename is a Javascript one (by checking if it has a ``.js`` or ``.coffee`` file extension). | ||
146 | |||
147 | ``isNull()`` | ||
148 | ------------------------------------------------------------------------------- | ||
149 | |||
150 | **Signature:** ``isNull(value)`` | ||
151 | |||
152 | Checks if passed argument is a ``null``. | ||
153 | |||
154 | ``isNumber()`` | ||
155 | ------------------------------------------------------------------------------- | ||
156 | |||
157 | **Signature:** ``isNumber(value)`` | ||
158 | |||
159 | Checks if passed argument is an instance of ``Number``. | ||
160 | |||
161 | ``isObject()`` | ||
162 | ------------------------------------------------------------------------------- | ||
163 | |||
164 | **Signature:** ``isObject(value)`` | ||
165 | |||
166 | Checks if passed argument is an object. | ||
167 | |||
168 | ``isString()`` | ||
169 | ------------------------------------------------------------------------------- | ||
170 | |||
171 | **Signature:** ``isString(value)`` | ||
172 | |||
173 | Checks if passed argument is an instance of ``String``. | ||
174 | |||
175 | .. index:: truthiness | ||
176 | |||
177 | ``isTruthy()`` | ||
178 | ------------------------------------------------------------------------------- | ||
179 | |||
180 | **Signature:** ``isTruthy(subject)`` | ||
181 | |||
182 | .. versionadded:: 1.0 | ||
183 | |||
184 | Returns subject `truthiness <http://11heavens.com/falsy-and-truthy-in-javascript>`_. | ||
185 | |||
186 | ``isType()`` | ||
187 | ------------------------------------------------------------------------------- | ||
188 | |||
189 | **Signature:** ``isType(what, type)`` | ||
190 | |||
191 | Checks if passed argument has its type matching the ``type`` argument. | ||
192 | |||
193 | ``isUndefined()`` | ||
194 | ------------------------------------------------------------------------------- | ||
195 | |||
196 | **Signature:** ``isUndefined(value)`` | ||
197 | |||
198 | Checks if passed argument is ``undefined``. | ||
199 | |||
200 | ``isWebPage()`` | ||
201 | ------------------------------------------------------------------------------- | ||
202 | |||
203 | **Signature:** ``isWebPage(what)`` | ||
204 | |||
205 | Checks if passed argument is an instance of native PhantomJS' ``WebPage`` object. | ||
206 | |||
207 | ``mergeObjects()`` | ||
208 | ------------------------------------------------------------------------------- | ||
209 | |||
210 | **Signature:** ``mergeObjects(origin, add)`` | ||
211 | |||
212 | Merges two objects recursively. | ||
213 | |||
214 | .. index:: DOM | ||
215 | |||
216 | ``node()`` | ||
217 | ------------------------------------------------------------------------------- | ||
218 | |||
219 | **Signature:** ``node(name, attributes)`` | ||
220 | |||
221 | Creates an (HT\|X)ML element, having optional ``attributes`` added. | ||
222 | |||
223 | .. index:: JSON | ||
224 | |||
225 | ``serialize()`` | ||
226 | ------------------------------------------------------------------------------- | ||
227 | |||
228 | **Signature:** ``serialize(value)`` | ||
229 | |||
230 | Serializes a value using JSON_ format. Will serialize functions as strings. Useful for :doc:`debugging <../debugging>` and comparing objects. | ||
231 | |||
232 | ``unique()`` | ||
233 | ------------------------------------------------------------------------------- | ||
234 | |||
235 | **Signature:** ``unique(array)`` | ||
236 | |||
237 | Retrieves unique values from within a given ``Array``. | ||
238 | |||
239 | .. _JSON: http://json.org/ |
docs/quickstart.rst
0 → 100644
1 | .. _quickstart: | ||
2 | |||
3 | ========== | ||
4 | Quickstart | ||
5 | ========== | ||
6 | |||
7 | 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>`. | ||
8 | |||
9 | .. hint:: | ||
10 | |||
11 | If you're not too comfortable with Javascript, a :ref:`dedicated FAQ entry <faq_javascript>` is waiting for you. | ||
12 | |||
13 | .. _quickstart_javascript: | ||
14 | |||
15 | A minimal scraping script | ||
16 | ------------------------- | ||
17 | |||
18 | Fire up your favorite editor, create and save a ``sample.js`` file like below:: | ||
19 | |||
20 | var casper = require('casper').create(); | ||
21 | |||
22 | casper.start('http://casperjs.org/', function() { | ||
23 | this.echo(this.getTitle()); | ||
24 | }); | ||
25 | |||
26 | casper.thenOpen('http://phantomjs.org', function() { | ||
27 | this.echo(this.getTitle()); | ||
28 | }); | ||
29 | |||
30 | casper.run(); | ||
31 | |||
32 | Run it: | ||
33 | |||
34 | .. code-block:: text | ||
35 | |||
36 | $ casperjs sample.js | ||
37 | |||
38 | You should get something like this: | ||
39 | |||
40 | .. code-block:: text | ||
41 | |||
42 | $ casperjs c.js | ||
43 | CasperJS, a navigation scripting and testing utility for PhantomJS | CasperJS 1.0.0 | ||
44 | PhantomJS: Headless WebKit with JavaScript API | ||
45 | |||
46 | .. topic:: What did we just do? | ||
47 | |||
48 | 1. we created a new :ref:`Casper <casper_module>` instance | ||
49 | 2. we started it and opened ``http://casperjs.org/`` | ||
50 | 3. *once* the page has been loaded, we asked to print the title of that webpage (the content of its ``<title>`` tag) | ||
51 | 4. *then* we opened another url, ``http://phantomjs.org/`` | ||
52 | 5. *once* the new page has been loaded, we asked to print its title too | ||
53 | 6. we executed the whole process | ||
54 | |||
55 | |||
56 | Now let's scrape Google! | ||
57 | ------------------------ | ||
58 | |||
59 | 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. | ||
60 | |||
61 | Fire up your favorite editor and save the javascript code below in a | ||
62 | ``googlelinks.js`` file:: | ||
63 | |||
64 | var links = []; | ||
65 | var casper = require('casper').create(); | ||
66 | |||
67 | function getLinks() { | ||
68 | var links = document.querySelectorAll('h3.r a'); | ||
69 | return Array.prototype.map.call(links, function(e) { | ||
70 | return e.getAttribute('href') | ||
71 | }); | ||
72 | } | ||
73 | |||
74 | casper.start('http://google.fr/', function() { | ||
75 | // search for 'casperjs' from google form | ||
76 | this.fill('form[action="/search"]', { q: 'casperjs' }, true); | ||
77 | }); | ||
78 | |||
79 | casper.then(function() { | ||
80 | // aggregate results for the 'casperjs' search | ||
81 | links = this.evaluate(getLinks); | ||
82 | // now search for 'phantomjs' by filling the form again | ||
83 | this.fill('form[action="/search"]', { q: 'phantomjs' }, true); | ||
84 | }); | ||
85 | |||
86 | casper.then(function() { | ||
87 | // aggregate results for the 'phantomjs' search | ||
88 | links = links.concat(this.evaluate(getLinks)); | ||
89 | }); | ||
90 | |||
91 | casper.run(function() { | ||
92 | // echo results in some pretty fashion | ||
93 | this.echo(links.length + ' links found:'); | ||
94 | this.echo(' - ' + links.join('\n - ')).exit(); | ||
95 | }); | ||
96 | |||
97 | Run it: | ||
98 | |||
99 | .. code-block:: text | ||
100 | |||
101 | $ casperjs googlelinks.js | ||
102 | 20 links found: | ||
103 | - https://github.com/n1k0/casperjs | ||
104 | - https://github.com/n1k0/casperjs/issues/2 | ||
105 | - https://github.com/n1k0/casperjs/tree/master/samples | ||
106 | - https://github.com/n1k0/casperjs/commits/master/ | ||
107 | - http://www.facebook.com/people/Casper-Js/100000337260665 | ||
108 | - http://www.facebook.com/public/Casper-Js | ||
109 | - http://hashtags.org/tag/CasperJS/ | ||
110 | - http://www.zerotohundred.com/newforums/members/casper-js.html | ||
111 | - http://www.yellowpages.com/casper-wy/j-s-enterprises | ||
112 | - http://local.trib.com/casper+wy/j+s+chinese+restaurant.zq.html | ||
113 | - http://www.phantomjs.org/ | ||
114 | - http://code.google.com/p/phantomjs/ | ||
115 | - http://code.google.com/p/phantomjs/wiki/QuickStart | ||
116 | - http://svay.com/blog/index/post/2011/08/31/Paris-JS-10-%3A-Introduction-%C3%A0-PhantomJS | ||
117 | - https://github.com/ariya/phantomjs | ||
118 | - http://dailyjs.com/2011/01/28/phantoms/ | ||
119 | - http://css.dzone.com/articles/phantom-js-alternative | ||
120 | - http://pilvee.com/blog/tag/phantom-js/ | ||
121 | - http://ariya.blogspot.com/2011/01/phantomjs-minimalistic-headless-webkit.html | ||
122 | - http://www.readwriteweb.com/hack/2011/03/phantomjs-the-power-of-webkit.php | ||
123 | |||
124 | |||
125 | .. _quickstart_coffeescript: | ||
126 | |||
127 | .. index:: coffeescript | ||
128 | |||
129 | CoffeeScript version | ||
130 | -------------------- | ||
131 | |||
132 | You can also write Casper scripts using the `CoffeeScript syntax <http://jashkenas.github.com/coffee-script/>`_: | ||
133 | |||
134 | .. code-block:: coffeescript | ||
135 | |||
136 | getLinks = -> | ||
137 | links = document.querySelectorAll "h3.r a" | ||
138 | Array::map.call links, (e) -> e.getAttribute "href" | ||
139 | |||
140 | links = [] | ||
141 | casper = require('casper').create() | ||
142 | |||
143 | casper.start "http://google.fr/", -> | ||
144 | # search for 'casperjs' from google form | ||
145 | @fill "form[action='/search']", q: "casperjs", true | ||
146 | |||
147 | casper.then -> | ||
148 | # aggregate results for the 'casperjs' search | ||
149 | links = @evaluate getLinks | ||
150 | # search for 'phantomjs' from google form | ||
151 | @fill "form[action='/search']", q: "phantomjs", true | ||
152 | |||
153 | casper.then -> | ||
154 | # concat results for the 'phantomjs' search | ||
155 | links = links.concat @evaluate(getLinks) | ||
156 | |||
157 | casper.run -> | ||
158 | # display results | ||
159 | @echo links.length + " links found:" | ||
160 | @echo(" - " + links.join("\n - ")).exit() | ||
161 | |||
162 | Just remember to suffix your script with the ``.coffee`` extension. | ||
163 | |||
164 | A minimal testing script | ||
165 | ------------------------ | ||
166 | |||
167 | 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:: | ||
168 | |||
169 | // hello-test.js | ||
170 | casper.test.assert(true); | ||
171 | casper.test.done(); | ||
172 | |||
173 | Run it using the ``casperjs test`` subcommand: | ||
174 | |||
175 | .. code-block:: text | ||
176 | |||
177 | $ casperjs test hello-test.js | ||
178 | Test file: hello-test.js | ||
179 | PASS Subject is strictly true | ||
180 | PASS 1 tests executed in 0.103s, 1 passed, 0 failed. | ||
181 | |||
182 | .. note:: | ||
183 | |||
184 | 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. | ||
185 | |||
186 | You can read more about testing in the :ref:`dedicated section <testing>`. |
docs/selectors.rst
0 → 100644
1 | .. _selectors: | ||
2 | |||
3 | .. index:: selector, DOM, HTML | ||
4 | |||
5 | ========= | ||
6 | Selectors | ||
7 | ========= | ||
8 | |||
9 | 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. | ||
10 | |||
11 | All the examples below are based on this HTML code: | ||
12 | |||
13 | .. code-block:: html | ||
14 | |||
15 | <!doctype html> | ||
16 | <html> | ||
17 | <head> | ||
18 | <meta charset="utf-8"> | ||
19 | <title>My page</title> | ||
20 | </head> | ||
21 | <body> | ||
22 | <h1 class="page-title">Hello</h1> | ||
23 | <ul> | ||
24 | <li>one</li> | ||
25 | <li>two</li> | ||
26 | <li>three</li> | ||
27 | </ul> | ||
28 | <footer><p>©2012 myself</p></footer> | ||
29 | </body> | ||
30 | </html> | ||
31 | |||
32 | .. index:: CSS, CSS3 | ||
33 | |||
34 | CSS3 | ||
35 | ---- | ||
36 | |||
37 | By default, CasperJS accepts `CSS3 selector strings <http://www.w3.org/TR/selectors/#selectors>`_ to check for elements within the DOM. | ||
38 | |||
39 | To check if the ``<h1 class="page-title">`` element exists in the example page, you can use:: | ||
40 | |||
41 | var casper = require('casper').create(); | ||
42 | |||
43 | casper.start('http://domain.tld/page.html', function() { | ||
44 | if (this.exists('h1.page-title')) { | ||
45 | this.echo('the heading exists'); | ||
46 | } | ||
47 | }); | ||
48 | |||
49 | casper.run(); | ||
50 | |||
51 | Or if you're using the :doc:`testing framework <testing>`:: | ||
52 | |||
53 | casper.test.begin('The heading exists', 1, function suite(test) { | ||
54 | casper.start('http://domain.tld/page.html', function() { | ||
55 | this.assertExists('h1.page-title'); | ||
56 | }).run(function() { | ||
57 | test.done(); | ||
58 | }); | ||
59 | }); | ||
60 | |||
61 | Some other convenient testing methods are relying on selectors:: | ||
62 | |||
63 | casper.test.begin('Page content tests', 3, function suite(test) { | ||
64 | casper.start('http://domain.tld/page.html', function() { | ||
65 | this.assertExists('h1.page-title'); | ||
66 | this.assertSelectorHasText('h1.page-title', 'Hello'); | ||
67 | this.assertVisible('footer'); | ||
68 | }).run(function() { | ||
69 | test.done(); | ||
70 | }); | ||
71 | }); | ||
72 | |||
73 | .. index:: XPath | ||
74 | |||
75 | XPath | ||
76 | ----- | ||
77 | |||
78 | .. versionadded:: 0.6.8 | ||
79 | |||
80 | You can alternatively use `XPath expressions <http://en.wikipedia.org/wiki/XPath>`_ instead:: | ||
81 | |||
82 | casper.start('http://domain.tld/page.html', function() { | ||
83 | this.test.assertExists({ | ||
84 | type: 'xpath', | ||
85 | path: '//*[@class="plop"]' | ||
86 | }, 'the element exists'); | ||
87 | }); | ||
88 | |||
89 | To ease the use and reading of XPath expressions, a ``selectXPath`` helper is available from the ``casper`` module:: | ||
90 | |||
91 | var x = require('casper').selectXPath; | ||
92 | |||
93 | casper.start('http://domain.tld/page.html', function() { | ||
94 | this.test.assertExists(x('//*[@id="plop"]'), 'the element exists'); | ||
95 | }); | ||
96 | |||
97 | .. warning:: | ||
98 | |||
99 | 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. |
docs/testing.rst
0 → 100644
1 | .. _testing: | ||
2 | |||
3 | .. index:: Testing | ||
4 | |||
5 | ======= | ||
6 | Testing | ||
7 | ======= | ||
8 | |||
9 | CasperJS ships with its own :doc:`testing framework <modules/tester>`, providing a handful set of tools to ease testing your webapps. | ||
10 | |||
11 | .. warning:: | ||
12 | |||
13 | .. versionchanged:: 1.1 | ||
14 | |||
15 | The testing framework — hence its whole API — can only be used when using the ``casperjs test`` subcommand. | ||
16 | |||
17 | If you try to use the ``casper.test`` property out of the testing environment, you'll get an error. | ||
18 | |||
19 | .. index:: Unit testing | ||
20 | |||
21 | Unit testing | ||
22 | ------------ | ||
23 | |||
24 | Imagine a dumb ``Cow`` object we want to unit test:: | ||
25 | |||
26 | function Cow() { | ||
27 | this.mowed = false; | ||
28 | this.moo = function moo() { | ||
29 | this.mowed = true; // mootable state: don't do that at home | ||
30 | return 'moo!'; | ||
31 | }; | ||
32 | } | ||
33 | |||
34 | Let's write a tiny test suite for it:: | ||
35 | |||
36 | // cow-test.js | ||
37 | casper.test.begin('Cow can moo', 2, function suite(test) { | ||
38 | var cow = new Cow(); | ||
39 | test.assertEquals(cow.moo(), 'moo!'); | ||
40 | test.assert(cow.mowed); | ||
41 | test.done(); | ||
42 | }); | ||
43 | |||
44 | Run the tests using the ``casperjs test`` command: | ||
45 | |||
46 | .. code-block:: text | ||
47 | |||
48 | $ casperjs test cow-test.js | ||
49 | |||
50 | You should theoretically get something like this: | ||
51 | |||
52 | .. figure:: _static/images/cow-test-ok.png | ||
53 | :align: center | ||
54 | |||
55 | Make it fail:: | ||
56 | |||
57 | casper.test.begin('Cow can moo', 2, function suite(test) { | ||
58 | var cow = new Cow(); | ||
59 | test.assertEquals(cow.moo(), 'BAZINGA!'); | ||
60 | test.assert(cow.mowed); | ||
61 | test.done(); | ||
62 | }); | ||
63 | |||
64 | You'll get this instead: | ||
65 | |||
66 | .. figure:: _static/images/cow-test-ko.png | ||
67 | :align: center | ||
68 | |||
69 | .. hint:: | ||
70 | |||
71 | The whole ``tester`` module API is documented :doc:`here <modules/tester>`. | ||
72 | |||
73 | |||
74 | .. index:: Functional testing, Browser testing, Test suite | ||
75 | |||
76 | Browser tests | ||
77 | ------------- | ||
78 | |||
79 | Now let's write a suite for testing google search (yes, you read it well):: | ||
80 | |||
81 | // googletesting.js | ||
82 | casper.test.begin('Google search retrieves 10 or more results', 5, function suite(test) { | ||
83 | casper.start("http://www.google.fr/", function() { | ||
84 | test.assertTitle("Google", "google homepage title is the one expected"); | ||
85 | test.assertExists('form[action="/search"]', "main form is found"); | ||
86 | this.fill('form[action="/search"]', { | ||
87 | q: "casperjs" | ||
88 | }, true); | ||
89 | }); | ||
90 | |||
91 | casper.then(function() { | ||
92 | test.assertTitle("casperjs - Recherche Google", "google title is ok"); | ||
93 | test.assertUrlMatch(/q=casperjs/, "search term has been submitted"); | ||
94 | test.assertEval(function() { | ||
95 | return __utils__.findAll("h3.r").length >= 10; | ||
96 | }, "google search for \"casperjs\" retrieves 10 or more results"); | ||
97 | }); | ||
98 | |||
99 | casper.run(function() { | ||
100 | test.done(); | ||
101 | }); | ||
102 | }); | ||
103 | |||
104 | Now run the tests suite: | ||
105 | |||
106 | .. code-block:: text | ||
107 | |||
108 | $ casperjs test googletesting.js | ||
109 | |||
110 | You'll probably get something like this: | ||
111 | |||
112 | .. figure:: _static/images/testsuiteok.png | ||
113 | :align: center | ||
114 | |||
115 | |||
116 | Advanced techniques | ||
117 | ------------------- | ||
118 | |||
119 | 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:: | ||
120 | |||
121 | // cow-test.js | ||
122 | casper.test.begin('Cow can moo', 2, { | ||
123 | setUp: function(test) { | ||
124 | this.cow = new Cow(); | ||
125 | }, | ||
126 | |||
127 | tearDown: function(test) { | ||
128 | this.cow.destroy(); | ||
129 | }, | ||
130 | |||
131 | test: function(test) { | ||
132 | test.assertEquals(this.cow.moo(), 'moo!'); | ||
133 | test.assert(this.cow.mowed); | ||
134 | test.done(); | ||
135 | } | ||
136 | }); | ||
137 | |||
138 | |||
139 | Test command args and options | ||
140 | ----------------------------- | ||
141 | |||
142 | Arguments | ||
143 | ~~~~~~~~~ | ||
144 | |||
145 | 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. | ||
146 | |||
147 | .. warning :: | ||
148 | |||
149 | There are two important conditions when writing tests: | ||
150 | |||
151 | - You **must not** create a new ``Casper`` instance in a test file; | ||
152 | - You **must** call ``Tester.done()`` when all the tests contained in a suite (or in a file) have been executed. | ||
153 | |||
154 | Options | ||
155 | ~~~~~~~ | ||
156 | |||
157 | Options are prefixed with a double-dash (``--``): | ||
158 | |||
159 | - ``--xunit=<filename>`` will export test suite results in a :ref:`XUnit XML file <xunit_report>` | ||
160 | - ``--direct`` will print :doc:`log messages <logging>` directly to the console | ||
161 | - ``--log-level=<logLevel>`` sets the logging level (see the :doc:`related section <logging>`) | ||
162 | |||
163 | .. versionadded:: 1.0 | ||
164 | |||
165 | - ``--includes=foo.js,bar.js`` will include the ``foo.js`` and ``bar.js`` files before each test file execution; | ||
166 | - ``--pre=pre-test.js`` will add the tests contained in ``pre-test.js`` **before** executing the whole test suite; | ||
167 | - ``--post=post-test.js`` will add the tests contained in ``post-test.js`` **after** having executed the whole test suite; | ||
168 | - ``--fail-fast`` will terminate the current test suite as soon as a first failure is encountered. | ||
169 | |||
170 | Sample custom command: | ||
171 | |||
172 | .. code-block:: text | ||
173 | |||
174 | $ casperjs test --includes=foo.js,bar.js \ | ||
175 | --pre=pre-test.js \ | ||
176 | --post=post-test.js \ | ||
177 | --direct \ | ||
178 | --log-level=debug \ | ||
179 | --fail-fast \ | ||
180 | test1.js test2.js /path/to/some/test/dir | ||
181 | |||
182 | .. hint:: | ||
183 | |||
184 | 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. | ||
185 | |||
186 | |||
187 | .. _xunit_report: | ||
188 | |||
189 | .. index:: XUnit, XML, Jenkins, Continuous Integration | ||
190 | |||
191 | Exporting results in XUnit format | ||
192 | --------------------------------- | ||
193 | |||
194 | 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: | ||
195 | |||
196 | .. code-block:: text | ||
197 | |||
198 | $ casperjs test googletesting.js --save=log.xml | ||
199 | |||
200 | You should get a pretty XUnit XML report like this: | ||
201 | |||
202 | .. code-block:: xml | ||
203 | |||
204 | <?xml version="1.0" encoding="UTF-8"?> | ||
205 | <testsuites duration="1.249"> | ||
206 | <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"> | ||
207 | <testcase classname="googletesting" name="google homepage title is the one expected" time="0.813"/> | ||
208 | <testcase classname="googletesting" name="main form is found" time="0.002"/> | ||
209 | <testcase classname="googletesting" name="google title is ok" time="0.416"/> | ||
210 | <testcase classname="googletesting" name="search term has been submitted" time="0.017"/> | ||
211 | <testcase classname="googletesting" name="google search for "casperjs" retrieves 10 or more results" time="0.001"/> | ||
212 | <system-out/> | ||
213 | </testsuite> | ||
214 | </testsuites> | ||
215 | |||
216 | CasperJS own tests | ||
217 | ------------------ | ||
218 | |||
219 | CasperJS has its own unit and functional test suite, located in the ``tests`` subfolder. To run this test suite: | ||
220 | |||
221 | .. code-block:: text | ||
222 | |||
223 | $ casperjs selftest | ||
224 | |||
225 | .. note:: | ||
226 | |||
227 | 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>`_. | ||
228 | |||
229 | |||
230 | .. index:: extending | ||
231 | |||
232 | Extending Casper for Testing | ||
233 | ---------------------------- | ||
234 | |||
235 | This command: | ||
236 | |||
237 | .. code-block:: text | ||
238 | |||
239 | $ casperjs test [path] | ||
240 | |||
241 | is just a shortcut for this one: | ||
242 | |||
243 | .. code-block:: text | ||
244 | |||
245 | $ casper /path/to/casperjs/tests/run.js [path] | ||
246 | |||
247 | 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. | ||
248 | |||
249 | .. hint:: | ||
250 | |||
251 | You can find the default runner code in `run.js <https://github.com/n1k0/casperjs/blob/master/tests/run.js>`_. |
docs/upgrading/1.1.rst
0 → 100644
1 | Upgrading to 1.1 | ||
2 | ================ | ||
3 | |||
4 | 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:: | ||
5 | |||
6 | // 1.0 style test script not using the `casperjs test` subcommand | ||
7 | var casper = require('casper').create(); | ||
8 | |||
9 | casper.start('http://foo.bar/', function() { | ||
10 | this.test.assert(true); | ||
11 | }); | ||
12 | |||
13 | casper.run(function() { | ||
14 | this.test.done(1); | ||
15 | this.test.renderResults(true); | ||
16 | }); | ||
17 | |||
18 | 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. | ||
19 | |||
20 | Instead you now have to use the :doc:`casperjs test <../testing>` subcommand mandatorily to access a tester instance from the ``casper.test`` property. | ||
21 | |||
22 | .. warning:: | ||
23 | |||
24 | As of 1.1: | ||
25 | |||
26 | - you shouldn't invoke the ``renderResults()`` method directly anymore | ||
27 | - you shouldn't use the ``done()`` first argument to set planned test as it's been deprecated | ||
28 | - you can't access the ``casper.test`` property when not using the ``casperjs test`` subcommand | ||
29 | |||
30 | If you try, you'll get an error:: | ||
31 | |||
32 | // test.js | ||
33 | var casper = require('casper').create(); | ||
34 | casper.test.assert(true); | ||
35 | |||
36 | Will give: | ||
37 | |||
38 | .. code-block:: text | ||
39 | |||
40 | $ casperjs test.js | ||
41 | CasperError: casper.test property is only available using the `casperjs test` command | ||
42 | |||
43 | The new ``Tester#begin()`` method | ||
44 | --------------------------------- | ||
45 | |||
46 | However, a new :ref:`begin() <tester_begin>` method as been added to the :ref:`Tester <tester_module>` prototype, to ease describing your tests:: | ||
47 | |||
48 | casper.test.begin('Description of my test', 1, function(test) { | ||
49 | test.assert(true); | ||
50 | test.done(); | ||
51 | }); | ||
52 | |||
53 | More asynchronously:: | ||
54 | |||
55 | casper.test.begin('Description of my test', 1, function(test) { | ||
56 | casper.start('http://foo.bar/', function() { | ||
57 | test.assert(true); | ||
58 | }); | ||
59 | |||
60 | casper.run(function() { | ||
61 | test.done(); | ||
62 | }); | ||
63 | }); | ||
64 | |||
65 | .. note:: | ||
66 | |||
67 | Please note that ``begin()``'s the second argument which is now the place to set the number of planned tests. |
docs/writing_modules.rst
0 → 100644
1 | .. _writing_modules: | ||
2 | |||
3 | .. index:: Modules, Modules, Custom module | ||
4 | |||
5 | Writing CasperJS modules | ||
6 | ======================== | ||
7 | |||
8 | 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')``. | ||
9 | |||
10 | So if you plan to write your own modules and uses casperjs' ones from them, be sure to call the ``patchRequire()`` function:: | ||
11 | |||
12 | // my module, stored in universe.js | ||
13 | // patching phantomjs' require() | ||
14 | var require = patchRequire(require); | ||
15 | |||
16 | // now you're ready to go | ||
17 | var utils = require('utils'); | ||
18 | var magic = 42; | ||
19 | exports.answer = function() { | ||
20 | return utils.format("it's %d", magic); | ||
21 | }; | ||
22 | |||
23 | .. warning:: | ||
24 | |||
25 | When using CoffeeScript ``global.require`` must be passed to ``patchRequire()`` instead of just ``require``. | ||
26 | |||
27 | From your root casper script:: | ||
28 | |||
29 | var universe = require('./universe'); | ||
30 | console.log(universe.answer()); // prints "It's 42" |
-
Please register or sign in to post a comment