poltergeist 0.7.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # Poltergeist - A PhantomJS driver for Capybara #
2
2
 
3
- Version: 0.7.0
3
+ Version: 1.0
4
4
 
5
5
  [![Build Status](https://secure.travis-ci.org/jonleighton/poltergeist.png)](http://travis-ci.org/jonleighton/poltergeist)
6
- [![Dependency Status](https://gemnasium.com/jonleighton/poltergeist.png)](https://gemnasium.com/jonleighton/poltergeist)
7
6
 
8
7
  Poltergeist is a driver for [Capybara](https://github.com/jnicklas/capybara). It allows you to
9
8
  run your Capybara tests on a headless [WebKit](http://webkit.org) browser,
@@ -25,46 +24,41 @@ detail](https://github.com/jnicklas/capybara/blob/master/README.md#transactions-
25
24
 
26
25
  ## Installing PhantomJS ##
27
26
 
28
- You need at least PhantomJS 1.6.0, but 1.6.1 is recommended as there some issues with the former.
29
- There are *no other external dependencies* (you don't need Qt, or a running X
30
- server, etc.)
27
+ You need at least PhantomJS 1.7.0. There are *no other external
28
+ dependencies* (you don't need Qt, or a running X server, etc.)
31
29
 
32
30
  ### Mac ###
33
31
 
34
- * *Manual install*: [Download this](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-macosx-static.zip&can=2&q=)
35
32
  * *Homebrew*: `brew install phantomjs`
33
+ * *Manual install*: [Download this](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.7.0-macosx.zip&can=2&q=)
36
34
 
37
35
  ### Linux ###
38
36
 
39
37
  * Download the [32
40
- bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-linux-i686-dynamic.tar.bz2&can=2&q=)
38
+ bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.7.0-linux-i686.tar.bz2&can=2&q=)
41
39
  or [64
42
- bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-linux-x86_64-dynamic.tar.bz2&can=2&q=)
40
+ bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.7.0-linux-x86_64.tar.bz2&can=2&q=)
43
41
  binary.
44
- * Extract it: `sudo tar xvjf phantomjs-1.6.1-linux-*-dynamic.tar.gz -C /usr/local`
45
- * Link it: `sudo ln -s /usr/local/phantomjs-1.6.1-linux*/bin/phantomjs /usr/local/bin/phantomjs`
46
-
47
- (Note that you cannot copy the `/usr/local/phantomjs/bin/phantomjs`
48
- binary elsewhere on its own as it dynamically links with other files in
49
- `/usr/local/phantomjs/lib`.)
42
+ * Extract the tarball and copy `bin/phantomjs` into your `PATH`
50
43
 
51
44
  ### Manual compilation ###
52
45
 
53
46
  Do this as a last resort if the binaries don't work for you. It will
54
47
  take quite a long time as it has to build WebKit.
55
48
 
56
- * Download [the source tarball](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-source.zip&can=2&q=)
49
+ * Download [the source tarball](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.7.0-source.zip&can=2&q=)
57
50
  * Extract and cd in
58
51
  * `./build.sh`
59
52
 
60
- ## Compatibility ##
53
+ (See also the [PhantomJS building
54
+ guide](http://phantomjs.org/build.html).)
61
55
 
62
- Supported: MRI 1.8.7, MRI 1.9.2, MRI 1.9.3, JRuby 1.8, JRuby 1.9.
56
+ ## Compatibility ##
63
57
 
64
- Not supported:
58
+ Supported: MRI 1.8.7, MRI 1.9.2, MRI 1.9.3, JRuby 1.8, JRuby 1.9,
59
+ Rubinius 1.8 on UNIX platforms.
65
60
 
66
- * Rubinius
67
- * Windows
61
+ Not supported: Rubinius 1.9, Windows.
68
62
 
69
63
  Contributions are welcome in order to move 'unsupported'
70
64
  items into the 'supported' list.
@@ -74,6 +68,11 @@ items into the 'supported' list.
74
68
  There are no special steps to take. You don't need Xvfb or any running X
75
69
  server at all.
76
70
 
71
+ [Travis CI](https://travis-ci.org/) has PhantomJS pre-installed, but it
72
+ might not be the latest version. If you need to install the latest
73
+ version, [check out the .travis.yml that Poltergeist
74
+ uses](https://github.com/jonleighton/poltergeist/blob/master/.travis.yml).
75
+
77
76
  Depending on your tests, one thing that you may need is some fonts. If
78
77
  you're getting errors on a CI that don't occur during development then
79
78
  try taking some screenshots - it may well be missing fonts throwing
@@ -82,8 +81,16 @@ to install.
82
81
 
83
82
  ## What's supported? ##
84
83
 
85
- Poltergeist supports basically everything that is supported by the stock Selenium driver,
86
- including Javascript, drag-and-drop, etc.
84
+ Poltergeist supports all the mandatory features for a Capybara driver,
85
+ and the following optional features:
86
+
87
+ * `page.evaluate_script` and `page.execute_script`
88
+ * `page.within_frame`
89
+ * `page.within_window`
90
+ * `page.status_code`
91
+ * `page.response_headers`
92
+ * cookie handling
93
+ * drag-and-drop
87
94
 
88
95
  There are some additional features:
89
96
 
@@ -118,13 +125,12 @@ here](http://jonathanleighton.com/articles/2012/poltergeist-0-6-0/)
118
125
  Additional HTTP request headers can be set like so:
119
126
 
120
127
  ``` ruby
121
- page.driver.headers = {
122
- "Cookie" => "foo=bar",
123
- "Host" => "foo.com"
124
- }
128
+ page.driver.headers = { "User-Agent" => "Poltergeist" }
125
129
  ```
126
130
 
127
- They will be cleared between tests, so you do not have to do this manually.
131
+ The extra headers will apply to all subsequent HTTP requests (including
132
+ requests for assets, AJAX, etc). They will be automatically cleared at
133
+ the end of the test.
128
134
 
129
135
  ### Inspecting network traffic ###
130
136
 
@@ -133,6 +139,20 @@ loaded) on the current page by calling `page.driver.network_traffic`.
133
139
  This returns an array of request objects. A request object has a
134
140
  `response_parts` method containing data about the response chunks.
135
141
 
142
+ ### Manipulating cookies ###
143
+
144
+ The following methods are used to inspect and manipulate cookies:
145
+
146
+ * `page.driver.cookies` - a hash of cookies accessible to the current
147
+ page. The keys are cookie names. The values are `Cookie` objects, with
148
+ the following methods: `name`, `value`, `domain`, `path`, `secure?`,
149
+ `httponly?`, `expires`.
150
+ * `page.driver.set_cookie(name, value, options = {})` - set a cookie.
151
+ The options hash can take the following keys: `:domain`, `:path`,
152
+ `:secure`, `:httponly`, `:expires`. `:expires` should be a `Time`
153
+ object.
154
+ * `page.driver.remove_cookie(name)` - remove a cookie
155
+
136
156
  ## Customization ##
137
157
 
138
158
  You can customize the way that Capybara sets up Poltegeist via the following code in your
@@ -158,30 +178,163 @@ end
158
178
  as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
159
179
  * `:phantomjs_options` (Array) - Additional [command line options](http://code.google.com/p/phantomjs/wiki/Interface#Command-line_Options)
160
180
  to be passed to PhantomJS, e.g. `['--load-images=no', '--ignore-ssl-errors=yes']`
181
+ * `:port` (Fixnum) - The port which should be used to communicate
182
+ with the PhantomJS process. Default: 44678.
183
+
184
+ ## Troubleshooting ##
185
+
186
+ Unfortunately, the nature of full-stack testing is that things can and
187
+ do go wrong from time to time. This section aims to highlight a number
188
+ of common problems and provide ideas about how you can work around them.
189
+
190
+ ### DeadClient errors ###
191
+
192
+ Sometimes PhantomJS crashes during a test. There are basically two kinds
193
+ of crashes: those that can be reproduced every time, and those that
194
+ occur sporadically and are not easily reproduced.
195
+
196
+ If your crash happens every time, you should read the [PhantomJS crash
197
+ reporting
198
+ guide](https://github.com/ariya/phantomjs/wiki/Crash-Reporting) and file
199
+ a bug against PhantomJS. Feel free to also file a bug against
200
+ Poltergeist in case there are workarounds that can be implemented within
201
+ Poltergeist. Also, if lots of Poltergeist users are experiencing the
202
+ same crash then fixing it will move up the priority list.
203
+
204
+ If your crash is sporadic, there is less that can be done. Often these
205
+ issues are very complicated and difficult to track down. It may be that
206
+ the crash has already been fixed in a newer version of WebKit that will
207
+ eventually find its way into PhantomJS. It's still worth reporting your
208
+ bug against PhantomJS, but it's probably not worth filing a bug against
209
+ Poltergeist as there's not much we can do.
210
+
211
+ If you experience sporadic crashes a lot, it may be worth configuring
212
+ your CI to automatically re-run failing tests before reporting a failed
213
+ build.
214
+
215
+ ### ClickFailed errors ###
216
+
217
+ When Poltergeist clicks on an element, rather than generating a DOM
218
+ click event, it actually generates a "proper" click. This is much closer
219
+ to what happens when a real user clicks on the page - but it means that
220
+ Poltergeist must scroll the page to where the element is, and work out
221
+ the correct co-ordinates to click. If the element is covered up by
222
+ another element, the click will fail (this is a good thing - because
223
+ your user won't be able to click a covered up element either).
224
+
225
+ Sometimes there can be issues with this behavior. If you have problems,
226
+ it's worth taking screenshots of the page and trying to work out what's
227
+ going on. If your click is failing, but you're not getting a
228
+ `ClickFailed` error, then you can turn on the `:debug` option and look
229
+ in the output to see what co-ordinates Poltergeist is using for the
230
+ click. You can then cross-reference this with a screenshot to see if
231
+ something is obviously wrong.
232
+
233
+ If you can't figure out what's going on and just want to work around the
234
+ problem so you can get on with life, consider using a DOM click
235
+ event. For example, if this code is failing:
161
236
 
162
- ## Bugs ##
237
+ ``` ruby
238
+ click_button "Save"
239
+ ```
163
240
 
164
- Please file bug reports on Github and include example code to reproduce the problem wherever
165
- possible. (Tests are even better.) Please also provide the output with
166
- `:debug` turned on, and screenshots if you think it's relevant.
241
+ Then try:
167
242
 
168
- ## Hacking ##
243
+ ``` ruby
244
+ find_button("Save").trigger('click')
245
+ ```
246
+
247
+ ### Timing problems ###
248
+
249
+ Sometimes tests pass and fail sporadically. This is often because there
250
+ is some problem synchronising events properly. It's often
251
+ straightforward to verify this by adding `sleep` statements into your
252
+ test to allow sufficient time for the page to settle.
253
+
254
+ If you have these types of problems, read through the [Capybara
255
+ documentation on asynchronous
256
+ Javascript](https://github.com/jnicklas/capybara#asynchronous-javascript-ajax-and-friends)
257
+ which explains the tools that Capybara provides for dealing with this.
169
258
 
170
- Contributions are very welcome and I will happily give commit access to
171
- anyone who does a few good pull requests.
259
+ ### General troubleshooting hints ###
172
260
 
173
- To get setup, run `bundle install`. You can run the full test suite with
174
- `rspec spec/` or `rake`.
261
+ * Configure Poltergeist with `:debug` turned on so you can see its
262
+ communication with PhantomJS.
263
+ * Take screenshots to figure out what the state of your page is when the
264
+ problem occurs.
265
+ * Use the remote web inspector in case it provides any useful insight
266
+ * Consider downloading the Poltergeist source and using `console.log`
267
+ debugging to figure out what's going on inside PhantomJS. (This will
268
+ require an understanding of the Poltergeist source code and PhantomJS,
269
+ so it's only for the committed!)
175
270
 
176
- While PhantomJS is capable of compiling and running CoffeeScript code
177
- directly, I prefer to compile the code myself and distribute that (it
178
- makes debugging easier). Running `rake autocompile` will watch the
179
- `.coffee` files for changes, and compile them into
180
- `lib/capybara/client/compiled`.
271
+ ### Filing a bug ###
272
+
273
+ If you can provide specific steps to reproduce your problem, or have
274
+ specific information that might help other help you track down the
275
+ problem, then please file a bug on Github.
276
+
277
+ Include as much information as possible. For example:
278
+
279
+ * Specific steps to reproduce where possible (failing tests are even
280
+ better)
281
+ * The output obtained from running Poltergeist with `:debug` turned on
282
+ * Screenshots
283
+ * Stack traces if there are any Ruby on Javascript exceptions generated
284
+ * The Poltergeist and PhantomJS version numbers used
285
+ * The operating system name and version used
181
286
 
182
287
  ## Changes ##
183
288
 
184
- ### 0.7.0 ###
289
+ ### 1.0 ###
290
+
291
+ #### Features ####
292
+
293
+ * Click co-ordinates are shown in the debug log. You can use this in
294
+ combination with `page.driver.render` to work out where clicks are
295
+ actually happening if you are having trouble.
296
+ * Added `:port` configuration option and made the default port 44678
297
+ rather than a random available port.
298
+ * Support for Capybara's `page.response_headers` API to retrieve the
299
+ headers of the last page load.
300
+ * Support for cookie manipulation. [Issue #12]
301
+ * Frame switching support now uses native PhantomJS APIs. (This might
302
+ make it work better, but in general it's a badly tested area both in
303
+ Capybara and Poltergeist.)
304
+ * Support for the Capybara window switching API (`page.within_window`).
305
+
306
+ #### Bug fixes ####
307
+
308
+ * Prevent `TypeError: 'undefined' is not an object (evaluating
309
+ 'rect.top')` error when clicking an element with `display: none`.
310
+ The click will fail, but an obsolete node error will be raised, meaning
311
+ that Capybara's retry mechanisms will kick in. [Issue #130]
312
+ * Mouse over the element we will click, before clicking it. This
313
+ enables `:hover` effects etc to trigger before the click happens,
314
+ which can affect the click in some cases. [Issue #120]
315
+ * Don't blow up when `evaluate_script` is called with a cyclic
316
+ structure.
317
+ * Fix the text method for title elements, so it doesn't return an
318
+ empty string.
319
+ * Fixed problem with cookies not being clearer between tests on
320
+ PhantomJS 1.7
321
+ * Fixed Javascript errors during page load causes TimeoutErrors.
322
+ [Issue #124]
323
+ * Ensure the User-Agent header can be set successfully. (Klaus Hartl)
324
+ [Issue #127]
325
+ * Use `el.innerText` for `Node#text`. This ensures that e.g. `<br>` is
326
+ returned as a space. It also simplifies the method. [Issue #139]
327
+ * Fix status code support when a response redirects to another URL.
328
+ This was previously tested to ensure it would return the status code
329
+ of the redirected URL, but the test was falsely broken and the
330
+ implementation was also broken.
331
+ * Fixed visiting URLs where only a hash change occurs (no HTTP
332
+ request). [Issue #79]
333
+ * Setting `page.driver.headers` now applies the headers to all
334
+ requests, not just calls to `visit`. (So XHR, asset requests, etc
335
+ will all receive the headers.) [Issue #149]
336
+
337
+ ### 0.7 ###
185
338
 
186
339
  #### Features ####
187
340
 
@@ -210,14 +363,14 @@ makes debugging easier). Running `rake autocompile` will watch the
210
363
  happened when dealing with pages that include JS rewriting
211
364
  Array.prototype.toJSON. (Tom Stuart) [Issue #63]
212
365
 
213
- ### 0.6.0 ###
366
+ ### 0.6 ###
214
367
 
215
368
  #### Features ####
216
369
 
217
370
  * Updated to PhantomJS 1.5.0, giving us proper support for reporting
218
371
  Javascript exception backtraces.
219
372
 
220
- ### 0.5.0 ###
373
+ ### 0.5 ###
221
374
 
222
375
  #### Features ####
223
376
 
@@ -226,65 +379,52 @@ makes debugging easier). Running `rake autocompile` will watch the
226
379
  want to click), the user will now see an exception explaining what
227
380
  happened and which element would actually be targeted by the click. This
228
381
  should aid debugging. [Issue #25]
229
-
230
382
  * Click elements at their middle position rather than the top-left.
231
383
  This is presumed to be more likely to succeed because the top-left
232
384
  may be obscured by overlapping elements, negative margins, etc. [Issue #26]
233
-
234
385
  * Add experimental support for using the remote WebKit web inspector.
235
386
  This will only work with PhantomJS 1.5, which is not yet released,
236
387
  so it won't be officially supported by Poltergeist until 1.5 is
237
388
  released. [Issue #31]
238
-
239
389
  * Add `page.driver.quit` method. If you spawn additional Capybara
240
390
  sessions, you might want to use this to reap the child phantomjs
241
391
  process. [Issue #24]
242
-
243
392
  * Errors produced by Javascript on the page will now generate an
244
393
  exception within Ruby. [Issue #27]
245
-
246
394
  * JRuby support. [Issue #20]
247
395
 
248
396
  #### Bug fixes ####
249
397
 
250
398
  * Fix bug where we could end up interacting with an obsolete element. [Issue #30]
251
-
252
399
  * Raise an suitable error if PhantomJS returns a non-zero exit status.
253
400
  Previously a version error would be raised, indicating that the
254
401
  PhantomJS version was too old when in fact it did not start at all. [Issue #23]
255
-
256
402
  * Ensure the `:timeout` option is actually used. [Issue #36]
257
-
258
403
  * Nodes need to know which page they are associated with. Before this,
259
404
  if Javascript caused a new page to load, existing node references
260
405
  would be wrong, but wouldn't raise an ObsoleteNode error. [Issue #39]
261
-
262
406
  * In some circumstances, we could end up missing an inline element
263
407
  when attempting to click it. This is due to the use of
264
408
  `getBoundingClientRect()`. We're now using `getClientRects()` to
265
409
  address this.
266
410
 
267
- ### 0.4.0 ###
411
+ ### 0.4 ###
268
412
 
269
413
  * Element click position is now calculated using the native
270
414
  `getBoundingClientRect()` method, which will be faster and less
271
415
  buggy.
272
-
273
416
  * Handle `window.confirm()`. Always returns true, which is the same
274
417
  as capybara-webkit. [Issue #10]
275
-
276
418
  * Handle `window.prompt()`. Returns the default value, if present, or
277
419
  null.
278
-
279
420
  * Fix bug with page Javascript page loading causing problems. [Issue #19]
280
421
 
281
- ### 0.3.0 ###
422
+ ### 0.3 ###
282
423
 
283
424
  * There was a bad bug to do with clicking elements in a page where the
284
425
  page is smaller than the window. The incorrect position would be
285
426
  calculated, and so the click would happen in the wrong place. This is
286
427
  fixed. [Issue #8]
287
-
288
428
  * Poltergeist didn't work in conjunction with the Thin web server,
289
429
  because that server uses Event Machine, and Poltergeist was assuming
290
430
  that it was the only thing in the process using EventMachine.
@@ -294,15 +434,14 @@ makes debugging easier). Running `rake autocompile` will watch the
294
434
  no longer have the overhead of running a mostly-idle event loop.
295
435
 
296
436
  [Issue #6]
297
-
298
437
  * Added the `:timeout` option to configure the timeout when talking to
299
438
  PhantomJS.
300
439
 
301
- ### 0.2.0 ###
440
+ ### 0.2 ###
302
441
 
303
442
  * First version considered 'ready', hopefully fewer problems.
304
443
 
305
- ### 0.1.0 ###
444
+ ### 0.1 ###
306
445
 
307
446
  * First version, various problems.
308
447
 
@@ -8,12 +8,12 @@ module Capybara
8
8
  require 'capybara/poltergeist/server'
9
9
  require 'capybara/poltergeist/web_socket_server'
10
10
  require 'capybara/poltergeist/client'
11
- require 'capybara/poltergeist/util'
12
11
  require 'capybara/poltergeist/inspector'
13
12
  require 'capybara/poltergeist/spawn'
14
13
  require 'capybara/poltergeist/json'
15
14
  require 'capybara/poltergeist/network_traffic'
16
15
  require 'capybara/poltergeist/errors'
16
+ require 'capybara/poltergeist/cookie'
17
17
  end
18
18
  end
19
19
 
@@ -1,4 +1,5 @@
1
1
  require 'multi_json'
2
+ require 'time'
2
3
 
3
4
  module Capybara::Poltergeist
4
5
  class Browser
@@ -16,8 +17,8 @@ module Capybara::Poltergeist
16
17
  client.restart
17
18
  end
18
19
 
19
- def visit(url, headers)
20
- command 'visit', url, headers
20
+ def visit(url)
21
+ command 'visit', url
21
22
  end
22
23
 
23
24
  def current_url
@@ -81,13 +82,20 @@ module Capybara::Poltergeist
81
82
  command 'execute', script
82
83
  end
83
84
 
84
- def within_frame(id, &block)
85
- command 'push_frame', id
85
+ def within_frame(name, &block)
86
+ command 'push_frame', name
86
87
  yield
87
88
  ensure
88
89
  command 'pop_frame'
89
90
  end
90
91
 
92
+ def within_window(name, &block)
93
+ command 'push_window', name
94
+ yield
95
+ ensure
96
+ command 'pop_window'
97
+ end
98
+
91
99
  def click(page_id, id)
92
100
  command 'click', page_id, id
93
101
  end
@@ -129,6 +137,30 @@ module Capybara::Poltergeist
129
137
  command('equals', page_id, id, other_id)
130
138
  end
131
139
 
140
+ def set_headers(headers)
141
+ command 'set_headers', headers
142
+ end
143
+
144
+ def response_headers
145
+ command 'response_headers'
146
+ end
147
+
148
+ def cookies
149
+ Hash[command('cookies').map { |cookie| [cookie['name'], Cookie.new(cookie)] }]
150
+ end
151
+
152
+ def set_cookie(cookie)
153
+ if cookie[:expires].respond_to?(:httpdate)
154
+ cookie[:expires] = cookie[:expires].httpdate
155
+ end
156
+
157
+ command 'set_cookie', cookie
158
+ end
159
+
160
+ def remove_cookie(name)
161
+ command 'remove_cookie', name
162
+ end
163
+
132
164
  def command(name, *args)
133
165
  message = { 'name' => name, 'args' => args }
134
166
  log message.inspect