added documentation :)
Showing
2 changed files
with
322 additions
and
19 deletions
1 | # Casper.js | 1 | # Casper.js |
2 | 2 | ||
3 | Casper is a navigation utility for [PhantomJS](http://www.phantomjs.org/). | 3 | Casper.js is a navigation utility for [PhantomJS](http://www.phantomjs.org/). It eases the process of defining a full navigation scenario and provides useful high-level function, methods & syntaxic sugar for doing common tasks such as: |
4 | 4 | ||
5 | More documentation to come soon, I swear. If you just can't wait, here's a sample script: | 5 | - chaining navigation steps |
6 | - capturing screenshots of a page (or an area) | ||
7 | - logging events | ||
8 | - evaluating dynamic code within the remote page environment | ||
9 | - retrieve base64 encoded version of remote resources | ||
10 | - catch errors and react accordingly | ||
6 | 11 | ||
7 | phantom.injectJs('casper.js'); | 12 | ## Quickstart |
8 | 13 | ||
9 | // User defined functions | 14 | In the following example, we'll query google for two terms consecutively, `capser` and `homer`, and aggregate the result links in a standard Array. Running the script will output a standard JSON string containing both the logs and the results: |
10 | function q() { | 15 | |
16 | ``` javascript | ||
17 | phantom.injectJs('path/to/casper.js'); | ||
18 | |||
19 | // User defined functions | ||
20 | function q() { | ||
11 | document.querySelector('input[name="q"]').setAttribute('value', '%term%'); | 21 | document.querySelector('input[name="q"]').setAttribute('value', '%term%'); |
12 | document.querySelector('form[name="f"]').submit(); | 22 | document.querySelector('form[name="f"]').submit(); |
13 | } | 23 | } |
14 | 24 | ||
15 | function getLinks() { | 25 | function getLinks() { |
16 | return Array.prototype.map.call(document.querySelectorAll('h3.r a'), function(e) { | 26 | var links = document.querySelectorAll('h3.r a'); |
27 | return Array.prototype.map.call(links, function(e) { | ||
17 | return e.getAttribute('href'); | 28 | return e.getAttribute('href'); |
18 | }); | 29 | }); |
19 | } | 30 | } |
20 | 31 | ||
21 | // Casper suite | 32 | // Casper suite |
22 | var links = []; | 33 | var links = []; |
23 | var casper = new phantom.Casper() | 34 | var casper = new phantom.Casper({ |
24 | .start('http://google.fr/') | 35 | logLevel: "info" |
36 | }); | ||
37 | casper.start('http://google.fr/') | ||
25 | .thenEvaluate(q, { | 38 | .thenEvaluate(q, { |
26 | term: 'casper', | 39 | term: 'casper' |
27 | }) | 40 | }) |
28 | .then(function(self) { | 41 | .then(function(self) { |
29 | links = self.evaluate(getLinks); | 42 | links = self.evaluate(getLinks); |
30 | }) | 43 | }) |
31 | .thenEvaluate(q, { | 44 | .thenEvaluate(q, { |
32 | term: 'homer', | 45 | term: 'homer' |
33 | }) | 46 | }) |
34 | .then(function(self) { | 47 | .then(function(self) { |
35 | links = links.concat(self.evaluate(getLinks)); | 48 | links = links.concat(self.evaluate(getLinks)); |
... | @@ -41,7 +54,9 @@ More documentation to come soon, I swear. If you just can't wait, here's a sampl | ... | @@ -41,7 +54,9 @@ More documentation to come soon, I swear. If you just can't wait, here's a sampl |
41 | }, null, ' ')); | 54 | }, null, ' ')); |
42 | self.exit(); | 55 | self.exit(); |
43 | }) | 56 | }) |
44 | ; | 57 | ; |
58 | ``` | ||
59 | **Hint:** Method chaining is not mandatory but provided as an alternative way to structure your code. | ||
45 | 60 | ||
46 | Run it: | 61 | Run it: |
47 | 62 | ||
... | @@ -143,8 +158,296 @@ Run it: | ... | @@ -143,8 +158,296 @@ Run it: |
143 | "http://www.homeralaska.org/", | 158 | "http://www.homeralaska.org/", |
144 | "http://homeralaska.com/" | 159 | "http://homeralaska.com/" |
145 | ] | 160 | ] |
146 | } | 161 | } |
162 | |||
163 | ### CoffeeScript | ||
164 | |||
165 | You can also write Casper scripts using the [CoffeeScript syntax](http://jashkenas.github.com/coffee-script/): | ||
166 | |||
167 | ``` coffeescript | ||
168 | phantom.injectJs "path/to/casper.js" | ||
169 | |||
170 | q = -> | ||
171 | document.querySelector('input[name="q"]').setAttribute "value", "%term%" | ||
172 | document.querySelector('form[name="f"]').submit() | ||
173 | |||
174 | getLinks = -> | ||
175 | links = document.querySelectorAll("h3.r a") | ||
176 | Array::map.call links, (e) -> | ||
177 | e.getAttribute "href" | ||
178 | |||
179 | links = [] | ||
180 | |||
181 | casper = new phantom.Casper verbose: true, logLevel: "debug" | ||
182 | casper.start "http://google.fr/" | ||
183 | casper.thenEvaluate q, term: "casper" | ||
184 | casper.then -> links = casper.evaluate getLinks | ||
185 | casper.thenEvaluate q, term: "homer" | ||
186 | casper.then -> links = links.concat casper.evaluate getLinks | ||
187 | casper.run -> | ||
188 | out = | ||
189 | result: casper.result | ||
190 | links: links | ||
191 | casper.echo JSON.stringify out, null, " " | ||
192 | casper.exit() | ||
193 | ``` | ||
194 | |||
195 | ## Casper.js API Documentation | ||
196 | |||
197 | Code is quite heavily documented using `jsdoc`, but here are the whole API documentation with sample examples supplied: | ||
198 | |||
199 | ### Casper#base64encode(String url) | ||
200 | |||
201 | Encodes a resource using the base64 algorithm synchroneously using client-side XMLHttpRequest. | ||
202 | |||
203 | NOTE: we cannot use `window.btoa()` because it fails miserably in the version of WebKit shipping with PhantomJS. | ||
204 | |||
205 | Example: retrieving google logo image encoded in base64: | ||
206 | |||
207 | ``` javascript | ||
208 | var base64logo = null; | ||
209 | casper.start('http://www.google.fr/', function(self) { | ||
210 | base64logo = self.base64encode('http://www.google.fr/images/srpr/logo3w.png'); | ||
211 | }).run(function() { | ||
212 | self.echo(base64logo); | ||
213 | }); | ||
214 | ``` | ||
215 | |||
216 | ### Casper#capture(String targetFilepath, Object clipRect) | ||
217 | |||
218 | Proxy method for PhantomJS' `WebPage#render`. Adds a clipRect parameter for automatically setting page clipRect setting values and sets it back once done. | ||
219 | |||
220 | Example: | ||
221 | |||
222 | ``` javascript | ||
223 | casper.start('http://www.google.fr/', function(self) { | ||
224 | self.capture('google.png', { | ||
225 | top: 100, | ||
226 | left: 100, | ||
227 | width: 500, | ||
228 | height: 400 | ||
229 | }); | ||
230 | }).run(); | ||
231 | ``` | ||
232 | |||
233 | ### Casper#debugHTML() | ||
234 | |||
235 | Logs the HTML code of the current page directly to the standard output, for debugging purpose. | ||
236 | |||
237 | Example: | ||
238 | |||
239 | ``` javascript | ||
240 | casper.start('http://www.google.fr/', function(self) { | ||
241 | self.debugHTML(); | ||
242 | }).run(); | ||
243 | ``` | ||
244 | |||
245 | ### Casper#debugPage() | ||
246 | |||
247 | Logs the textual contents of the current page directly to the standard output, for debugging purpose. | ||
248 | |||
249 | Example: | ||
250 | |||
251 | ``` javascript | ||
252 | casper.start('http://www.google.fr/', function(self) { | ||
253 | self.debugPage(); | ||
254 | }).run(); | ||
255 | ``` | ||
256 | |||
257 | ### Casper#die(String message[, int status]) | ||
258 | |||
259 | Exits phantom with a logged error message and an optional exit status code. | ||
260 | |||
261 | Example: | ||
262 | |||
263 | ``` javascript | ||
264 | casper.start('http://www.google.fr/', function(self) { | ||
265 | self.die("Fail.", 1); | ||
266 | }).run(); | ||
267 | ``` | ||
268 | |||
269 | ### Casper#echo(String message) | ||
270 | |||
271 | Prints something to stdout. | ||
272 | |||
273 | Example: | ||
274 | |||
275 | ``` javascript | ||
276 | casper.start('http://www.google.fr/', function(self) { | ||
277 | self.echo('Page title is: ' + self.evaluate(function() { | ||
278 | return document.title; | ||
279 | })); | ||
280 | }).run(); | ||
281 | ``` | ||
282 | |||
283 | ### Casper#evaluate(function fn[, Object replacements]) | ||
284 | |||
285 | Evaluates an expression in the page context, a bit like what PhantomJS' `WebPage#evaluate` does, but can also replace values by their placeholer names. | ||
286 | |||
287 | Example: | ||
288 | |||
289 | ``` javascript | ||
290 | casper.evaluate(function() { | ||
291 | document.querySelector('#username').setAttribute('value', '%username%'); | ||
292 | document.querySelector('#password').setAttribute('value', '%password%'); | ||
293 | document.querySelector('#submit').click(); | ||
294 | }, { | ||
295 | username: 'Bazoonga', | ||
296 | password: 'baz00nga' | ||
297 | }); | ||
298 | ``` | ||
299 | |||
300 | ### Casper#evaluateOrDie(function fn[, String message]) | ||
301 | |||
302 | Evaluates an expression within the current page DOM and `die()` if it returns anything but `true`. | ||
303 | |||
304 | Example: | ||
305 | |||
306 | ``` javascript | ||
307 | casper.start('http://foo.bar/home', function(self) { | ||
308 | self.evaluateOrDie(function() { | ||
309 | return /logged in/.match(document.title); | ||
310 | }, 'not authenticated'); | ||
311 | }).run(); | ||
312 | ``` | ||
313 | |||
314 | ### Casper#exit([int status]) | ||
315 | |||
316 | Exits PhantomJS with an optional exit status code. | ||
317 | |||
318 | ### Casper#log(String message[, String level, String space) | ||
319 | |||
320 | 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. | ||
321 | |||
322 | Example: | ||
323 | |||
324 | ``` javascript | ||
325 | casper.start('http://www.google.fr/', function(self) { | ||
326 | self.log("I'm logging an error", "error"); | ||
327 | }).run(); | ||
328 | ``` | ||
329 | |||
330 | ### Casper#repeat(int times, function then) | ||
331 | |||
332 | Repeats a navigation step a given number of times. | ||
333 | |||
334 | Example: | ||
335 | |||
336 | ``` javascript | ||
337 | var i = 0; | ||
338 | casper.start('http://foo.bar/home', function(self) { | ||
339 | self.evaluateOrDie(function() { | ||
340 | return /logged in/.match(document.title); | ||
341 | }, 'not authenticated'); | ||
342 | }).repeat(5, function(self) { | ||
343 | self.echo("I am step #" + ++i); | ||
344 | }).run(); | ||
345 | ``` | ||
346 | |||
347 | ### Casper#run(fn onComplete[, int time]) | ||
348 | |||
349 | 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. | ||
350 | |||
351 | Casper suite **won't run**: | ||
352 | |||
353 | ``` javascript | ||
354 | casper.start('http://foo.bar/home', function(self) { | ||
355 | // ... | ||
356 | }).then(function(self) { | ||
357 | // ... | ||
358 | }); | ||
359 | ``` | ||
360 | |||
361 | Casper suite **will run**: | ||
362 | |||
363 | ``` javascript | ||
364 | casper.start('http://foo.bar/home', function(self) { | ||
365 | // ... | ||
366 | }).then(function(self) { | ||
367 | // ... | ||
368 | }).run(); | ||
369 | ``` | ||
370 | |||
371 | ### Casper#start(String url[, function then]) | ||
372 | |||
373 | Configures and starts Casper, then open the provided `url` and optionnaly adds the step provided by the `then` argument. | ||
374 | |||
375 | Example: | ||
376 | |||
377 | ``` javascript | ||
378 | casper.start('http://google.fr/', function(self) { | ||
379 | self.echo("I'm loaded."); | ||
380 | }).run(); | ||
381 | ``` | ||
382 | |||
383 | Alternatively: | ||
384 | |||
385 | ``` javascript | ||
386 | casper.start('http://google.fr/'); | ||
387 | casper.then(function(self) { | ||
388 | self.echo("I'm loaded."); | ||
389 | }); | ||
390 | casper.run(); | ||
391 | ``` | ||
392 | |||
393 | Please note that **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. | ||
394 | |||
395 | ### Casper#then(function fn) | ||
396 | |||
397 | The standard way to add a new navigation step to the Casper suite by provide a callback function which will be executed when the requested page is loaded. | ||
398 | |||
399 | Example: | ||
400 | |||
401 | ``` javascript | ||
402 | casper.start('http://google.fr/').then(function(self) { | ||
403 | self.echo("I'm in your google."); | ||
404 | }).run(); | ||
405 | ``` | ||
406 | |||
407 | Please note that usage of the `self` argument is not mandatory, it's just pythonic-like syntaxic sugar. You can perfectly use this alternative: | ||
408 | |||
409 | ``` javascript | ||
410 | casper.start('http://google.fr/').then(function() { | ||
411 | casper.echo("I'm in your google."); | ||
412 | }).run(); | ||
413 | ``` | ||
414 | |||
415 | If you want to open a page as a next step in your navigation scenario, please refer to the `Casper#thenOpen()` method documentation. | ||
416 | |||
417 | ### Casper#thenEvaluate(function fn[, Object replacements]) | ||
418 | |||
419 | Adds a new navigation step to perform code evaluation within the current retrieved page DOM. | ||
420 | |||
421 | Example: | ||
422 | |||
423 | ``` javascript | ||
424 | // Querying for "Chuck Norris" on Google | ||
425 | casper.start('http://google.fr/').thenEvaluate(function() { | ||
426 | document.querySelector('input[name="q"]').setAttribute('value', '%term%'); | ||
427 | document.querySelector('form[name="f"]').submit(); | ||
428 | }, { | ||
429 | term: 'Chuck Norris' | ||
430 | }).run(); | ||
431 | ``` | ||
432 | |||
433 | ### Casper#thenOpen(String location[, function then]) | ||
434 | |||
435 | Adds a new navigation step for opening a new location, and optionnaly add a next step when its loaded. | ||
436 | |||
437 | Example: | ||
438 | |||
439 | ``` javascript | ||
440 | casper.start('http://google.fr/').then(function(self) { | ||
441 | self.echo("I'm in your google."); | ||
442 | }).thenOpen('http://yahoo.fr/', function(self) { | ||
443 | self.echo("Now I'm in your yahoo.") | ||
444 | }).run(); | ||
445 | ``` | ||
446 | |||
447 | ## Licensing | ||
448 | |||
449 | `Casper.js` is released under the terms of the [MIT license](http://en.wikipedia.org/wiki/MIT_License). | ||
147 | 450 | ||
148 | ## Now what | 451 | ## Now what |
149 | 452 | ||
150 | Feel free to play with the code and report an issue on github. I'm also reachable [on twitter](https://twitter.com/n1k0). | 453 | Feel free to play with the code and [report an issue on github](https://github.com/n1k0/casperjs/issues). I'm also reachable [on twitter](https://twitter.com/n1k0). | ... | ... |
... | @@ -331,7 +331,7 @@ | ... | @@ -331,7 +331,7 @@ |
331 | }, | 331 | }, |
332 | 332 | ||
333 | /** | 333 | /** |
334 | * Configures and start the Casper. | 334 | * Configures and starts Casper. |
335 | * | 335 | * |
336 | * @param String location An optional location to open on start | 336 | * @param String location An optional location to open on start |
337 | * @param function then Next step function to execute on page loaded (optional) | 337 | * @param function then Next step function to execute on page loaded (optional) | ... | ... |
-
Please register or sign in to post a comment