capybara-webkit 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,8 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "capybara-webkit"
3
- s.version = "0.1.7"
4
- s.authors = ["thoughtbot", "Joe Ferris", "Jason Morrison", "Tristan Dunn"]
3
+ s.version = "0.2.0"
4
+ s.authors = ["thoughtbot", "Joe Ferris", "Jason Morrison", "Tristan Dunn",
5
+ "Joshua Clayton", "Yuichi Tateno", "Aaron Gibralter"]
5
6
  s.email = "support@thoughtbot.com"
6
7
  s.files = `git ls-files`.split("\n")
7
8
  s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
@@ -52,8 +52,13 @@ class Capybara::Driver::Webkit
52
52
  raise Capybara::NotSupportedByDriverError
53
53
  end
54
54
 
55
- def within_frame(frame_id)
56
- raise Capybara::NotSupportedByDriverError
55
+ def within_frame(frame_id_or_index)
56
+ browser.frame_focus(frame_id_or_index)
57
+ begin
58
+ yield
59
+ ensure
60
+ browser.frame_focus
61
+ end
57
62
  end
58
63
 
59
64
  def within_window(handle)
@@ -30,6 +30,16 @@ class Capybara::Driver::Webkit
30
30
  command("Url")
31
31
  end
32
32
 
33
+ def frame_focus(frame_id_or_index=nil)
34
+ if frame_id_or_index.is_a? Fixnum
35
+ command("FrameFocus", "", frame_id_or_index.to_s)
36
+ elsif frame_id_or_index
37
+ command("FrameFocus", frame_id_or_index)
38
+ else
39
+ command("FrameFocus")
40
+ end
41
+ end
42
+
33
43
  def command(name, *args)
34
44
  @socket.puts name
35
45
  @socket.puts args.size
data/spec/driver_spec.rb CHANGED
@@ -6,6 +6,104 @@ describe Capybara::Driver::Webkit do
6
6
  before { subject.visit("/hello/world?success=true") }
7
7
  after { subject.reset! }
8
8
 
9
+ context "iframe app" do
10
+ before(:all) do
11
+ @app = lambda do |env|
12
+ params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
13
+ if params["iframe"] == "true"
14
+ # We are in an iframe request.
15
+ p_id = "farewell"
16
+ msg = "goodbye"
17
+ iframe = nil
18
+ else
19
+ # We are not in an iframe request and need to make an iframe!
20
+ p_id = "greeting"
21
+ msg = "hello"
22
+ iframe = "<iframe id=\"f\" src=\"/?iframe=true\"></iframe>"
23
+ end
24
+ body = <<-HTML
25
+ <html>
26
+ <head>
27
+ <style type="text/css">
28
+ #display_none { display: none }
29
+ </style>
30
+ </head>
31
+ <body>
32
+ #{iframe}
33
+ <script type="text/javascript">
34
+ document.write("<p id='#{p_id}'>#{msg}</p>");
35
+ </script>
36
+ </body>
37
+ </html>
38
+ HTML
39
+ [200,
40
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
41
+ [body]]
42
+ end
43
+ end
44
+
45
+ it "finds frames by index" do
46
+ subject.within_frame(0) do
47
+ subject.find("//*[contains(., 'goodbye')]").should_not be_empty
48
+ end
49
+ end
50
+
51
+ it "finds frames by id" do
52
+ subject.within_frame("f") do
53
+ subject.find("//*[contains(., 'goodbye')]").should_not be_empty
54
+ end
55
+ end
56
+
57
+ it "raises error for missing frame by index" do
58
+ expect { subject.within_frame(1) { } }.
59
+ to raise_error(Capybara::Driver::Webkit::WebkitError)
60
+ end
61
+
62
+ it "raise_error for missing frame by id" do
63
+ expect { subject.within_frame("foo") { } }.
64
+ to raise_error(Capybara::Driver::Webkit::WebkitError)
65
+ end
66
+
67
+ it "returns an attribute's value" do
68
+ subject.within_frame("f") do
69
+ subject.find("//p").first["id"].should == "farewell"
70
+ end
71
+ end
72
+
73
+ it "returns a node's text" do
74
+ subject.within_frame("f") do
75
+ subject.find("//p").first.text.should == "goodbye"
76
+ end
77
+ end
78
+
79
+ it "returns the current URL" do
80
+ subject.within_frame("f") do
81
+ port = subject.instance_variable_get("@rack_server").port
82
+ subject.current_url.should == "http://127.0.0.1:#{port}/?iframe=true"
83
+ end
84
+ end
85
+
86
+ it "returns the source code for the page" do
87
+ subject.within_frame("f") do
88
+ subject.source.should =~ %r{<html>.*farewell.*}m
89
+ end
90
+ end
91
+
92
+ it "evaluates Javascript" do
93
+ subject.within_frame("f") do
94
+ result = subject.evaluate_script(%<document.getElementById('farewell').innerText>)
95
+ result.should == "goodbye"
96
+ end
97
+ end
98
+
99
+ it "executes Javascript" do
100
+ subject.within_frame("f") do
101
+ subject.execute_script(%<document.getElementById('farewell').innerHTML = 'yo'>)
102
+ subject.find("//p[contains(., 'yo')]").should_not be_empty
103
+ end
104
+ end
105
+ end
106
+
9
107
  context "hello app" do
