poltergeist 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Poltergeist - A PhantomJS driver for Capybara #
2
2
 
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
 
5
5
  [![Build Status](https://secure.travis-ci.org/jonleighton/poltergeist.png)](http://travis-ci.org/jonleighton/poltergeist)
6
6
 
@@ -12,8 +12,32 @@ provided by [PhantomJS](http://www.phantomjs.org/).
12
12
 
13
13
  Add `poltergeist` to your Gemfile, and add in your test setup add:
14
14
 
15
- require 'capybara/poltergeist'
16
- Capybara.javascript_driver = :poltergeist
15
+ ``` ruby
16
+ require 'capybara/poltergeist'
17
+ Capybara.javascript_driver = :poltergeist
18
+ ```
19
+
20
+ ## Important note about Rack versions < 1.3.0 ##
21
+
22
+ Prior to version 1.3.0, the Rack handlers for Mongrel and Thin wrap your
23
+ app in the `Rack::Chunked` middleware so that it uses
24
+ `Transfer-Encoding: chunked`
25
+ ([commit](https://github.com/rack/rack/commit/50cdd0bf000a9ffb3eb3760fda2ff3e1ad18f3a7)).
26
+ This has been observed to cause problems,
27
+ probably due to race conditions in Qt's HTTP handling code, so you are
28
+ recommended to avoid this by specifying your own server setup for
29
+ Capybara:
30
+
31
+ ``` ruby
32
+ Capybara.server do |app, port|
33
+ require 'rack/handler/thin'
34
+ Thin::Logging.silent = true
35
+ Thin::Server.new('0.0.0.0', port, app).start
36
+ end
37
+ ```
38
+
39
+ If you're using Rails 3.0, this affects you. If you're using Rails 3.1+,
40
+ this doesn't affect you.
17
41
 
18
42
  ## Installing PhantomJS ##
19
43
 
@@ -32,9 +56,7 @@ the relationship between `bin/phantomjs` and `lib/`. This is because the
32
56
  `bin/phantomjs` binary looks in `../lib/` for its library files. So the
33
57
  best thing to do is to link (rather than copy) it into your `PATH`:
34
58
 
35
- ```
36
- ln -s /path/to/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
37
- ```
59
+ ln -s /path/to/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
38
60
 
39
61
  ### Compiling PhantomJS ###
40
62
 
@@ -53,7 +75,8 @@ you should copy (or link) the `bin/phantomjs` binary into your `PATH`.
53
75
 
54
76
  ## Running on a CI ##
55
77
 
56
- Currently PhantomJS is not 'truly headless', so to run it on a continuous integration
78
+ Currently PhantomJS is not yet 'truly headless' (but that's planned for the future),
79
+ so to run it on a continuous integration
57
80
  server you will need to install [Xvfb](http://en.wikipedia.org/wiki/Xvfb).
58
81
 
59
82
  ### On any generic server ###
@@ -98,16 +121,18 @@ size to 1024x768 by default, but you can set this yourself with `page.driver.res
98
121
  You can customize the way that Capybara sets up Poltegeist via the following code in your
99
122
  test setup:
100
123
 
101
- Capybara.register_driver :poltergeist do |app|
102
- Capybara::Poltergeist::Driver.new(app, options)
103
- end
124
+ ``` ruby
125
+ Capybara.register_driver :poltergeist do |app|
126
+ Capybara::Poltergeist::Driver.new(app, options)
127
+ end
128
+ ```
104
129
 
105
130
  `options` is a hash of options. The following options are supported:
106
131
 
107
- * `:phantomjs` (String) - A custom path to the phantomjs executable
108
- * `:debug` (Boolean) - When true, debug output is logged to `STDERR`
109
- * `:logger` (Object responding to `puts`) - When present, debug output is written to this object
110
- * `:timeout` (Numeric) - The number of seconds we'll wait for a response
132
+ * `:phantomjs` (String) - A custom path to the phantomjs executable
133
+ * `:debug` (Boolean) - When true, debug output is logged to `STDERR`
134
+ * `:logger` (Object responding to `puts`) - When present, debug output is written to this object
135
+ * `:timeout` (Numeric) - The number of seconds we'll wait for a response
111
136
  when communicating with PhantomJS. `nil` means wait forever. Default
112
137
  is 30.
113
138
 
@@ -117,22 +142,19 @@ Please file bug reports on Github and include example code to reproduce the prob
117
142
  possible. (Tests are even better.) Please also provide the output with
118
143
  `:debug` turned on, and screenshots if you think it's relevant.
119
144
 
120
- ## Why not use [capybara-webkit](https://github.com/thoughtbot/capybara-webkit)? ##
145
+ ## Differences from [capybara-webkit](https://github.com/thoughtbot/capybara-webkit) ##
121
146
 
122
- If capybara-webkit works for you, then by all means carry on using it.
147
+ Poltergeist is similar to capybara-webkit, but here are the key
148
+ differences:
123
149
 
124
- However, I have had some trouble with it, and Poltergeist basically started
125
- as an experiment to see whether a PhantomJS driver was possible. (It turned out it
126
- was, but only thanks to some new features since the 1.3 release.)
150
+ * It's more hackable. Poltergeist is written in Ruby + CoffeeScript.
151
+ We only have to worry about C++ when dealing with issues in
152
+ PhantomJS itself. In contrast, the majority of capybara-webkit is
153
+ written in C++.
127
154
 
128
- In the long term, I think having a PhantomJS driver makes sense, because that allows
129
- PhantomJS to concentrate on being an awesome headless browser, while the capybara driver
130
- (Poltergeist) is able to be the minimal amount of glue code necessary to drive the
131
- browser.
132
-
133
- I also find it more pleasant to hack in CoffeeScript than C++,
134
- particularly as my C++ experience only goes as far as trying to make
135
- PhantomJS/Qt/WebKit work with Poltergeist :)
155
+ * We're able to tap into the PhantomJS community. When PhantomJS
156
+ improves, Poltergeist improves. User's don't have to install Qt
157
+ because self-contained PhantomJS binary packages are available.
136
158
 
137
159
  ## Hacking ##
138
160
 
@@ -142,11 +164,6 @@ anyone who does a few good pull requests.
142
164
  To get setup, run `bundle install`. You can run the full test suite with
143
165
  `rspec spec/` or `rake`.
144
166
 
145
- I previously set up the repository on [Travis CI](http://travis-ci.org/)
146
- but unfortunately given they need a custom-built Qt+PhantomJS in order
147
- to pass, it can't be used for now. When static Linux PhantomJS builds
148
- are working this can be revisited.
149
-
150
167
  While PhantomJS is capable of compiling and running CoffeeScript code
151
168
  directly, I prefer to compile the code myself and distribute that (it
152
169
  makes debugging easier). Running `rake autocompile` will watch the
@@ -155,7 +172,21 @@ makes debugging easier). Running `rake autocompile` will watch the
155
172
 
156
173
  ## Changes ##
157
174
 
158
- ### 0.3 ###
175
+ ### 0.4.0 ###
176
+
177
+ * Element click position is now calculated using the native
178
+ `getBoundingClientRect()` method, which will be faster and less
179
+ buggy.
180
+
181
+ * Handle `window.confirm()`. Always returns true, which is the same
182
+ as capybara-webkit. [Issue #10]
183
+
184
+ * Handle `window.prompt()`. Returns the default value, if present, or
185
+ null.
186
+
187
+ * Fix bug with page Javascript page loading causing problems. [Issue #19]
188
+
189
+ ### 0.3.0 ###
159
190
 
160
191
  * There was a bad bug to do with clicking elements in a page where the
161
192
  page is smaller than the window. The incorrect position would be
@@ -175,11 +206,11 @@ makes debugging easier). Running `rake autocompile` will watch the
175
206
  * Added the `:timeout` option to configure the timeout when talking to
176
207
  PhantomJS.
177
208
 
178
- ### 0.2 ###
209
+ ### 0.2.0 ###
179
210
 
180
211
  * First version considered 'ready', hopefully fewer problems.
181
212
 
182
- ### 0.1 ###
213
+ ### 0.1.0 ###
183
214
 
184
215
  * First version, various problems.
185
216
 
@@ -9,7 +9,7 @@ module Capybara::Poltergeist
9
9
  def initialize(options = {})
10
10
  @options = options
11
11
  @server = Server.new(options.fetch(:timeout, DEFAULT_TIMEOUT))
12
- @client = Client.new(server.port, options[:phantomjs])
12
+ @client = Client.start(server.port, options[:phantomjs])
13
13
  end
14
14
 
15
15
  def timeout
@@ -2,29 +2,47 @@ require 'sfl'
2
2
 
3
3
  module Capybara::Poltergeist
4
4
  class Client
5
- PHANTOM_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__)
5
+ PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__)
6
+ PHANTOMJS_VERSION = "1.4.1"
6
7
 
7
- attr_reader :thread, :pid, :err, :port, :path
8
+ attr_reader :pid, :port, :path
9
+
10
+ def self.start(*args)
11
+ client = new(*args)
12
+ client.start
13
+ client
14
+ end
8
15
 
9
16
  def initialize(port, path = nil)
10
17
  @port = port
11
18
  @path = path || 'phantomjs'
12
-
13
- start
14
19
  at_exit { stop }
15
20
  end
16
21
 
17
22
  def start
18
- @pid = Kernel.spawn("#{path} #{PHANTOM_SCRIPT} #{port}")
23
+ check_phantomjs_version
24
+ @pid = Kernel.spawn("#{path} #{PHANTOMJS_SCRIPT} #{port}")
19
25
  end
20
26
 
21
27
  def stop
22
- Process.kill('TERM', pid)
28
+ Process.kill('TERM', pid) if pid
23
29
  end
24
30
 
25
31
  def restart
26
32
  stop
27
33
  start
28
34
  end
35
+
36
+ private
37
+
38
+ def check_phantomjs_version
39
+ return if @phantomjs_version_checked
40
+
41
+ version = `#{path} --version`.chomp
42
+ if version < PHANTOMJS_VERSION
43
+ raise PhantomJSTooOld.new(version)
44
+ end
45
+ @phantomjs_version_checked = true
46
+ end
29
47
  end
30
48
  end
@@ -151,18 +151,8 @@ class PoltergeistAgent.Node
151
151
  true
152
152
 
153
153
  position: ->
154
- pos = (element) ->
155
- x = element.offsetLeft
156
- y = element.offsetTop
157
-
158
- if element.offsetParent
159
- parentPos = pos(element.offsetParent)
160
-
161
- x += parentPos.x
162
- y += parentPos.y
163
-
164
- { x: x, y: y }
165
- pos @element
154
+ rect = @element.getBoundingClientRect()
155
+ { top: rect.top, left: rect.left }
166
156
 
167
157
  trigger: (name) ->
168
158
  if Node.EVENTS.MOUSE.indexOf(name) != -1
@@ -185,3 +175,6 @@ document.addEventListener(
185
175
  'DOMContentLoaded',
186
176
  -> console.log('__DOMContentLoaded')
187
177
  )
178
+
179
+ window.confirm = (message) -> true
180
+ window.prompt = (message, _default) -> _default or null
@@ -1,19 +1,23 @@
1
1
  class Poltergeist.Browser
2
2
  constructor: (@owner) ->
3
- @awaiting_response = false
3
+ @state = 'default'
4
4
  this.resetPage()
5
5
 
6
6
  resetPage: ->
7
7
  @page.release() if @page?
8
8
 
9
9
  @page = new Poltergeist.WebPage
10
+
11
+ @page.onLoadStarted = =>
12
+ @state = 'loading' if @state == 'clicked'
13
+
10
14
  @page.onLoadFinished = (status) =>
11
- if @awaiting_response
15
+ if @state == 'loading'
12
16
  @owner.sendResponse(status)
13
- @awaiting_response = false
17
+ @state = 'default'
14
18
 
15
19
  visit: (url) ->
16
- @awaiting_response = true
20
+ @state = 'loading'
17
21
  @page.open(url)
18
22
 
19
23
  current_url: ->
@@ -73,7 +77,7 @@ class Poltergeist.Browser
73
77
  @owner.sendResponse @page.get(id).isVisible()
74
78
 
75
79
  evaluate: (script) ->
76
- @owner.sendResponse @page.evaluate("function() { return #{script} }")
80
+ @owner.sendResponse JSON.parse(@page.evaluate("function() { return JSON.stringify(#{script}) }"))
77
81
 
78
82
  execute: (script) ->
79
83
  @page.execute("function() { #{script} }")
@@ -88,13 +92,9 @@ class Poltergeist.Browser
88
92
  @owner.sendResponse(true)
89
93
 
90
94
  click: (id) ->
91
- load_detected = false
92
-
93
- # Detect if the click event triggers a page load. If it does, don't send
94
- # a response here, because the response will be sent once the page has loaded.
95
- @page.onLoadStarted = =>
96
- @awaiting_response = true
97
- load_detected = true
95
+ # If the click event triggers onLoadStarted, we will transition to the 'loading'
96
+ # state and wait for onLoadFinished before sending a response.
97
+ @state = 'clicked'
98
98
 
99
99
  @page.get(id).click()
100
100
 
@@ -102,8 +102,9 @@ class Poltergeist.Browser
102
102
  # callback can (possibly) fire, before we decide whether to send a response.
103
103
  setTimeout(
104
104
  =>
105
- @page.onLoadStarted = null
106
- @owner.sendResponse(true) unless load_detected
105
+ if @state == 'clicked'
106
+ @state = 'default'
107
+ @owner.sendResponse(true)
107
108
  ,
108
109
  10
109
110
  )
@@ -177,22 +177,12 @@ PoltergeistAgent.Node = (function() {
177
177
  }
178
178
  };
179
179
  Node.prototype.position = function() {
180
- var pos;
181
- pos = function(element) {
182
- var parentPos, x, y;
183
- x = element.offsetLeft;
184
- y = element.offsetTop;
185
- if (element.offsetParent) {
186
- parentPos = pos(element.offsetParent);
187
- x += parentPos.x;
188
- y += parentPos.y;
189
- }
190
- return {
191
- x: x,
192
- y: y
193
- };
180
+ var rect;
181
+ rect = this.element.getBoundingClientRect();
182
+ return {
183
+ top: rect.top,
184
+ left: rect.left
194
185
  };
195
- return pos(this.element);
196
186
  };
197
187
  Node.prototype.trigger = function(name) {
198
188
  var event;
@@ -212,4 +202,10 @@ PoltergeistAgent.Node = (function() {
212
202
  window.__poltergeist = new PoltergeistAgent;
213
203
  document.addEventListener('DOMContentLoaded', function() {
214
204
  return console.log('__DOMContentLoaded');
215
- });
205
+ });
206
+ window.confirm = function(message) {
207
+ return true;
208
+ };
209
+ window.prompt = function(message, _default) {
210
+ return _default || null;
211
+ };
@@ -2,7 +2,7 @@ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments)
2
2
  Poltergeist.Browser = (function() {
3
3
  function Browser(owner) {
4
4
  this.owner = owner;
5
- this.awaiting_response = false;
5
+ this.state = 'default';
6
6
  this.resetPage();
7
7
  }
8
8
  Browser.prototype.resetPage = function() {
@@ -10,15 +10,20 @@ Poltergeist.Browser = (function() {
10
10
  this.page.release();
11
11
  }
12
12
  this.page = new Poltergeist.WebPage;
13
+ this.page.onLoadStarted = __bind(function() {
14
+ if (this.state === 'clicked') {
15
+ return this.state = 'loading';
16
+ }
17
+ }, this);
13
18
  return this.page.onLoadFinished = __bind(function(status) {
14
- if (this.awaiting_response) {
19
+ if (this.state === 'loading') {
15
20
  this.owner.sendResponse(status);
16
- return this.awaiting_response = false;
21
+ return this.state = 'default';
17
22
  }
18
23
  }, this);
19
24
  };
20
25
  Browser.prototype.visit = function(url) {
21
- this.awaiting_response = true;
26
+ this.state = 'loading';
22
27
  return this.page.open(url);
23
28
  };
24
29
  Browser.prototype.current_url = function() {
@@ -71,7 +76,7 @@ Poltergeist.Browser = (function() {
71
76
  return this.owner.sendResponse(this.page.get(id).isVisible());
72
77
  };
73
78
  Browser.prototype.evaluate = function(script) {
74
- return this.owner.sendResponse(this.page.evaluate("function() { return " + script + " }"));
79
+ return this.owner.sendResponse(JSON.parse(this.page.evaluate("function() { return JSON.stringify(" + script + ") }")));
75
80
  };
76
81
  Browser.prototype.execute = function(script) {
77
82
  this.page.execute("function() { " + script + " }");
@@ -86,16 +91,11 @@ Poltergeist.Browser = (function() {
86
91
  return this.owner.sendResponse(true);
87
92
  };
88
93
  Browser.prototype.click = function(id) {
89
- var load_detected;
90
- load_detected = false;
91
- this.page.onLoadStarted = __bind(function() {
92
- this.awaiting_response = true;
93
- return load_detected = true;
94
- }, this);
94
+ this.state = 'clicked';
95
95
  this.page.get(id).click();
96
96
  return setTimeout(__bind(function() {
97
- this.page.onLoadStarted = null;
98
- if (!load_detected) {
97
+ if (this.state === 'clicked') {
98
+ this.state = 'default';
99
99
  return this.owner.sendResponse(true);
100
100
  }
101
101
  }, this), 10);
@@ -1,8 +1,4 @@
1
1
  var Poltergeist;
2
- if (("" + phantom.version.major + "." + phantom.version.minor + "." + phantom.version.patch) < "1.4.1") {
3
- console.log("Poltergeist requires a PhantomJS version of at least 1.4.1");
4
- phantom.exit(1);
5
- }
6
2
  Poltergeist = (function() {
7
3
  function Poltergeist(port) {
8
4
  this.browser = new Poltergeist.Browser(this);
@@ -29,7 +29,7 @@ Poltergeist.Node = (function() {
29
29
  _fn(name);
30
30
  }
31
31
  Node.prototype.scrollIntoView = function() {
32
- var dimensions, document, pos, scroll, viewport, _ref2, _ref3;
32
+ var adjust, dimensions, document, pos, scroll, viewport;
33
33
  dimensions = this.page.validatedDimensions();
34
34
  document = dimensions.document;
35
35
  viewport = dimensions.viewport;
@@ -38,38 +38,33 @@ Poltergeist.Node = (function() {
38
38
  left: dimensions.left,
39
39
  top: dimensions.top
40
40
  };
41
- if (!((dimensions.left <= (_ref2 = pos.x) && _ref2 < dimensions.right))) {
42
- scroll.left = Math.min(pos.x, document.width - viewport.width);
43
- }
44
- if (!((dimensions.top <= (_ref3 = pos.y) && _ref3 < dimensions.bottom))) {
45
- scroll.top = Math.min(pos.y, document.height - viewport.height);
46
- }
41
+ adjust = function(coord, measurement) {
42
+ if (pos[coord] < 0) {
43
+ return scroll[coord] = Math.max(0, scroll[coord] + pos[coord] - (viewport[measurement] / 2));
44
+ } else if (pos[coord] >= viewport[measurement]) {
45
+ return scroll[coord] = Math.min(document[measurement] - viewport[measurement], scroll[coord] + pos[coord] - viewport[measurement] + (viewport[measurement] / 2));
46
+ }
47
+ };
48
+ adjust('left', 'width');
49
+ adjust('top', 'height');
47
50
  if (scroll.left !== dimensions.left || scroll.top !== dimensions.top) {
48
51
  this.page.setScrollPosition(scroll);
52
+ pos = this.position();
49
53
  }
50
- return {
51
- position: this.relativePosition(pos, scroll),
52
- scroll: scroll
53
- };
54
- };
55
- Node.prototype.relativePosition = function(position, scroll) {
56
- return {
57
- x: position.x - scroll.left,
58
- y: position.y - scroll.top
59
- };
54
+ return pos;
60
55
  };
61
56
  Node.prototype.click = function() {
62
57
  var position;
63
- position = this.scrollIntoView().position;
64
- return this.page.sendEvent('click', position.x, position.y);
58
+ position = this.scrollIntoView();
59
+ return this.page.sendEvent('click', position.left, position.top);
65
60
  };
66
61
  Node.prototype.dragTo = function(other) {
67
- var otherPosition, position, scroll, _ref2;
68
- _ref2 = this.scrollIntoView(), position = _ref2.position, scroll = _ref2.scroll;
69
- otherPosition = this.relativePosition(other.position(), scroll);
70
- this.page.sendEvent('mousedown', position.x, position.y);
71
- this.page.sendEvent('mousemove', otherPosition.x, otherPosition.y);
72
- return this.page.sendEvent('mouseup', otherPosition.x, otherPosition.y);
62
+ var otherPosition, position;
63
+ position = this.scrollIntoView();
64
+ otherPosition = other.position();
65
+ this.page.sendEvent('mousedown', position.left, position.top);
66
+ this.page.sendEvent('mousemove', otherPosition.left, otherPosition.top);
67
+ return this.page.sendEvent('mouseup', otherPosition.left, otherPosition.top);
73
68
  };
74
69
  return Node;
75
70
  }).call(this);
@@ -107,10 +107,9 @@ Poltergeist.WebPage = (function() {
107
107
  };
108
108
  };
109
109
  WebPage.prototype.validatedDimensions = function() {
110
- var changed, dimensions, document, orig_left, orig_top;
110
+ var dimensions, document, orig_left, orig_top;
111
111
  dimensions = this.dimensions();
112
112
  document = dimensions.document;
113
- changed = false;
114
113
  orig_left = dimensions.left;
115
114
  orig_top = dimensions.top;
116
115
  if (dimensions.right > document.width) {
@@ -1,7 +1,3 @@
1
- if "#{phantom.version.major}.#{phantom.version.minor}.#{phantom.version.patch}" < "1.4.1"
2
- console.log "Poltergeist requires a PhantomJS version of at least 1.4.1"
3
- phantom.exit(1)
4
-
5
1
  class Poltergeist
6
2
  constructor: (port) ->
7
3
  @browser = new Poltergeist.Browser(this)
@@ -28,30 +28,36 @@ class Poltergeist.Node
28
28
 
29
29
  scroll = { left: dimensions.left, top: dimensions.top }
30
30
 
31
- unless dimensions.left <= pos.x < dimensions.right
32
- scroll.left = Math.min(pos.x, document.width - viewport.width)
33
-
34
- unless dimensions.top <= pos.y < dimensions.bottom
35
- scroll.top = Math.min(pos.y, document.height - viewport.height)
31
+ adjust = (coord, measurement) ->
32
+ if pos[coord] < 0
33
+ scroll[coord] = Math.max(
34
+ 0,
35
+ scroll[coord] + pos[coord] - (viewport[measurement] / 2)
36
+ )
37
+
38
+ else if pos[coord] >= viewport[measurement]
39
+ scroll[coord] = Math.min(
40
+ document[measurement] - viewport[measurement],
41
+ scroll[coord] + pos[coord] - viewport[measurement] + (viewport[measurement] / 2)
42
+ )
43
+
44
+ adjust('left', 'width')
45
+ adjust('top', 'height')
36
46
 
37
47
  if scroll.left != dimensions.left || scroll.top != dimensions.top
38
48
  @page.setScrollPosition(scroll)
49
+ pos = this.position()
39
50
 
40
- position: this.relativePosition(pos, scroll),
41
- scroll: scroll
42
-
43
- relativePosition: (position, scroll) ->
44
- x: position.x - scroll.left
45
- y: position.y - scroll.top
51
+ pos
46
52
 
47
53
  click: ->
48
- position = this.scrollIntoView().position
49
- @page.sendEvent('click', position.x, position.y)
54
+ position = this.scrollIntoView()
55
+ @page.sendEvent('click', position.left, position.top)
50
56
 
51
57
  dragTo: (other) ->
52
- { position, scroll } = this.scrollIntoView()
53
- otherPosition = this.relativePosition(other.position(), scroll)
58
+ position = this.scrollIntoView()
59
+ otherPosition = other.position()
54
60
 
55
- @page.sendEvent('mousedown', position.x, position.y)
56
- @page.sendEvent('mousemove', otherPosition.x, otherPosition.y)
57
- @page.sendEvent('mouseup', otherPosition.x, otherPosition.y)
61
+ @page.sendEvent('mousedown', position.left, position.top)
62
+ @page.sendEvent('mousemove', otherPosition.left, otherPosition.top)
63
+ @page.sendEvent('mouseup', otherPosition.left, otherPosition.top)
@@ -83,7 +83,6 @@ class Poltergeist.WebPage
83
83
  validatedDimensions: ->
84
84
  dimensions = this.dimensions()
85
85
  document = dimensions.document
86
- changed = false
87
86
 
88
87
  orig_left = dimensions.left
89
88
  orig_top = dimensions.top
@@ -42,5 +42,17 @@ module Capybara
42
42
  "The PhantomJS client died while processing #{@message}"
43
43
  end
44
44
  end
45
+
46
+ class PhantomJSTooOld < Error
47
+ attr_reader :version
48
+
49
+ def initialize(version)
50
+ @version = version
51
+ end
52
+
53
+ def message
54
+ "PhantomJS version #{version} is too old. You must use at least version #{Client::PHANTOMJS_VERSION}"
55
+ end
56
+ end
45
57
  end
46
58
  end
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Poltergeist
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poltergeist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-13 00:00:00.000000000 Z
12
+ date: 2012-02-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capybara
16
- requirement: &17990880 !ruby/object:Gem::Requirement
16
+ requirement: &16526020 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *17990880
24
+ version_requirements: *16526020
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &17990000 !ruby/object:Gem::Requirement
27
+ requirement: &16525520 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.6'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *17990000
35
+ version_requirements: *16525520
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sfl
38
- requirement: &17988720 !ruby/object:Gem::Requirement
38
+ requirement: &16525060 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '2.0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *17988720
46
+ version_requirements: *16525060
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: http_parser.rb
49
- requirement: &17987320 !ruby/object:Gem::Requirement
49
+ requirement: &16524600 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.5.3
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *17987320
57
+ version_requirements: *16524600
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: faye-websocket
60
- requirement: &17986640 !ruby/object:Gem::Requirement
60
+ requirement: &16524140 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,21 +65,21 @@ dependencies:
65
65
  version: 0.2.0
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *17986640
68
+ version_requirements: *16524140
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &17985780 !ruby/object:Gem::Requirement
71
+ requirement: &16523680 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
75
75
  - !ruby/object:Gem::Version
76
- version: 2.7.0
76
+ version: 2.8.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *17985780
79
+ version_requirements: *16523680
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: sinatra
82
- requirement: &17984960 !ruby/object:Gem::Requirement
82
+ requirement: &16523220 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '1.0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *17984960
90
+ version_requirements: *16523220
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rake
93
- requirement: &17967380 !ruby/object:Gem::Requirement
93
+ requirement: &16522760 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 0.9.2
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *17967380
101
+ version_requirements: *16522760
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: image_size
104
- requirement: &17966680 !ruby/object:Gem::Requirement
104
+ requirement: &16522300 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: '1.0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *17966680
112
+ version_requirements: *16522300
113
113
  description: PhantomJS driver for Capybara
114
114
  email:
115
115
  - j@jonathanleighton.com
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
160
  version: '0'
161
161
  requirements: []
162
162
  rubyforge_project:
163
- rubygems_version: 1.8.10
163
+ rubygems_version: 1.8.15
164
164
  signing_key:
165
165
  specification_version: 3
166
166
  summary: PhantomJS driver for Capybara