capybara-webkit 0.11.0 → 0.12.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.
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");