capybara-webkit 0.6.0 → 0.6.1

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.
@@ -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