capybara-webkit 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/.gitignore +3 -1
  2. data/Gemfile.lock +5 -4
  3. data/NEWS.md +11 -0
  4. data/README.md +42 -0
  5. data/lib/capybara/driver/webkit.rb +7 -2
  6. data/lib/capybara/driver/webkit/browser.rb +22 -96
  7. data/lib/capybara/driver/webkit/connection.rb +120 -0
  8. data/lib/capybara/driver/webkit/version.rb +1 -1
  9. data/lib/capybara/webkit/matchers.rb +2 -4
  10. data/lib/capybara_webkit_builder.rb +22 -4
  11. data/spec/browser_spec.rb +19 -29
  12. data/spec/connection_spec.rb +54 -0
  13. data/spec/driver_resize_window_spec.rb +59 -0
  14. data/spec/driver_spec.rb +175 -27
  15. data/spec/spec_helper.rb +9 -2
  16. data/src/Body.h +2 -2
  17. data/src/ClearCookies.cpp +2 -5
  18. data/src/ClearCookies.h +2 -2
  19. data/src/Command.cpp +7 -3
  20. data/src/Command.h +4 -2
  21. data/src/CommandFactory.cpp +7 -2
  22. data/src/CommandFactory.h +1 -1
  23. data/src/CommandParser.cpp +13 -5
  24. data/src/CommandParser.h +6 -2
  25. data/src/Connection.cpp +18 -47
  26. data/src/Connection.h +5 -7
  27. data/src/ConsoleMessages.cpp +2 -3
  28. data/src/ConsoleMessages.h +2 -2
  29. data/src/CurrentUrl.cpp +3 -6
  30. data/src/CurrentUrl.h +2 -2
  31. data/src/Evaluate.cpp +3 -3
  32. data/src/Evaluate.h +2 -2
  33. data/src/Execute.cpp +4 -4
  34. data/src/Execute.h +2 -2
  35. data/src/Find.cpp +4 -4
  36. data/src/Find.h +2 -2
  37. data/src/FrameFocus.cpp +7 -7
  38. data/src/FrameFocus.h +2 -2
  39. data/src/GetCookies.cpp +2 -4
  40. data/src/GetCookies.h +2 -2
  41. data/src/Header.cpp +4 -4
  42. data/src/Header.h +2 -2
  43. data/src/Headers.cpp +2 -3
  44. data/src/Headers.h +2 -2
  45. data/src/IgnoreSslErrors.cpp +12 -0
  46. data/src/IgnoreSslErrors.h +12 -0
  47. data/src/NetworkAccessManager.cpp +4 -0
  48. data/src/NetworkAccessManager.h +2 -1
  49. data/src/Node.cpp +3 -3
  50. data/src/Node.h +2 -2
  51. data/src/NullCommand.cpp +10 -0
  52. data/src/NullCommand.h +11 -0
  53. data/src/PageLoadingCommand.cpp +46 -0
  54. data/src/PageLoadingCommand.h +40 -0
  55. data/src/Render.cpp +5 -6
  56. data/src/Render.h +2 -2
  57. data/src/RequestedUrl.cpp +3 -6
  58. data/src/RequestedUrl.h +2 -2
  59. data/src/Reset.cpp +8 -7
  60. data/src/Reset.h +2 -2
  61. data/src/ResizeWindow.cpp +16 -0
  62. data/src/ResizeWindow.h +12 -0
  63. data/src/Response.cpp +6 -1
  64. data/src/Response.h +4 -2
  65. data/src/Server.cpp +2 -3
  66. data/src/Server.h +1 -1
  67. data/src/SetCookie.cpp +3 -5
  68. data/src/SetCookie.h +2 -2
  69. data/src/SetProxy.cpp +7 -9
  70. data/src/SetProxy.h +2 -2
  71. data/src/Source.cpp +2 -4
  72. data/src/Source.h +2 -2
  73. data/src/Status.cpp +2 -3
  74. data/src/Status.h +2 -2
  75. data/src/Url.cpp +3 -6
  76. data/src/Url.h +2 -2
  77. data/src/Visit.cpp +4 -13
  78. data/src/Visit.h +2 -5
  79. data/src/WebPage.cpp +11 -9
  80. data/src/WebPage.h +3 -3
  81. data/src/body.cpp +2 -3
  82. data/src/capybara.js +58 -3
  83. data/src/find_command.h +3 -1
  84. data/src/main.cpp +1 -2
  85. data/src/webkit_server.pro +8 -0
  86. metadata +29 -16