10
108
  before(:all) do
11
109
  @app = lambda do |env|
@@ -1,3 +1,5 @@
1
+ # -*- encoding: UTF-8 -*-
2
+
1
3
  require 'spec_helper'
2
4
  require 'capybara-webkit'
3
5
 
@@ -50,18 +52,32 @@ describe Capybara::Session do
50
52
  body = <<-HTML
51
53
  <html><body>
52
54
  <strong>Hello</strong>
55
+ <span>UTF8文字列</span>
56
+ <input type="button" value="ボタン" />
53
57
  </body></html>
54
58
  HTML
55
59
  [200,
56
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
60
+ { 'Content-Type' => 'text/html; charset=UTF-8', 'Content-Length' => body.length.to_s },
57
61
  [body]]
58
62
  end
59
63
  end
60
64
 
61
- it "inspects nodes" do
65
+ before do
62
66
  subject.visit("/")
67
+ end
68
+
69
+ it "inspects nodes" do
63
70
  subject.all(:xpath, "//strong").first.inspect.should include("strong")
64
71
  end
72
+
73
+ it "can read utf8 string" do
74
+ utf8str = subject.all(:xpath, "//span").first.text
75
+ utf8str.should eq('UTF8文字列')
76
+ end
77
+
78
+ it "can click utf8 string" do
79
+ subject.click_button('ボタン')
80
+ end
65
81
  end
66
82
  end
67
83
 
data/src/Connection.cpp CHANGED
@@ -9,6 +9,7 @@
9
9
  #include "Source.h"
10
10
  #include "Evaluate.h"
11
11
  #include "Execute.h"
12
+ #include "FrameFocus.h"
12
13
 
13
14
  #include <QTcpSocket>
14
15
  #include <iostream>
@@ -69,7 +70,7 @@ void Connection::processArgument(const char *data) {
69
70
  } else if (m_expectingDataSize == -1) {
70
71
  m_expectingDataSize = QString(data).toInt();
71
72
  } else {
72
- m_arguments.append(data);
73
+ m_arguments.append(QString::fromUtf8(data));
73
74
  }
74
75
 
