capybara-webkit 0.5.0 → 0.6.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.
@@ -86,6 +86,6 @@ describe Capybara::Session, "with TestApp" do
86
86
  @session = Capybara::Session.new(:reusable_webkit, TestApp)
87
87
  end
88
88
 
89
- # it_should_behave_like "session"
90
- # it_should_behave_like "session with javascript support"
89
+ it_should_behave_like "session"
90
+ it_should_behave_like "session with javascript support"
91
91
  end
data/src/Body.h ADDED
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class Body : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ Body(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+ };
12
+
data/src/Connection.cpp CHANGED
@@ -10,6 +10,9 @@
10
10
  #include "Evaluate.h"
11
11
  #include "Execute.h"
12
12
  #include "FrameFocus.h"
13
+ #include "Header.h"
14
+ #include "Render.h"
15
+ #include "Body.h"
13
16
 
14
17
  #include <QTcpSocket>
15
18
  #include <iostream>
@@ -55,7 +58,7 @@ void Connection::readDataBlock() {
55
58
  buffer[m_expectingDataSize] = 0;
56
59
  processNext(buffer);
57
60
  m_expectingDataSize = -1;
58
- delete buffer;
61
+ delete[] buffer;
59
62
  }
60
63
 
61
64
  void Connection::processNext(const char *data) {
@@ -95,7 +98,7 @@ void Connection::startCommand() {
95
98
  SLOT(finishCommand(Response *)));
96
99
  m_command->start(m_arguments);
97
100
  } else {
98
- QString failure = QString("Unknown command: ") + m_commandName + "\n";
101
+ QString failure = QString("[Capybara WebKit] Unknown command: ") + m_commandName + "\n";
99
102
  writeResponse(new Response(false, failure));
100
103
  }
101
104
  m_commandName = QString();
data/src/Header.cpp ADDED
@@ -0,0 +1,18 @@
1
+ #include "Header.h"
2
+ #include "WebPage.h"
3
+ #include "NetworkAccessManager.h"
4
+
5
+ Header::Header(WebPage *page, QObject *parent) : Command(page, parent) {
6
+ }
7
+
8
+ void Header::start(QStringList &arguments) {
9
+ QString key = arguments[0];
10
+ QString value = arguments[1];
11
+ NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
12
+ if (key.toLower().replace("-", "_") == "user_agent") {
13
+ page()->setUserAgent(value);
14
+ } else {
15
+ networkAccessManager->addHeader(key, value);
16
+ }
17
+ emit finished(new Response(true));
18
+ }
data/src/Header.h ADDED
@@ -0,0 +1,11 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class Header : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ Header(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+ };
@@ -0,0 +1,22 @@
1
+ #include "NetworkAccessManager.h"
2
+ #include "WebPage.h"
3
+ #include <iostream>
4
+
5
+
6
+ NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
7
+ }
8
+
9
+ QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation oparation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
10
+ QNetworkRequest new_request(request);
11
+ QHashIterator<QString, QString> item(m_headers);
12
+ while (item.hasNext()) {
13
+ item.next();
14
+ new_request.setRawHeader(item.key().toAscii(), item.value().toAscii());
15
+ }
16
+ return QNetworkAccessManager::createRequest(oparation, new_request, outgoingData);
17
+ };
18
+
19
+ void NetworkAccessManager::addHeader(QString key, QString value) {
20
+ m_headers.insert(key, value);
21
+ };
22
+
@@ -0,0 +1,18 @@
1
+ #include <QtNetwork/QNetworkAccessManager>
2
+ #include <QtNetwork/QNetworkRequest>
3
+ #include <QtNetwork/QNetworkReply>
4
+
5
+ class NetworkAccessManager : public QNetworkAccessManager {
6
+
7
+ Q_OBJECT
8
+
9
+ public:
10
+ NetworkAccessManager(QObject *parent = 0);
11
+ void addHeader(QString key, QString value);
12
+
13
+ protected:
14
+ QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData);
15
+
16
+ private:
17
+ QHash<QString, QString> m_headers;
18
+ };
data/src/Render.cpp ADDED
@@ -0,0 +1,19 @@
1
+ #include "Render.h"
2
+ #include "WebPage.h"
3
+
4
+ Render::Render(WebPage *page, QObject *parent) : Command(page, parent) {
5
+ }
6
+
7
+ void Render::start(QStringList &arguments) {
8
+ QStringList functionArguments(arguments);
9
+ QString imagePath = functionArguments.takeFirst();
10
+ int width = functionArguments.takeFirst().toInt();
11
+ int height = functionArguments.takeFirst().toInt();
12
+
13
+ QSize size(width, height);
14
+ page()->setViewportSize(size);
15
+
16
+ bool result = page()->render( imagePath );
17
+
18
+ emit finished(new Response(result));
19
+ }
data/src/Render.h ADDED
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+ #include <QStringList>
3
+
4
+ class WebPage;
5
+
6
+ class Render : public Command {
7
+ Q_OBJECT
8
+
9
+ public:
10
+ Render(WebPage *page, QObject *parent = 0);
11
+ virtual void start(QStringList &arguments);
12
+ };
data/src/Reset.cpp CHANGED
@@ -1,5 +1,6 @@
1
1
  #include "Reset.h"
