capybara-webkit 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "capybara-webkit"
3
- s.version = "0.6.0"
3
+ s.version = "0.6.1"
4
4
  s.authors = ["thoughtbot", "Joe Ferris", "Jason Morrison", "Tristan Dunn",
5
5
  "Joshua Clayton", "Yuichi Tateno", "Aaron Gibralter",
6
6
  "Vasily Reys", "petrushka", "John Bintz", "Chad Pytel",
@@ -54,11 +54,11 @@ class Capybara::Driver::Webkit
54
54
  end
55
55
 
56
56
  def response_headers
57
- raise Capybara::NotSupportedByDriverError
57
+ browser.response_headers
58
58
  end
59
59
 
60
60
  def status_code
61
- raise Capybara::NotSupportedByDriverError
61
+ browser.status_code
62
62
  end
63
63
 
64
64
  def within_frame(frame_id_or_index)
@@ -1,4 +1,5 @@
1
1
  require 'socket'
2
+ require 'thread'
2
3
  require 'capybara/util/timeout'
3
4
  require 'json'
4
5
 
@@ -8,6 +9,9 @@ class Capybara::Driver::Webkit
8
9
 
9
10
  def initialize(options = {})
10
11
  @socket_class = options[:socket_class] || TCPSocket
12
+ @stdout = options.has_key?(:stdout) ?
13
+ options[:stdout] :
14
+ $stdout
11
15
  start_server
12
16
  connect
13
17
  end
@@ -36,6 +40,14 @@ class Capybara::Driver::Webkit
36
40
  command("Source")
37
41
  end
38
42
 
43
+ def status_code
44
+ command("Status").to_i
45
+ end
46
+
47
+ def response_headers
48
+ Hash[command("Headers").split("\n").map { |header| header.split(": ") }]
49
+ end
50
+
39
51
  def url
40
52
  command("Url")
41
53
  end
@@ -77,23 +89,27 @@ class Capybara::Driver::Webkit
77
89
  private
78
90
 
79
91
  def start_server
80
- read_pipe, write_pipe = fork_server
81
- @server_port = discover_server_port(read_pipe)
92
+ pipe = fork_server
93
+ @server_port = discover_server_port(pipe)
94
+ @stdout_thread = Thread.new do
95
+ Thread.current.abort_on_exception = true
96
+ forward_stdout(pipe)
97
+ end
82
98
  end
83
99
 
84
100
  def fork_server
85
101
  server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
86
102
 
87
- read_pipe, write_pipe = IO.pipe
88
- @pid = fork do
89
- $stdout.reopen write_pipe
90
- read_pipe.close
91
- exec(server_path)
92
- end
103
+ pipe, @pid = server_pipe_and_pid(server_path)
104
+
93
105
  at_exit { Process.kill("INT", @pid) }
94
106
 
95
- write_pipe.close
96
- [read_pipe, write_pipe]
107
+ pipe
108
+ end
109
+
110
+ def server_pipe_and_pid(server_path)
111
+ pipe = IO.popen(server_path)
112
+ [pipe, pipe.pid]
97
113
  end
98
114
 
99
115
  def discover_server_port(read_pipe)
@@ -101,6 +117,31 @@ class Capybara::Driver::Webkit
101
117
  ((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
102
118
  end
103
119
 
120
+ def forward_stdout(pipe)
121
+ while pipe_readable?(pipe)
122
+ line = pipe.readline
123
+ if @stdout
124
+ @stdout.write(line)
125
+ @stdout.flush
126
+ end
127
+ end
128
+ rescue EOFError
129
+ end
130
+
131
+ if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
132
+ # please note the use of IO::select() here, as it is used specifically to
133
+ # preserve correct signal handling behavior in ruby 1.8.
134
+ # https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
135
+ # https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
136
+ def pipe_readable?(pipe)
137
+ IO.select([pipe])
138
+ end
139
+ else
140
+ def pipe_readable?(pipe)
141
+ !pipe.eof?
142
+ end
143
+ end
144
+
104
145
  def connect
105
146
  Capybara.timeout(5) do
106
147
  attempt_connect
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'stringio'
2
3
  require 'capybara/driver/webkit/browser'
3
4
 
4
5
  describe Capybara::Driver::Webkit::Browser do
@@ -22,5 +23,13 @@ describe Capybara::Driver::Webkit::Browser do
22
23
  new_browser.server_port.should_not == browser.server_port
23
24
  end
24
25
  end
26
+
27
+ it 'forwards stdout to the given IO object' do
28
+ io = StringIO.new
29
+ new_browser = Capybara::Driver::Webkit::Browser.new(:stdout => io)
30
+ new_browser.execute_script('console.log("hello world")')
31
+ sleep(0.5)
32
+ io.string.should == "hello world\n"
33
+ end
25
34
 
26
35
  end
@@ -267,6 +267,7 @@ describe Capybara::Driver::Webkit do
267
267
  <html><body>
268
268
  <form action="/" method="GET">
269
269
  <input type="text" name="foo" value="bar"/>
270
+ <input type="text" name="maxlength_foo" value="bar" maxlength="10"/>
270
271
  <input type="text" id="disabled_input" disabled="disabled"/>
271
272
  <input type="checkbox" name="checkedbox" value="1" checked="checked"/>
272
273
  <input type="checkbox" name="uncheckedbox" value="2"/>
@@ -312,6 +313,24 @@ describe Capybara::Driver::Webkit do
312
313
  input.value.should == "newvalue"
313
314
  end
314
315
 
316
+ it "sets an input's value greater than the max length" do
317
+ input = subject.find("//input[@name='maxlength_foo']").first
318
+ input.set("allegories (poems)")
319
+ input.value.should == "allegories"
320
+ end
321
+
322
+ it "sets an input's value equal to the max length" do
323
+ input = subject.find("//input[@name='maxlength_foo']").first
324
+ input.set("allegories")
325
+ input.value.should == "allegories"
326
+ end
327
+
328
+ it "sets an input's value less than the max length" do
329
+ input = subject.find("//input[@name='maxlength_foo']").first
330
+ input.set("poems")
331
+ input.value.should == "poems"
332
+ end
333
+
315
334
  it "sets an input's nil value" do
316
335
  input = subject.find("//input").first
317
336
  input.set(nil)
@@ -6,18 +6,15 @@ describe Capybara::Driver::Webkit do
6
6
  @driver = Capybara::Driver::Webkit.new(TestApp, :browser => $webkit_browser)
7
7
  end
8
8
 
9
- # TODO: select options
10
- # it_should_behave_like "driver"
11
-
9
+ it_should_behave_like "driver"
12
10
  it_should_behave_like "driver with javascript support"
13
11
  it_should_behave_like "driver with cookies support"
14
-
12
+ it_should_behave_like "driver with header support"
13
+ it_should_behave_like "driver with status code support"
14
+ it_should_behave_like "driver with frame support"
15
+
15
16
  it "returns the rack server port" do
16
17
  @driver.server_port.should eq(@driver.instance_variable_get(:@rack_server).port)
17
18
  end
18
19
 
19
- # Can't support:
20
- # it_should_behave_like "driver with header support"
21
- # it_should_behave_like "driver with status code support"
22
- # it_should_behave_like "driver with frame support"
23
20
  end
@@ -18,7 +18,7 @@ end
18
18
  require File.join(spec_dir,"spec_helper")
19
19
 
20
20
  require 'capybara/driver/webkit/browser'
21
- $webkit_browser = Capybara::Driver::Webkit::Browser.new(:socket_class => TCPSocket)
21
+ $webkit_browser = Capybara::Driver::Webkit::Browser.new(:socket_class => TCPSocket, :stdout => nil)
22
22
 
23
23
  Capybara.register_driver :reusable_webkit do |app|
24
24
  Capybara::Driver::Webkit.new(app, :browser => $webkit_browser)
@@ -13,6 +13,8 @@
13
13
  #include "Header.h"
14
14
  #include "Render.h"
15
15
  #include "Body.h"
16
+ #include "Status.h"
17
+ #include "Headers.h"
16
18
 
17
19
  #include <QTcpSocket>
18
20
  #include <iostream>
@@ -0,0 +1,11 @@
1
+ #include "Headers.h"
2
+ #include "WebPage.h"
3
+
4
+ Headers::Headers(WebPage *page, QObject *parent) : Command(page, parent) {
5
+ }
6
+
7
+ void Headers::start(QStringList &arguments) {
8
+ Q_UNUSED(arguments);
9
+ emit finished(new Response(true, page()->pageHeaders()));
10
+ }
11
+
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class Headers : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ Headers(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+ };
12
+
@@ -0,0 +1,13 @@
1
+ #include "Status.h"
2
+ #include "WebPage.h"
3
+ #include <sstream>
4
+
5
+ Status::Status(WebPage *page, QObject *parent) : Command(page, parent) {
6
+ }
7
+
8
+ void Status::start(QStringList &arguments) {
9
+ Q_UNUSED(arguments);
10
+ int status = page()->getLastStatus();
11
+ emit finished(new Response(true, QString::number(status)));
12
+ }
13
+
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class Status : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ Status(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+ };
12
+
@@ -10,7 +10,9 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
10
10
 
11
11
  m_loading = false;
12
12
 
13
- this->setNetworkAccessManager(new NetworkAccessManager());
13
+ NetworkAccessManager *manager = new NetworkAccessManager();
14
+ this->setNetworkAccessManager(manager);
15
+ connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
14
16
 
15
17
  connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
16
18
  connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
@@ -164,3 +166,24 @@ bool WebPage::extension(Extension extension, const ExtensionOption *option, Exte
164
166
  QString WebPage::getLastAttachedFileName() {
165
167
  return currentFrame()->evaluateJavaScript(QString("Capybara.lastAttachedFile")).toString();
166
168
  }
169
+
170
+ void WebPage::replyFinished(QNetworkReply *reply) {
171
+ QStringList headers;
172
+ lastStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
173
+ QList<QByteArray> list = reply->rawHeaderList();
174
+
175
+ int length = list.size();
176
+ for(int i = 0; i < length; i++) {
177
+ headers << list.at(i)+": "+reply->rawHeader(list.at(i));
178
+ }
179
+
180
+ m_pageHeaders = headers.join("\n");
181
+ }
182
+
183
+ int WebPage::getLastStatus() {
184
+ return lastStatus;
185
+ }
186
+
187
+ QString WebPage::pageHeaders() {
188
+ return m_pageHeaders;
189
+ }
@@ -10,6 +10,7 @@ class WebPage : public QWebPage {
10
10
  QString failureString();
11
11
  QString userAgentForUrl(const QUrl &url ) const;
12
12
  void setUserAgent(QString userAgent);
13
+ int getLastStatus();
13
14
  bool render(const QString &fileName);
14
15
  virtual bool extension (Extension extension, const ExtensionOption *option=0, ExtensionReturn *output=0);
15
16
 
@@ -19,7 +20,9 @@ class WebPage : public QWebPage {
19
20
  void loadStarted();
20
21
  void loadFinished(bool);
21
22
  bool isLoading() const;
23
+ QString pageHeaders();
22
24
  void frameCreated(QWebFrame *);
25
+ void replyFinished(QNetworkReply *reply);
23
26
 
24
27
  protected:
25
28
  virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
@@ -35,5 +38,7 @@ class WebPage : public QWebPage {
35
38
  QString getLastAttachedFileName();
36
39
  void loadJavascript();
37
40
  void setUserStylesheet();
41
+ int lastStatus;
42
+ QString m_pageHeaders;
38
43
  };
39
44
 
@@ -105,7 +105,14 @@ Capybara = {
105
105
  if (type == "text" || type == "textarea" || type == "password") {
106
106
  this.trigger(index, "focus");
107
107
  node.value = "";
108
- var length = this.attribute(index, "maxlength") || value.length;
108
+ var maxLength = this.attribute(index, "maxlength"),
109
+ length;
110
+ if (maxLength && value.length > maxLength) {
111
+ length = maxLength;
112
+ } else {
113
+ length = value.length;
114
+ }
115
+
109
116
  for(var strindex = 0; strindex < length; strindex++) {
110
117
  node.value += value[strindex];
111
118
  this.trigger(index, "keydown");
@@ -15,3 +15,5 @@ CHECK_COMMAND(FrameFocus)
15
15
  CHECK_COMMAND(Header)
16
16
  CHECK_COMMAND(Render)
17
17
  CHECK_COMMAND(Body)
18
+ CHECK_COMMAND(Status)
19
+ CHECK_COMMAND(Headers)
@@ -1,8 +1,18 @@
1
1
  #include "Server.h"
2
2
  #include <QtGui>
3
3
  #include <iostream>
4
+ #ifdef Q_OS_UNIX
5
+ #include <unistd.h>
6
+ #endif
4
7
 
5
8
  int main(int argc, char **argv) {
9
+ #ifdef Q_OS_UNIX
10
+ if (setpgid(0, 0) < 0) {
11
+ std::cerr << "Unable to set new process group." << std::endl;
12
+ return 1;
13
+ }
14
+ #endif
15
+
6
16
  QApplication app(argc, argv);
7
17
  app.setApplicationName("capybara-webkit");
8
18
  app.setOrganizationName("thoughtbot, inc");
@@ -1,8 +1,8 @@
1
1
  TEMPLATE = app
2
2
  TARGET = webkit_server
3
3
  DESTDIR = .
4
- HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h Execute.h FrameFocus.h Response.h NetworkAccessManager.h Header.h Render.h body.h
5
- SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp Execute.cpp FrameFocus.cpp Response.cpp NetworkAccessManager.cpp Header.cpp Render.cpp body.cpp
4
+ HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h Execute.h FrameFocus.h Response.h NetworkAccessManager.h Header.h Render.h body.h Status.h Headers.h
5
+ SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp Execute.cpp FrameFocus.cpp Response.cpp NetworkAccessManager.cpp Header.cpp Render.cpp body.cpp Status.cpp Headers.cpp
6
6
  RESOURCES = webkit_server.qrc
7
7
  QT += network webkit
8
8
  CONFIG += console
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-webkit
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
5
4
  prerelease:
6
- segments:
7
- - 0
8
- - 6
9
- - 0
10
- version: 0.6.0
5
+ version: 0.6.1
11
6
  platform: ruby
12
7
  authors:
13
8
  - thoughtbot
@@ -30,25 +25,20 @@ autorequire:
30
25
  bindir: bin
31
26
  cert_chain: []
32
27
 
33
- date: 2011-08-12 00:00:00 -04:00
28
+ date: 2011-08-25 00:00:00 -04:00
34
29
  default_executable:
35
30
  dependencies:
36
31
  - !ruby/object:Gem::Dependency
37
- type: :runtime
32
+ name: capybara
33
+ prerelease: false
38
34
  requirement: &id001 !ruby/object:Gem::Requirement
39
35
  none: false
40
36
  requirements:
41
37
  - - ~>
42
38
  - !ruby/object:Gem::Version
43
- hash: 23
44
- segments:
45
- - 1
46
- - 0
47
- - 0
48
39
  version: 1.0.0
40
+ type: :runtime
49
41
  version_requirements: *id001
50
- name: capybara
51
- prerelease: false
52
42
  description:
53
43
  email: support@thoughtbot.com
54
44
  executables: []
@@ -96,6 +86,8 @@ files:
96
86
  - src/FrameFocus.h
97
87
  - src/Header.cpp
98
88
  - src/Header.h
89
+ - src/Headers.cpp
90
+ - src/Headers.h
99
91
  - src/JavascriptInvocation.cpp
100
92
  - src/JavascriptInvocation.h
101
93
  - src/NetworkAccessManager.cpp
@@ -112,6 +104,8 @@ files:
112
104
  - src/Server.h
113
105
  - src/Source.cpp
114
106
  - src/Source.h
107
+ - src/Status.cpp
108
+ - src/Status.h
115
109
  - src/Url.cpp
116
110
  - src/Url.h
117
111
  - src/Visit.cpp
@@ -141,23 +135,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
141
135
  requirements:
142
136
  - - ">="
143
137
  - !ruby/object:Gem::Version
144
- hash: 3
145
- segments:
146
- - 0
147
138
  version: "0"
148
139
  required_rubygems_version: !ruby/object:Gem::Requirement
149
140
  none: false
150
141
  requirements:
151
142
  - - ">="
152
143
  - !ruby/object:Gem::Version
153
- hash: 3
154
- segments:
155
- - 0
156
144
  version: "0"
157
145
  requirements: []
158
146
 
159
147
  rubyforge_project:
160
- rubygems_version: 1.6.1
148
+ rubygems_version: 1.6.2
161
149
  signing_key:
162
150
  specification_version: 3
163
151
  summary: Headless Webkit driver for Capybara