data/src/RequestedUrl.h CHANGED
@@ -6,7 +6,7 @@ class RequestedUrl : public Command {
6
6
  Q_OBJECT
7
7
 
8
8
  public:
9
- RequestedUrl(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &arguments);
9
+ RequestedUrl(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
11
  };
12
12
 
data/src/Reset.cpp CHANGED
@@ -3,19 +3,20 @@
3
3
  #include "NetworkAccessManager.h"
4
4
  #include "NetworkCookieJar.h"
5
5
 
6
- Reset::Reset(WebPage *page, QObject *parent) : Command(page, parent) {
6
+ Reset::Reset(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
7
7
  }
8
8
 
9
- void Reset::start(QStringList &arguments) {
10
- Q_UNUSED(arguments);
11
-
9
+ void Reset::start() {
12
10
  page()->triggerAction(QWebPage::Stop);
13
- page()->currentFrame()->setHtml("<html><body></body></html>");
14
- page()->networkAccessManager()->setCookieJar(new NetworkCookieJar());
15
- page()->setCustomNetworkAccessManager();
11
+
12
+ NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
13
+ networkAccessManager->setCookieJar(new NetworkCookieJar());
14
+ networkAccessManager->resetHeaders();
15
+
16
16
  page()->setUserAgent(NULL);
17
17
  page()->resetResponseHeaders();
18
18
  page()->resetConsoleMessages();
19
+ page()->resetWindowSize();
19
20
  resetHistory();
20
21
  emit finished(new Response(true));
21
22
  }
data/src/Reset.h CHANGED
@@ -6,8 +6,8 @@ class Reset : public Command {
6
6
  Q_OBJECT
7
7
 
8
8
  public:
9
- Reset(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &arguments);
9
+ Reset(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
11
 
12
12
  private:
13
13
  void resetHistory();
@@ -0,0 +1,16 @@
1
+ #include "ResizeWindow.h"
2
+ #include "WebPage.h"
3
+
4
+ ResizeWindow::ResizeWindow(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
+ }
6
+
7
+ void ResizeWindow::start() {
8
+ int width = arguments()[0].toInt();
9
+ int height = arguments()[1].toInt();
10
+
11
+ QSize size(width, height);
12
+ page()->setViewportSize(size);
13
+
14
+ emit finished(new Response(true));
15
+ }
16
+
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class ResizeWindow : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ ResizeWindow(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
+ };
12
+
data/src/Response.cpp CHANGED
@@ -2,6 +2,11 @@
2
2
  #include <iostream>
3
3
 
4
4
  Response::Response(bool success, QString message) {
5
+ m_success = success;
6
+ m_message = message.toUtf8();
7
+ }
8
+
9
+ Response::Response(bool success, QByteArray message) {
5
10
  m_success = success;
6
11
  m_message = message;
7
12
  }
@@ -14,6 +19,6 @@ bool Response::isSuccess() const {
14
19
  return m_success;
15
20
  }
16
21
 
17
- QString Response::message() const {
22
+ QByteArray Response::message() const {
18
23
  return m_message;
19
24
  }
data/src/Response.h CHANGED
@@ -1,13 +1,15 @@
1
1
  #include <QString>
2
+ #include <QByteArray>
2
3
 
3
4
  class Response {
4
5
  public:
5
6
  Response(bool success, QString message);
7
+ Response(bool success, QByteArray message);
6
8
  Response(bool success);
7
9
  bool isSuccess() const;
8
- QString message() const;
10
+ QByteArray message() const;
9
11
 
10
12
  private:
11
13
  bool m_success;
12
- QString m_message;
14
+ QByteArray m_message;
13
15
  };
data/src/Server.cpp CHANGED
@@ -4,15 +4,14 @@
4
4
 
5
5
  #include <QTcpServer>
6
6
 
7
- Server::Server(QObject *parent, bool ignoreSslErrors) : QObject(parent) {
7
+ Server::Server(QObject *parent) : QObject(parent) {
8
8
  m_tcp_server = new QTcpServer(this);
9
9
  m_page = new WebPage(this);
10
- m_page->setIgnoreSslErrors(ignoreSslErrors);
11
10
  }
12
11
 
13
12
  bool Server::start() {
14
13
  connect(m_tcp_server, SIGNAL(newConnection()), this, SLOT(handleConnection()));
15
- return m_tcp_server->listen(QHostAddress::Any, 0);
14
+ return m_tcp_server->listen(QHostAddress::LocalHost, 0);
16
15
  }
17
16
 
18
17
  quint16 Server::server_port() const {
data/src/Server.h CHANGED
@@ -7,7 +7,7 @@ class Server : public QObject {
7
7
  Q_OBJECT
8
8
 
9
9
  public:
10
- Server(QObject *parent, bool ignoreSslErrors);
10
+ Server(QObject *parent);
11
11
  bool start();
12
12
  quint16 server_port() const;
13
13
 
data/src/SetCookie.cpp CHANGED
@@ -3,13 +3,11 @@
3
3
  #include "NetworkCookieJar.h"
4
4
  #include <QNetworkCookie>
5
5
 
6
- SetCookie::SetCookie(WebPage *page, QObject *parent)
7
- : Command(page, parent)
8
- { }
6
+ SetCookie::SetCookie(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
9
7
 
10
- void SetCookie::start(QStringList &arguments)
8
+ void SetCookie::start()
11
9
  {
12
- QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(arguments[0].toAscii());
10
+ QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(arguments()[0].toAscii());
13
11
  NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
14
12
  ->networkAccessManager()
15
13
  ->cookieJar());
data/src/SetCookie.h CHANGED
@@ -6,6 +6,6 @@ class SetCookie : public Command {
6
6
  Q_OBJECT;
7
7
 
8
8
  public:
9
- SetCookie(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &arguments);
9
+ SetCookie(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
11
  };
data/src/SetProxy.cpp CHANGED
@@ -3,21 +3,19 @@
3
3
  #include <QNetworkAccessManager>
4
4
  #include <QNetworkProxy>
5
5
 
6
- SetProxy::SetProxy(WebPage *page, QObject *parent)
7
- : Command(page, parent)
8
- { }
6
+ SetProxy::SetProxy(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
9
7
 
10
- void SetProxy::start(QStringList &arguments)
8
+ void SetProxy::start()
11
9
  {
12
10
  // default to empty proxy
13
11
  QNetworkProxy proxy;
14
12
 
15
- if (arguments.size() > 0)
13
+ if (arguments().size() > 0)
16
14
  proxy = QNetworkProxy(QNetworkProxy::HttpProxy,
17
- arguments[0],
18
- (quint16)(arguments[1].toInt()),
19
- arguments[2],
20
- arguments[3]);
15
+ arguments()[0],
16
+ (quint16)(arguments()[1].toInt()),
17
+ arguments()[2],
18
+ arguments()[3]);
21
19
 
22
20
  page()->networkAccessManager()->setProxy(proxy);
23
21
  emit finished(new Response(true));
data/src/SetProxy.h CHANGED
@@ -6,6 +6,6 @@ class SetProxy : public Command {
6
6
  Q_OBJECT;
7
7
 
8
8
  public:
9
- SetProxy(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &arguments);
9
+ SetProxy(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
11
  };
data/src/Source.cpp CHANGED
@@ -1,12 +1,10 @@
1
1
  #include "Source.h"
2
2
  #include "WebPage.h"
3
3
 
4
- Source::Source(WebPage *page, QObject *parent) : Command(page, parent) {
4
+ Source::Source(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
5
  }
6
6
 
7
- void Source::start(QStringList &arguments) {
8
- Q_UNUSED(arguments)
9
-
7
+ void Source::start() {
10
8
  QNetworkAccessManager* accessManager = page()->networkAccessManager();
11
9
  QNetworkRequest request(page()->currentFrame()->url());
12
10
  reply = accessManager->get(request);
data/src/Source.h CHANGED
@@ -7,8 +7,8 @@ class Source : public Command {
7
7
  Q_OBJECT
8
8
 
9
9
  public:
10
- Source(WebPage *page, QObject *parent = 0);
11
- virtual void start(QStringList &arguments);
10
+ Source(WebPage *page, QStringList &arguments, QObject *parent = 0);
11
+ virtual void start();
12
12
 
13
13
  public slots:
14
14
  void sourceLoaded();
data/src/Status.cpp CHANGED
@@ -2,11 +2,10 @@
2
2
  #include "WebPage.h"
3
3
  #include <sstream>
4
4
 
5
- Status::Status(WebPage *page, QObject *parent) : Command(page, parent) {
5
+ Status::Status(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
6
6
  }
7
7
 
8
- void Status::start(QStringList &arguments) {
9
- Q_UNUSED(arguments);
8
+ void Status::start() {
10
9
  int status = page()->getLastStatus();
11
10
  emit finished(new Response(true, QString::number(status)));
12
11
  }
data/src/Status.h CHANGED
@@ -6,7 +6,7 @@ class Status : public Command {
6
6
  Q_OBJECT
7
7
 
8
8
  public:
9
- Status(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &arguments);
9
+ Status(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
11
  };
12
12
 
data/src/Url.cpp CHANGED
@@ -1,15 +1,12 @@
1
1
  #include "Url.h"
2
2
  #include "WebPage.h"
3
3
 
4
- Url::Url(WebPage *page, QObject *parent) : Command(page, parent) {
4
+ Url::Url(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
5
  }
6
6
 
7
- void Url::start(QStringList &argments) {
8
- Q_UNUSED(argments);
9
-
7
+ void Url::start() {
10
8
  QUrl humanUrl = page()->currentFrame()->url();
11
9
  QByteArray encodedBytes = humanUrl.toEncoded();
12
- QString urlString = QString(encodedBytes);
13
- emit finished(new Response(true, urlString));
10
+ emit finished(new Response(true, encodedBytes));
14
11
  }
15
12
 
data/src/Url.h CHANGED
@@ -6,7 +6,7 @@ class Url : public Command {
6
6
  Q_OBJECT
7
7
 
8
8
  public:
9
- Url(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &argments);
9
+ Url(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
11
  };
12
12
 
data/src/Visit.cpp CHANGED
@@ -2,20 +2,11 @@
2
2
  #include "Command.h"
3
3
  #include "WebPage.h"
4
4
 
5
- Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) {
6
- connect(page, SIGNAL(pageFinished(bool)), this, SLOT(loadFinished(bool)));
5
+ Visit::Visit(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
7
6
  }
8
7
 
9
- void Visit::start(QStringList &arguments) {
10
- QUrl requestedUrl = QUrl::fromEncoded(arguments[0].toUtf8(), QUrl::StrictMode);
8
+ void Visit::start() {
9
+ QUrl requestedUrl = QUrl::fromEncoded(arguments()[0].toUtf8(), QUrl::StrictMode);
11
10
  page()->currentFrame()->load(QUrl(requestedUrl));
12
- }
13
-
14
- void Visit::loadFinished(bool success) {
15
- QString message;
16
- if (!success)
17
- message = page()->failureString();
18
-
19
- disconnect(page(), SIGNAL(pageFinished(bool)), this, SLOT(loadFinished(bool)));
20
- emit finished(new Response(success, message));
11
+ emit finished(new Response(true));
21
12
  }
data/src/Visit.h CHANGED
@@ -6,10 +6,7 @@ class Visit : public Command {
6
6
  Q_OBJECT
7
7
 
8
8
  public:
9
- Visit(WebPage *page, QObject *parent = 0);
10
- virtual void start(QStringList &arguments);
11
-
12
- private slots:
13
- void loadFinished(bool success);
9
+ Visit(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
14
11
  };
15
12
 
data/src/WebPage.cpp CHANGED
@@ -12,6 +12,7 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
12
12
  setUserStylesheet();
13
13
 
14
14
  m_loading = false;
15
+ m_ignoreSslErrors = false;
15
16
  this->setCustomNetworkAccessManager();
16
17
 
17
18
  connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
@@ -20,7 +21,12 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
20
21
  this, SLOT(frameCreated(QWebFrame *)));
21
22
  connect(this, SIGNAL(unsupportedContent(QNetworkReply*)),
22
23
  this, SLOT(handleUnsupportedContent(QNetworkReply*)));
24
+ resetWindowSize();
25
+ }
26
+
27
+ void WebPage::resetWindowSize() {
23
28
  this->setViewportSize(QSize(1680, 1050));
29
+ this->settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
24
30
  }
25
31
 
26
32
  void WebPage::setCustomNetworkAccessManager() {
@@ -28,7 +34,8 @@ void WebPage::setCustomNetworkAccessManager() {
28
34
  manager->setCookieJar(new NetworkCookieJar());
29
35
  this->setNetworkAccessManager(manager);
30
36
  connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
31
- connect(manager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)), this, SLOT(ignoreSslErrors(QNetworkReply *, QList<QSslError>)));
37
+ connect(manager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)),
38
+ this, SLOT(handleSslErrorsForReply(QNetworkReply *, QList<QSslError>)));
32
39
  }
33
40
 
34
41
  void WebPage::loadJavascript() {
@@ -200,20 +207,15 @@ void WebPage::replyFinished(QNetworkReply *reply) {
200
207
  }
201
208
  }
202
209
 
203
- void WebPage::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors) {
210
+ void WebPage::handleSslErrorsForReply(QNetworkReply *reply, const QList<QSslError> &errors) {
204
211
  if (m_ignoreSslErrors)
205
212
  reply->ignoreSslErrors(errors);
206
213
  }
207
214
 
208
- void WebPage::setIgnoreSslErrors(bool ignore) {
209
- m_ignoreSslErrors = ignore;
215
+ void WebPage::ignoreSslErrors() {
216
+ m_ignoreSslErrors = true;
210
217
  }
211
218
 
212
- bool WebPage::ignoreSslErrors() {
213
- return m_ignoreSslErrors;
214
- }
215
-
216
-
217
219
  int WebPage::getLastStatus() {
218
220
  return m_lastStatus;
219
221
  }
data/src/WebPage.h CHANGED
@@ -15,10 +15,10 @@ class WebPage : public QWebPage {
15
15
  void setCustomNetworkAccessManager();
16
16
  bool render(const QString &fileName);
17
17
  virtual bool extension (Extension extension, const ExtensionOption *option=0, ExtensionReturn *output=0);
18
- void setIgnoreSslErrors(bool ignore);
19
- bool ignoreSslErrors();
18
+ void ignoreSslErrors();
20
19
  QString consoleMessages();
21
20
  void resetConsoleMessages();
21
+ void resetWindowSize();
22
22
 
23
23
  public slots:
24
24
  bool shouldInterruptJavaScript();
@@ -29,7 +29,7 @@ class WebPage : public QWebPage {
29
29
  QString pageHeaders();
30
30
  void frameCreated(QWebFrame *);
31
31
  void replyFinished(QNetworkReply *reply);
32
- void ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &);
32
+ void handleSslErrorsForReply(QNetworkReply *reply, const QList<QSslError> &);
33
33
  void handleUnsupportedContent(QNetworkReply *reply);
34
34
 
35
35
  signals:
data/src/body.cpp CHANGED
@@ -1,11 +1,10 @@
1
1
  #include "Body.h"
2
2
  #include "WebPage.h"
3
3
 
4
- Body::Body(WebPage *page, QObject *parent) : Command(page, parent) {
4
+ Body::Body(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
5
  }
6
6
 
7
- void Body::start(QStringList &arguments) {
8
- Q_UNUSED(arguments);
7
+ void Body::start() {
9
8
  QString result = page()->currentFrame()->toHtml();
10
9
  emit finished(new Response(true, result));
11
10
  }
data/src/capybara.js CHANGED
@@ -132,6 +132,16 @@ Capybara = {
132
132
  eventObject.metaKey = metaKey;
133
133
  eventObject.keyCode = keyCode;
134
134
  eventObject.charCode = charCode;
135
+ eventObject.which = keyCode;
136
+ this.nodes[index].dispatchEvent(eventObject);
137
+ },
138
+
139
+ keyupdown: function(index, eventName, keyCode) {
140
+ var eventObject = document.createEvent("HTMLEvents");
141
+ eventObject.initEvent(eventName, true, true);
142
+ eventObject.keyCode = keyCode;
143
+ eventObject.which = keyCode;
144
+ eventObject.charCode = 0;
135
145
  this.nodes[index].dispatchEvent(eventObject);
136
146
  },
137
147
 
@@ -153,6 +163,49 @@ Capybara = {
153
163
  return this.nodes[index].value;
154
164
  },
155
165
 
166
+ characterToKeyCode: function(character) {
167
+ var code = character.toUpperCase().charCodeAt(0);
168
+ var specialKeys = {
169
+ 96: 192, //`
170
+ 45: 189, //-
171
+ 61: 187, //=
172
+ 91: 219, //[
173
+ 93: 221, //]
174
+ 92: 220, //\
175
+ 59: 186, //;
176
+ 39: 222, //'
177
+ 44: 188, //,
178
+ 46: 190, //.
179
+ 47: 191, ///
180
+ 127: 46, //delete
181
+ 126: 192, //~
182
+ 33: 49, //!
183
+ 64: 50, //@
184
+ 35: 51, //#
185
+ 36: 52, //$
186
+ 37: 53, //%
187
+ 94: 54, //^
188
+ 38: 55, //&
189
+ 42: 56, //*
190
+ 40: 57, //(
191
+ 41: 48, //)
192
+ 95: 189, //_
193
+ 43: 187, //+
194
+ 123: 219, //{
195
+ 125: 221, //}
196
+ 124: 220, //|
197
+ 58: 186, //:
198
+ 34: 222, //"
199
+ 60: 188, //<
200
+ 62: 190, //>
201
+ 63: 191 //?
202
+ };
203
+ if (specialKeys[code]) {
204
+ code = specialKeys[code];
205
+ }
206
+ return code;
207
+ },
208
+
156
209
  set: function (index, value) {
157
210
  var length, maxLength, node, strindex, textTypes, type;
158
211
 
@@ -173,9 +226,11 @@ Capybara = {
173
226
  node.value = "";
174
227
  for (strindex = 0; strindex < length; strindex++) {
175
228
  node.value += value[strindex];
176
- this.trigger(index, "keydown");
177
- this.keypress(index, false, false, false, false, 0, value.charCodeAt(strindex));
178
- this.trigger(index, "keyup");
229
+ var keyCode = this.characterToKeyCode(value[strindex]);
230
+ this.keyupdown(index, "keydown", keyCode);
231
+ this.keypress(index, false, false, false, false, value.charCodeAt(strindex), value.charCodeAt(strindex));
232
+ this.keyupdown(index, "keyup", keyCode);
233
+ this.trigger(index, "input");
179
234
  }
180
235
  this.trigger(index, "change");
181
236
  this.trigger(index, "blur");