2
2
  #include "WebPage.h"
3
+ #include "NetworkAccessManager.h"
3
4
 
4
5
  Reset::Reset(WebPage *page, QObject *parent) : Command(page, parent) {
5
6
  }
@@ -10,6 +11,8 @@ void Reset::start(QStringList &arguments) {
10
11
  page()->triggerAction(QWebPage::Stop);
11
12
  page()->currentFrame()->setHtml("<html><body></body></html>");
12
13
  page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
14
+ page()->setNetworkAccessManager(new NetworkAccessManager());
15
+ page()->setUserAgent(NULL);
13
16
  emit finished(new Response(true));
14
17
  }
15
18
 
data/src/Server.cpp CHANGED
@@ -11,11 +11,14 @@ Server::Server(QObject *parent) : QObject(parent) {
11
11
 
12
12
  bool Server::start() {
13
13
  connect(m_tcp_server, SIGNAL(newConnection()), this, SLOT(handleConnection()));
14
- return m_tcp_server->listen(QHostAddress::Any, 9200);
14
+ return m_tcp_server->listen(QHostAddress::Any, 0);
15
+ }
16
+
17
+ quint16 Server::server_port() const {
18
+ return m_tcp_server->serverPort();
15
19
  }
16
20
 
17
21
  void Server::handleConnection() {
18
22
  QTcpSocket *socket = m_tcp_server->nextPendingConnection();
19
23
  new Connection(socket, m_page, this);
20
24
  }
21
-
data/src/Server.h CHANGED
@@ -9,6 +9,7 @@ class Server : public QObject {
9
9
  public:
10
10
  Server(QObject *parent = 0);
11
11
  bool start();
12
+ quint16 server_port() const;
12
13
 
13
14
  public slots:
14
15
  void handleConnection();
data/src/Source.cpp CHANGED
@@ -7,7 +7,14 @@ 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 result = page()->currentFrame()->toHtml();
11
- emit finished(new Response(true, result));
10
+ QNetworkAccessManager* accessManager = page()->networkAccessManager();
11
+ QNetworkRequest request(page()->currentFrame()->url());
12
+ reply = accessManager->get(request);
13
+
14
+ connect(reply, SIGNAL(finished()), this, SLOT(sourceLoaded()));
15
+ }
16
+
17
+ void Source::sourceLoaded() {
18
+ emit finished(new Response(true, reply->readAll()));
12
19
  }
13
20
 
data/src/Source.h CHANGED
@@ -1,6 +1,7 @@
1
1
  #include "Command.h"
2
2
 
3
3
  class WebPage;
4
+ class QNetworkReply;
4
5
 
5
6
  class Source : public Command {
6
7
  Q_OBJECT
@@ -8,5 +9,11 @@ class Source : public Command {
8
9
  public:
9
10
  Source(WebPage *page, QObject *parent = 0);
10
11
  virtual void start(QStringList &arguments);
12
+
13
+ public slots:
14
+ void sourceLoaded();
15
+
16
+ private:
17
+ QNetworkReply *reply;
11
18
  };
12
19
 
data/src/WebPage.cpp CHANGED
@@ -1,9 +1,24 @@
1
1
  #include "WebPage.h"
2
2
  #include "JavascriptInvocation.h"
3
+ #include "NetworkAccessManager.h"
3
4
  #include <QResource>
4
5
  #include <iostream>
5
6
 
6
7
  WebPage::WebPage(QObject *parent) : QWebPage(parent) {
8
+ loadJavascript();
9
+ setUserStylesheet();
10
+
11
+ m_loading = false;
12
+
13
+ this->setNetworkAccessManager(new NetworkAccessManager());
14
+
15
+ connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
16
+ connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
17
+ connect(this, SIGNAL(frameCreated(QWebFrame *)),
18
+ this, SLOT(frameCreated(QWebFrame *)));
19
+ }
20
+
21
+ void WebPage::loadJavascript() {
7
22
  QResource javascript(":/capybara.js");
8
23
  if (javascript.isCompressed()) {
9
24
  QByteArray uncompressedBytes(qUncompress(javascript.data(), javascript.size()));
@@ -14,11 +29,24 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
14
29
  javascriptString[javascript.size()] = 0;
15
30
  m_capybaraJavascript = javascriptString;
16
31
  }
17
- m_loading = false;
18
- connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
19
- connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
20
- connect(this, SIGNAL(frameCreated(QWebFrame *)),
21
- this, SLOT(frameCreated(QWebFrame *)));
32
+ }
33
+
34
+ void WebPage::setUserStylesheet() {
35
+ QString data = QString("* { font-family: 'Arial' ! important; }").toUtf8().toBase64();
36
+ QUrl url = QUrl(QString("data:text/css;charset=utf-8;base64,") + data);
37
+ settings()->setUserStyleSheetUrl(url);
38
+ }
39
+
40
+ QString WebPage::userAgentForUrl(const QUrl &url ) const {
41
+ if (!m_userAgent.isEmpty()) {
42
+ return m_userAgent;
43
+ } else {
44
+ return QWebPage::userAgentForUrl(url);
45
+ }
46
+ }
47
+
48
+ void WebPage::setUserAgent(QString userAgent) {
49
+ m_userAgent = userAgent;
22
50
  }
23
51
 
24
52
  void WebPage::frameCreated(QWebFrame * frame) {
@@ -90,3 +118,49 @@ QString WebPage::failureString() {
90
118
  return QString("Unable to load URL: ") + currentFrame()->requestedUrl().toString();
91
119
  }
92
120
 
121
+ bool WebPage::render(const QString &fileName) {
122
+ QFileInfo fileInfo(fileName);
123
+ QDir dir;
124
+ dir.mkpath(fileInfo.absolutePath());
125
+
126
+ QSize viewportSize = this->viewportSize();
127
+ QSize pageSize = this->mainFrame()->contentsSize();
128
+ if (pageSize.isEmpty()) {
129
+ return false;
130
+ }
131
+
132
+ QImage buffer(pageSize, QImage::Format_ARGB32);
133
+ buffer.fill(qRgba(255, 255, 255, 0));
134
+
135
+ QPainter p(&buffer);
136
+ p.setRenderHint( QPainter::Antialiasing, true);
137
+ p.setRenderHint( QPainter::TextAntialiasing, true);
138
+ p.setRenderHint( QPainter::SmoothPixmapTransform, true);
139
+
140
+ this->setViewportSize(pageSize);
141
+ this->mainFrame()->render(&p);
142
+ p.end();
143
+ this->setViewportSize(viewportSize);
144
+
145
+ return buffer.save(fileName);
146
+ }
147
+
148
+ QString WebPage::chooseFile(QWebFrame *parentFrame, const QString &suggestedFile) {
149
+ Q_UNUSED(parentFrame);
150
+ Q_UNUSED(suggestedFile);
151
+
152
+ return getLastAttachedFileName();
153
+ }
154
+
155
+ bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output) {
156
+ if (extension == ChooseMultipleFilesExtension) {
157
+ QStringList names = QStringList() << getLastAttachedFileName();
158
+ static_cast<ChooseMultipleFilesExtensionReturn*>(output)->fileNames = names;
159
+ return true;
160
+ }
161
+ return false;
162
+ }
163
+
164
+ QString WebPage::getLastAttachedFileName() {
165
+ return currentFrame()->evaluateJavaScript(QString("Capybara.lastAttachedFile")).toString();
166
+ }
data/src/WebPage.h CHANGED
@@ -8,6 +8,10 @@ class WebPage : public QWebPage {
8
8
  QVariant invokeCapybaraFunction(const char *name, QStringList &arguments);
9
9
  QVariant invokeCapybaraFunction(QString &name, QStringList &arguments);
10
10
  QString failureString();
11
+ QString userAgentForUrl(const QUrl &url ) const;
12
+ void setUserAgent(QString userAgent);
13
+ bool render(const QString &fileName);
14
+ virtual bool extension (Extension extension, const ExtensionOption *option=0, ExtensionReturn *output=0);
11
15
 
12
16
  public slots:
13
17
  bool shouldInterruptJavaScript();
@@ -22,9 +26,14 @@ class WebPage : public QWebPage {
22
26
  virtual void javaScriptAlert(QWebFrame *frame, const QString &message);
23
27
  virtual bool javaScriptConfirm(QWebFrame *frame, const QString &message);
24
28
  virtual bool javaScriptPrompt(QWebFrame *frame, const QString &message, const QString &defaultValue, QString *result);
29
+ virtual QString chooseFile(QWebFrame * parentFrame, const QString &suggestedFile);
25
30
 
26
31
  private:
27
32
  QString m_capybaraJavascript;
33
+ QString m_userAgent;
28
34
  bool m_loading;
35
+ QString getLastAttachedFileName();
36
+ void loadJavascript();
37
+ void setUserStylesheet();
29
38
  };
30
39
 
data/src/body.cpp ADDED
@@ -0,0 +1,11 @@
1
+ #include "Body.h"
2
+ #include "WebPage.h"
3
+
4
+ Body::Body(WebPage *page, QObject *parent) : Command(page, parent) {
5
+ }
6
+
7
+ void Body::start(QStringList &arguments) {
8
+ Q_UNUSED(arguments);
9
+ QString result = page()->currentFrame()->toHtml();
10
+ emit finished(new Response(true, result));
11
+ }
data/src/capybara.js CHANGED
@@ -1,6 +1,7 @@
1
1
  Capybara = {
2
2
  nextIndex: 0,
3
3
  nodes: {},
4
+ lastAttachedFile: "",
4
5
 
5
6
  invoke: function () {
6
7
  return this[CapybaraInvocation.functionName].apply(this, CapybaraInvocation.arguments);
@@ -27,16 +28,22 @@ Capybara = {
27
28
  },
28
29
 
29
30
  text: function (index) {
30
- return this.nodes[index].innerText;
31
+ var node = this.nodes[index];
32
+ var type = (node.type || node.tagName).toLowerCase();
33
+ if (type == "textarea") {
34
+ return node.innerHTML;
35
+ } else {
36
+ return node.innerText;
37
+ }
31
38
  },
32
39
 
33
40
  attribute: function (index, name) {
34
41
  switch(name) {
35
- case 'checked':
42
+ case 'checked':
36
43
  return this.nodes[index].checked;
37
44
  break;
38
45
 
39
- case 'disabled':
46
+ case 'disabled':
40
47
  return this.nodes[index].disabled;
41
48
  break;
42
49
 
@@ -84,6 +91,10 @@ Capybara = {
84
91
  return true;
85
92
  },
86
93
 
94
+ selected: function (index) {
95
+ return this.nodes[index].selected;
96
+ },
97
+
87
98
  value: function(index) {
88
99
  return this.nodes[index].value;
89
100
  },
@@ -94,7 +105,8 @@ Capybara = {
94
105
  if (type == "text" || type == "textarea" || type == "password") {
95
106
  this.trigger(index, "focus");
96
107
  node.value = "";
97
- for(var strindex = 0; strindex < value.length; strindex++) {
108
+ var length = this.attribute(index, "maxlength") || value.length;
109
+ for(var strindex = 0; strindex < length; strindex++) {
98
110
  node.value += value[strindex];
99
111
  this.trigger(index, "keydown");
100
112
  this.keypress(index, false, false, false, false, 0, value[strindex]);
@@ -106,6 +118,9 @@ Capybara = {
106
118
  node.checked = (value == "true");
107
119
  this.trigger(index, "click");
108
120
  this.trigger(index, "change");
121
+ } else if(type == "file") {
122
+ this.lastAttachedFile = value;
123
+ this.trigger(index, "click");
109
124
  } else {
110
125
  node.value = value;
111
126
  }