75
76
  if (m_arguments.length() == m_argumentsExpected) {
@@ -123,8 +124,9 @@ void Connection::writeResponse(bool success, QString &response) {
123
124
  else
124
125
  m_socket->write("failure\n");
125
126
 
126
- QString responseLength = QString::number(response.size()) + "\n";
127
+ QByteArray response_utf8 = response.toUtf8();
128
+ QString responseLength = QString::number(response_utf8.size()) + "\n";
127
129
  m_socket->write(responseLength.toAscii());
128
- m_socket->write(response.toAscii());
130
+ m_socket->write(response_utf8);
129
131
  }
130
132
 
data/src/Evaluate.cpp CHANGED
@@ -7,7 +7,7 @@ Evaluate::Evaluate(WebPage *page, QObject *parent) : Command(page, parent) {
7
7
  }
8
8
 
9
9
  void Evaluate::start(QStringList &arguments) {
10
- QVariant result = page()->mainFrame()->evaluateJavaScript(arguments[0]);
10
+ QVariant result = page()->currentFrame()->evaluateJavaScript(arguments[0]);
11
11
  addVariant(result);
12
12
  emit finished(true, m_buffer);
13
13
  }
data/src/Execute.cpp CHANGED
@@ -6,7 +6,7 @@ Execute::Execute(WebPage *page, QObject *parent) : Command(page, parent) {
6
6
 
7
7
  void Execute::start(QStringList &arguments) {
8
8
  QString script = arguments[0] + QString("; 'success'");
9
- QVariant result = page()->mainFrame()->evaluateJavaScript(script);
9
+ QVariant result = page()->currentFrame()->evaluateJavaScript(script);
10
10
  QString response;
11
11
  if (result.isValid()) {
12
12
  emit finished(true, response);
@@ -0,0 +1,69 @@
1
+ #include "FrameFocus.h"
2
+ #include "Command.h"
3
+ #include "WebPage.h"
4
+
5
+ FrameFocus::FrameFocus(WebPage *page, QObject *parent) : Command(page, parent) {
6
+ }
7
+
8
+ void FrameFocus::start(QStringList &arguments) {
9
+ findFrames();
10
+ switch(arguments.length()) {
11
+ case 1:
12
+ focusId(arguments[0]);
13
+ break;
14
+ case 2:
15
+ focusIndex(arguments[1].toInt());
16
+ break;
17
+ default:
18
+ focusParent();
19
+ }
20
+ }
21
+
22
+ void FrameFocus::findFrames() {
23
+ frames = page()->currentFrame()->childFrames();
24
+ }
25
+
26
+ void FrameFocus::focusIndex(int index) {
27
+ if (isFrameAtIndex(index)) {
28
+ frames[index]->setFocus();
29
+ success();
30
+ } else {
31
+ frameNotFound();
32
+ }
33
+ }
34
+
35
+ bool FrameFocus::isFrameAtIndex(int index) {
36
+ return 0 <= index && index < frames.length();
37
+ }
38
+
39
+ void FrameFocus::focusId(QString name) {
40
+ for (int i = 0; i < frames.length(); i++) {
41
+ if (frames[i]->frameName().compare(name) == 0) {
42
+ frames[i]->setFocus();
43
+ success();
44
+ return;
45
+ }
46
+ }
47
+
48
+ frameNotFound();
49
+ }
50
+
51
+ void FrameFocus::focusParent() {
52
+ if (page()->currentFrame()->parentFrame() == 0) {
53
+ QString response = "Already at parent frame.";
54
+ emit finished(false, response);
55
+ } else {
56
+ page()->currentFrame()->parentFrame()->setFocus();
57
+ success();
58
+ }
59
+ }
60
+
61
+ void FrameFocus::frameNotFound() {
62
+ QString response = "Unable to locate frame. ";
63
+ emit finished(false, response);
64
+ }
65
+
66
+ void FrameFocus::success() {
67
+ QString response;
68
+ emit finished(true, response);
69
+ }
data/src/FrameFocus.h ADDED
@@ -0,0 +1,28 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+ class QWebFrame;
5
+
6
+ class FrameFocus : public Command {
7
+ Q_OBJECT
8
+
9
+ public:
10
+ FrameFocus(WebPage *page, QObject *parent = 0);
11
+ virtual void start(QStringList &arguments);
12
+
13
+ private:
14
+ void findFrames();
15
+
16
+ void focusParent();
17
+
18
+ void focusIndex(int index);
19
+ bool isFrameAtIndex(int index);
20
+
21
+ void focusId(QString id);
22
+
23
+ void success();
24
+ void frameNotFound();
25
+
26
+ QList<QWebFrame *> frames;
27
+ };
28
+
data/src/Reset.cpp CHANGED
@@ -8,7 +8,7 @@ void Reset::start(QStringList &arguments) {
8
8
  Q_UNUSED(arguments);
9
9
 
10
10
  page()->triggerAction(QWebPage::Stop);
11
- page()->mainFrame()->setHtml("<html><body></body></html>");
11
+ page()->currentFrame()->setHtml("<html><body></body></html>");
12
12
  page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
13
13
  QString response = "";
14
14
  emit finished(true, response);
data/src/Source.cpp CHANGED
@@ -7,7 +7,7 @@ Source::Source(WebPage *page, QObject *parent) : Command(page, parent) {
7
7
  void Source::start(QStringList &arguments) {
8
8
  Q_UNUSED(arguments)
9
9
 
10
- QString response = page()->mainFrame()->toHtml();
10
+ QString response = page()->currentFrame()->toHtml();
11
11
 
12
12
  emit finished(true, response);
13
13
  }
data/src/Url.cpp CHANGED
@@ -7,7 +7,7 @@ Url::Url(WebPage *page, QObject *parent) : Command(page, parent) {
7
7
  void Url::start(QStringList &argments) {
8
8
  Q_UNUSED(argments);
9
9
 
10
- QUrl humanUrl = page()->mainFrame()->url();
10
+ QUrl humanUrl = page()->currentFrame()->url();
11
11
  QByteArray encodedBytes = humanUrl.toEncoded();
12
12
  QString response = QString(encodedBytes);
13
13
 
data/src/Visit.cpp CHANGED
@@ -7,7 +7,7 @@ Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) {
7
7
  }
8
8
 
9
9
  void Visit::start(QStringList &arguments) {
10
- page()->mainFrame()->setUrl(QUrl(arguments[0]));
10
+ page()->currentFrame()->setUrl(QUrl(arguments[0]));
11
11
  }
12
12
 
13
13
  void Visit::loadFinished(bool success) {
data/src/WebPage.cpp CHANGED
@@ -4,8 +4,6 @@
4
4
  #include <iostream>
5
5
 
6
6
  WebPage::WebPage(QObject *parent) : QWebPage(parent) {
7
- connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
8
- this, SLOT(injectJavascriptHelpers()));
9
7
  QResource javascript(":/capybara.js");
10
8
  char * javascriptString = new char[javascript.size() + 1];
11
9
  strcpy(javascriptString, (const char *)javascript.data());
@@ -14,10 +12,18 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
14
12
  m_loading = false;
15
13
  connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
16
14
  connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
15
+ connect(this, SIGNAL(frameCreated(QWebFrame *)),
16
+ this, SLOT(frameCreated(QWebFrame *)));
17
+ }
18
+
19
+ void WebPage::frameCreated(QWebFrame * frame) {
20
+ connect(frame, SIGNAL(javaScriptWindowObjectCleared()),
21
+ this, SLOT(injectJavascriptHelpers()));
17
22
  }
18
23
 
19
24
  void WebPage::injectJavascriptHelpers() {
20
- mainFrame()->evaluateJavaScript(m_capybaraJavascript);
25
+ QWebFrame* frame = qobject_cast<QWebFrame *>(QObject::sender());
26
+ frame->evaluateJavaScript(m_capybaraJavascript);
21
27
  }
22
28
 
23
29
  bool WebPage::shouldInterruptJavaScript() {
@@ -28,9 +34,9 @@ QVariant WebPage::invokeCapybaraFunction(const char *name, QStringList &argument
28
34
  QString qname(name);
29
35
  QString objectName("CapybaraInvocation");
30
36
  JavascriptInvocation invocation(qname, arguments);
31
- mainFrame()->addToJavaScriptWindowObject(objectName, &invocation);
37
+ currentFrame()->addToJavaScriptWindowObject(objectName, &invocation);
32
38
  QString javascript = QString("Capybara.invoke()");
33
- return mainFrame()->evaluateJavaScript(javascript);
39
+ return currentFrame()->evaluateJavaScript(javascript);
34
40
  }
35
41
 
36
42
  QVariant WebPage::invokeCapybaraFunction(QString &name, QStringList &arguments) {
@@ -76,6 +82,6 @@ bool WebPage::isLoading() const {
76
82
  }
77
83
 
78
84
  QString WebPage::failureString() {
79
- return QString("Unable to load URL: ") + mainFrame()->url().toString();
85
+ return QString("Unable to load URL: ") + currentFrame()->url().toString();
80
86
  }
81
87
 
data/src/WebPage.h CHANGED
@@ -15,6 +15,7 @@ class WebPage : public QWebPage {
15
15
  void loadStarted();
16
16
  void loadFinished(bool);
17
17
  bool isLoading() const;
18
+ void frameCreated(QWebFrame *);
18
19
 
19
20
  protected:
20
21
  virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
data/src/find_command.h CHANGED
@@ -11,3 +11,4 @@ CHECK_COMMAND(Url)
11
11
  CHECK_COMMAND(Source)
12
12
  CHECK_COMMAND(Evaluate)
13
13
  CHECK_COMMAND(Execute)
14
+ CHECK_COMMAND(FrameFocus)
@@ -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
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
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
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
6
6
  RESOURCES = webkit_server.qrc
7
7
  QT += network webkit
8
8
  CONFIG += console
metadata CHANGED
@@ -1,32 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-webkit
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 23
4
5
  prerelease:
5
- version: 0.1.7
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
6
11
  platform: ruby
7
12
  authors:
8
13
  - thoughtbot
9
14
  - Joe Ferris
10
15
  - Jason Morrison
11
16
  - Tristan Dunn
17
+ - Joshua Clayton
18
+ - Yuichi Tateno
19
+ - Aaron Gibralter
12
20
  autorequire:
13
21
  bindir: bin
14
22
  cert_chain: []
15
23
 
16
- date: 2011-04-15 00:00:00 -04:00
24
+ date: 2011-04-20 00:00:00 -04:00
17
25
  default_executable:
18
26
  dependencies:
19
27
  - !ruby/object:Gem::Dependency
20
- name: capybara
28
+ type: :runtime
21
29
  requirement: &id001 !ruby/object:Gem::Requirement
22
30
  none: false
23
31
  requirements:
24
32
  - - ~>
25
33
  - !ruby/object:Gem::Version
34
+ hash: 13
35
+ segments:
36
+ - 0
37
+ - 4
38
+ - 1
26
39
  version: 0.4.1
27
- type: :runtime
28
- prerelease: false
29
40
  version_requirements: *id001
41
+ name: capybara
42
+ prerelease: false
30
43
  description:
31
44
  email: support@thoughtbot.com
32
45
  executables: []
@@ -65,6 +78,8 @@ files:
65
78
  - src/Execute.h
66
79
  - src/Find.cpp
67
80
  - src/Find.h
81
+ - src/FrameFocus.cpp
82
+ - src/FrameFocus.h
68
83
  - src/JavascriptInvocation.cpp
69
84
  - src/JavascriptInvocation.h
70
85
  - src/Node.cpp
@@ -103,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
118
  requirements:
104
119
  - - ">="
105
120
  - !ruby/object:Gem::Version
106
- hash: 2573501153324218535
121
+ hash: 3
107
122
  segments:
108
123
  - 0
109
124
  version: "0"
@@ -112,11 +127,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
127
  requirements:
113
128
  - - ">="
114
129
  - !ruby/object:Gem::Version
130
+ hash: 3
131
+ segments:
132
+ - 0
115
133
  version: "0"
116
134
  requirements: []
117
135
 
118
136
  rubyforge_project:
119
- rubygems_version: 1.6.2
137
+ rubygems_version: 1.6.1
120
138
  signing_key:
121
139
  specification_version: 3
122
140
  summary: Headless Webkit driver for Capybara