poltergeist 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ module Capybara::Poltergeist
2
+ class Inspector
3
+ BROWSERS = %w(chromium chromium-browser google-chrome safari)
4
+
5
+ def self.detect_browser
6
+ @browser ||= BROWSERS.find { |name| system("which #{name} &>/dev/null") }
7
+ end
8
+
9
+ def initialize(browser = nil)
10
+ @browser = browser.respond_to?(:to_str) ? browser : nil
11
+ end
12
+
13
+ def browser
14
+ @browser ||= self.class.detect_browser
15
+ end
16
+
17
+ def port
18
+ @port ||= Util.find_available_port
19
+ end
20
+
21
+ def url
22
+ "http://localhost:#{port}/"
23
+ end
24
+
25
+ def open
26
+ if browser
27
+ Spawn.spawn(browser, url)
28
+ else
29
+ raise Error, "Could not find a browser executable to open #{url}. " \
30
+ "You can specify one manually using e.g. `:inspector => 'chromium'` " \
31
+ "as a configuration option for Poltergeist."
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,12 @@
1
1
  module Capybara::Poltergeist
2
2
  class Node < Capybara::Driver::Node
3
+ attr_reader :page_id
4
+
5
+ def initialize(driver, page_id, id)
6
+ super(driver, id)
7
+ @page_id = page_id
8
+ end
9
+
3
10
  alias id native
4
11
 
5
12
  def browser
@@ -7,17 +14,20 @@ module Capybara::Poltergeist
7
14
  end
8
15
 
9
16
  def command(name, *args)
10
- browser.send(name, id, *args)
17
+ browser.send(name, page_id, id, *args)
11
18
  rescue BrowserError => error
12
- if error.text == 'Poltergeist.ObsoleteNode'
13
- raise ObsoleteNode.new(self)
19
+ case error.name
20
+ when 'Poltergeist.ObsoleteNode'
21
+ raise ObsoleteNode.new(self, error.response)
22
+ when 'Poltergeist.ClickFailed'
23
+ raise ClickFailed.new(self, error.response)
14
24
  else
15
- raise error
25
+ raise
16
26
  end
17
27
  end
18
28
 
19
29
  def find(selector)
20
- browser.find(selector, id).map { |node| self.class.new(driver, node) }
30
+ command(:find_within, selector).map { |id| self.class.new(driver, page_id, id) }
21
31
  end
22
32
 
23
33
  def text
@@ -3,7 +3,7 @@ module Capybara::Poltergeist
3
3
  attr_reader :port, :socket, :timeout
4
4
 
5
5
  def initialize(timeout = nil)
6
- @port = find_available_port
6
+ @port = Util.find_available_port
7
7
  @timeout = timeout
8
8
  start
9
9
  end
@@ -16,22 +16,17 @@ module Capybara::Poltergeist
16
16
  @socket = WebSocketServer.new(port, timeout)
17
17
  end
18
18
 
19
- def restart
19
+ def stop
20
20
  @socket.close
21
- @socket = WebSocketServer.new(port, timeout)
22
21
  end
23
22
 
24
- def send(message)
25
- @socket.send(message) or raise DeadClient.new(message)
23
+ def restart
24
+ stop
25
+ start
26
26
  end
27
27
 
28
- private
29
-
30
- def find_available_port
31
- server = TCPServer.new('127.0.0.1', 0)
32
- server.addr[1]
33
- ensure
34
- server.close if server
28
+ def send(message)
29
+ @socket.send(message) or raise DeadClient.new(message)
35
30
  end
36
31
  end
37
32
  end
@@ -0,0 +1,17 @@
1
+ require 'childprocess'
2
+
3
+ module Capybara::Poltergeist
4
+ module Spawn
5
+ def self.spawn(*args)
6
+ args = args.map(&:to_s)
7
+
8
+ if RUBY_VERSION >= "1.9"
9
+ Process.spawn(*args)
10
+ else
11
+ process = ChildProcess.build(*args)
12
+ process.start
13
+ process.pid
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ require 'socket'
2
+
3
+ module Capybara::Poltergeist
4
+ module Util
5
+ def self.find_available_port
6
+ server = TCPServer.new('127.0.0.1', 0)
7
+ server.addr[1]
8
+ ensure
9
+ server.close if server
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Poltergeist
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
@@ -54,16 +54,34 @@ module Capybara::Poltergeist
54
54
  # just keep reading until we've received a full frame)
55
55
  RECV_SIZE = 1024
56
56
 
57
+ # How many seconds to try to bind to the port for before failing
58
+ BIND_TIMEOUT = 5
59
+
57
60
  attr_reader :port, :parser, :socket, :handler, :server
58
61
  attr_accessor :timeout
59
62
 
60
63
  def initialize(port, timeout = nil)
61
64
  @port = port
62
65
  @parser = Http::Parser.new
63
- @server = TCPServer.open(port)
66
+ @server = start_server
64
67
  @timeout = timeout
65
68
  end
66
69
 
70
+ def start_server
71
+ time = Time.now
72
+
73
+ begin
74
+ TCPServer.open(port)
75
+ rescue Errno::EADDRINUSE
76
+ if (Time.now - time) < BIND_TIMEOUT
77
+ sleep(0.01)
78
+ retry
79
+ else
80
+ raise
81
+ end
82
+ end
83
+ end
84
+
67
85
  def connected?
68
86
  !socket.nil?
69
87
  end
@@ -104,11 +122,12 @@ module Capybara::Poltergeist
104
122
  end
105
123
  end
106
124
 
107
- # Block until the next message is available from the Web Socket
125
+ # Block until the next message is available from the Web Socket.
126
+ # Raises Errno::EWOULDBLOCK if timeout is reached.
108
127
  def receive
109
128
  until handler.message?
110
- IO.select([socket], [], [], timeout)
111
- data = socket.recv_nonblock(RECV_SIZE)
129
+ IO.select([socket], [], [], timeout) or raise Errno::EWOULDBLOCK
130
+ data = socket.recv(RECV_SIZE)
112
131
  break if data.empty?
113
132
  handler.parse(data)
114
133
  end
@@ -121,12 +140,12 @@ module Capybara::Poltergeist
121
140
  accept unless connected?
122
141
  socket.write handler.encode(message)
123
142
  receive
124
- rescue Errno::EAGAIN, Errno::EWOULDBLOCK
143
+ rescue Errno::EWOULDBLOCK
125
144
  raise TimeoutError.new(message)
126
145
  end
127
146
 
128
147
  def close
129
- [server, socket].each do |s|
148
+ [server, socket].compact.each do |s|
130
149
  s.close_read
131
150
  s.close_write
132
151
  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.4.0
4
+ version: 0.5.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-02-18 00:00:00.000000000 Z
12
+ date: 2012-03-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: capybara
16
- requirement: &16526020 !ruby/object:Gem::Requirement
16
+ requirement: &20962640 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,32 +21,32 @@ dependencies:
21
21
  version: '1.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *16526020
24
+ version_requirements: *20962640
25
25
  - !ruby/object:Gem::Dependency
26
- name: json
27
- requirement: &16525520 !ruby/object:Gem::Requirement
26
+ name: multi_json
27
+ requirement: &20960260 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
31
31
  - !ruby/object:Gem::Version
32
- version: '1.6'
32
+ version: '1.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *16525520
35
+ version_requirements: *20960260
36
36
  - !ruby/object:Gem::Dependency
37
- name: sfl
38
- requirement: &16525060 !ruby/object:Gem::Requirement
37
+ name: childprocess
38
+ requirement: &20958720 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
42
42
  - !ruby/object:Gem::Version
43
- version: '2.0'
43
+ version: '0.3'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *16525060
46
+ version_requirements: *20958720
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: http_parser.rb
49
- requirement: &16524600 !ruby/object:Gem::Requirement
49
+ requirement: &20957520 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,21 +54,24 @@ dependencies:
54
54
  version: 0.5.3
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *16524600
57
+ version_requirements: *20957520
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: faye-websocket
60
- requirement: &16524140 !ruby/object:Gem::Requirement
60
+ requirement: &21890060 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
64
64
  - !ruby/object:Gem::Version
65
- version: 0.2.0
65
+ version: '0.4'
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.4.4
66
69
  type: :runtime
67
70
  prerelease: false
68
- version_requirements: *16524140
71
+ version_requirements: *21890060
69
72
  - !ruby/object:Gem::Dependency
70
73
  name: rspec
71
- requirement: &16523680 !ruby/object:Gem::Requirement
74
+ requirement: &21888340 !ruby/object:Gem::Requirement
72
75
  none: false
73
76
  requirements:
74
77
  - - ~>
@@ -76,10 +79,10 @@ dependencies:
76
79
  version: 2.8.0
77
80
  type: :development
78
81
  prerelease: false
79
- version_requirements: *16523680
82
+ version_requirements: *21888340
80
83
  - !ruby/object:Gem::Dependency
81
84
  name: sinatra
82
- requirement: &16523220 !ruby/object:Gem::Requirement
85
+ requirement: &21886720 !ruby/object:Gem::Requirement
83
86
  none: false
84
87
  requirements:
85
88
  - - ~>
@@ -87,10 +90,10 @@ dependencies:
87
90
  version: '1.0'
88
91
  type: :development
89
92
  prerelease: false
90
- version_requirements: *16523220
93
+ version_requirements: *21886720
91
94
  - !ruby/object:Gem::Dependency
92
95
  name: rake
93
- requirement: &16522760 !ruby/object:Gem::Requirement
96
+ requirement: &21886100 !ruby/object:Gem::Requirement
94
97
  none: false
95
98
  requirements:
96
99
  - - ~>
@@ -98,10 +101,10 @@ dependencies:
98
101
  version: 0.9.2
99
102
  type: :development
100
103
  prerelease: false
101
- version_requirements: *16522760
104
+ version_requirements: *21886100
102
105
  - !ruby/object:Gem::Dependency
103
106
  name: image_size
104
- requirement: &16522300 !ruby/object:Gem::Requirement
107
+ requirement: &21212360 !ruby/object:Gem::Requirement
105
108
  none: false
106
109
  requirements:
107
110
  - - ~>
@@ -109,7 +112,7 @@ dependencies:
109
112
  version: '1.0'
110
113
  type: :development
111
114
  prerelease: false
112
- version_requirements: *16522300
115
+ version_requirements: *21212360
113
116
  description: PhantomJS driver for Capybara
114
117
  email:
115
118
  - j@jonathanleighton.com
@@ -121,9 +124,12 @@ files:
121
124
  - lib/capybara/poltergeist/client.rb
122
125
  - lib/capybara/poltergeist/server.rb
123
126
  - lib/capybara/poltergeist/browser.rb
127
+ - lib/capybara/poltergeist/inspector.rb
124
128
  - lib/capybara/poltergeist/errors.rb
129
+ - lib/capybara/poltergeist/util.rb
125
130
  - lib/capybara/poltergeist/web_socket_server.rb
126
131
  - lib/capybara/poltergeist/version.rb
132
+ - lib/capybara/poltergeist/spawn.rb
127
133
  - lib/capybara/poltergeist/driver.rb
128
134
  - lib/capybara/poltergeist/client/connection.coffee
129
135
  - lib/capybara/poltergeist/client/node.coffee