capybara-webkit 1.13.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f6bbf1dc179252a2f808fee415bcf4f94f3b0e0
4
- data.tar.gz: 320d1b94e5241d9aca6195f246487d018bc2d4d9
3
+ metadata.gz: adb3d932baa61a8938f10d7262631a313584a190
4
+ data.tar.gz: df339e2e1777df21576775f21a38188a972edb62
5
5
  SHA512:
6
- metadata.gz: cfe1194befdf9b3792390dab329ff59dab8ea834e132cf6d6c56d8f7a4df4748164593a5dd51c21c553b6a0c801f8bd6a9f0134b9b87d41a780c9a5d0dff75ff
7
- data.tar.gz: 27309b5dcd287b804d83c97c64bcc9f11bdac110891160ace21bb908ab8b7b68b9691165c226e87a5d1d7fb5c5a180e49ded3f1f44c75e46b6e4e720f3f32127
6
+ metadata.gz: 3154fa91673bf59aa710a48ed94ed93d2da7f3e2146e15cd9f99f952ac440b6b49b6784cbcc063ffe05dd4aa38c3108296fc14244ea316662c1d8000de0f870a
7
+ data.tar.gz: 08883b67a4e99e083eb65bfeee24d00d0775626d16d905c1a86aaa2e2f6e712b8efcd7b13c0f50e328f95d7ac016ae23375f69ffe755aede97f17f6eba28aa83
data/.gitignore CHANGED
@@ -1,6 +1,8 @@
1
1
  *.swp
2
2
  bin/webkit_server*
3
3
  test/testwebkitserver
4
+ test/moc_predefs.h
5
+ test/target_wrapper.sh
4
6
  *.swo
5
7
  *~
6
8
  *.o
@@ -28,7 +28,7 @@ matrix:
28
28
  gemfile: gemfiles/2.7.gemfile
29
29
  env: QMAKE=/usr/lib/x86_64-linux-gnu/qt4/bin/qmake
30
30
  - rvm: 1.9.3
31
- gemfile: gemfiles/2.12.gemfile
31
+ gemfile: gemfiles/2.13.gemfile
32
32
  env: QMAKE=/usr/lib/x86_64-linux-gnu/qt4/bin/qmake
33
33
  - rvm: 2.3.3
34
34
  gemfile: gemfiles/master.gemfile
@@ -36,7 +36,7 @@ matrix:
36
36
  - gemfile: gemfiles/master.gemfile
37
37
  gemfile:
38
38
  - gemfiles/2.7.gemfile
39
- - gemfiles/2.12.gemfile
39
+ - gemfiles/2.13.gemfile
40
40
  before_install:
41
41
  - gem install bundler
42
42
  install: bundle
data/Appraisals CHANGED
@@ -5,8 +5,8 @@ appraise "2.7" do
5
5
  gem 'nokogiri', '< 1.7.0', :platforms=>[:ruby_19, :jruby_19] # 1.7.0 requires ruby 2.1+
6
6
  end
7
7
 
8
- appraise "2.12" do
9
- gem "capybara", "~> 2.12.0"
8
+ appraise "2.13" do
9
+ gem "capybara", "~> 2.13.0"
10
10
  gem 'addressable', '< 2.5.0', :platforms=>[:ruby_19, :jruby_19] # 2.5 requires public_suffix which requires ruby 2.0
11
11
  gem 'nokogiri', '< 1.7.0', :platforms=>[:ruby_19, :jruby_19] # 1.7.0 requires ruby 2.1+
12
12
  end
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capybara-webkit (1.13.0)
5
- capybara (>= 2.3.0, < 2.13.0)
4
+ capybara-webkit (1.14.0)
5
+ capybara (>= 2.3.0, < 2.14.0)
6
6
  json
7
7
 
8
8
  GEM
@@ -13,7 +13,7 @@ GEM
13
13
  appraisal (0.4.1)
14
14
  bundler
15
15
  rake
16
- capybara (2.12.0)
16
+ capybara (2.13.0)
17
17
  addressable
18
18
  mime-types (>= 1.16)
19
19
  nokogiri (>= 1.3.3)
@@ -21,7 +21,7 @@ GEM
21
21
  rack-test (>= 0.5.4)
22
22
  xpath (~> 2.0)
23
23
  diff-lcs (1.3)
24
- ffi (1.9.17-java)
24
+ ffi (1.9.18-java)
25
25
  json (1.8.6)
26
26
  json (1.8.6-java)
27
27
  launchy (2.4.3)
@@ -30,12 +30,12 @@ GEM
30
30
  addressable (~> 2.3)
31
31
  spoon (~> 0.0.1)
32
32
  mime-types (2.99.3)
33
- mini_magick (4.6.0)
33
+ mini_magick (4.6.1)
34
34
  mini_portile2 (2.1.0)
35
- nokogiri (1.7.0.1)
35
+ nokogiri (1.7.1)
36
36
  mini_portile2 (~> 2.1.0)
37
- nokogiri (1.7.0.1-java)
38
- nokogiri (1.7.0.1-x86-mingw32)
37
+ nokogiri (1.7.1-java)
38
+ nokogiri (1.7.1-x86-mingw32)
39
39
  mini_portile2 (~> 2.1.0)
40
40
  public_suffix (2.0.5)
41
41
  rack (1.6.5)
@@ -63,7 +63,7 @@ GEM
63
63
  tilt (>= 1.3, < 3)
64
64
  spoon (0.0.6)
65
65
  ffi
66
- tilt (2.0.6)
66
+ tilt (2.0.7)
67
67
  xpath (2.0.0)
68
68
  nokogiri (~> 1.3)
69
69
 
@@ -84,4 +84,4 @@ DEPENDENCIES
84
84
  sinatra
85
85
 
86
86
  BUNDLED WITH
87
- 1.14.3
87
+ 1.14.5
data/NEWS.md CHANGED
@@ -1,3 +1,13 @@
1
+ New for 1.14.0:
2
+
3
+ * Fix the 'Reset' command in debug builds (on Windows)
4
+ * Check for Windows platform in a jruby compatible way
5
+ * Include qtwebkitversion.h to work in newer qtwebkit
6
+ * Support Capybara 2.13 and fix some hound warnings
7
+ * Support returning elements from evaluate_script
8
+ * Support most of the keys specified by Capybara for Node#send_keys
9
+ * Fix issue with switching to the same frame twice in a row
10
+
1
11
  New for 1.13.0:
2
12
 
3
13
  * Allow JavaScript errors to be raised as Ruby exceptions
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
 
22
22
  s.requirements << "Qt >= 4.8"
23
23
 
24
- s.add_runtime_dependency("capybara", ">= 2.3.0", "< 2.13.0")
24
+ s.add_runtime_dependency("capybara", ">= 2.3.0", "< 2.14.0")
25
25
  s.add_runtime_dependency("json")
26
26
 
27
27
  s.add_development_dependency("rspec", "~> 3.5")
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19]
6
6
  gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19]
7
- gem "capybara", "~> 2.12.0"
7
+ gem "capybara", "~> 2.13.0"
8
8
  gem "addressable", "< 2.5.0", :platforms=>[:ruby_19, :jruby_19]
9
9
  gem "nokogiri", "< 1.7.0", :platforms=>[:ruby_19, :jruby_19]
10
10
 
@@ -83,7 +83,7 @@ module Capybara::Webkit
83
83
 
84
84
  def frame_focus(selector=nil)
85
85
  if selector.respond_to?(:base)
86
- selector.base.invoke('focus')
86
+ selector.base.invoke("focus_frame")
87
87
  elsif selector.is_a? Fixnum
88
88
  command("FrameFocus", "", selector.to_s)
89
89
  elsif selector
@@ -87,7 +87,8 @@ module Capybara::Webkit
87
87
  end
88
88
 
89
89
  def evaluate_script(script, *args)
90
- @browser.evaluate_script(script, *encode_args(args))
90
+ result = @browser.evaluate_script(script, *encode_args(args))
91
+ decode_result(result)
91
92
  end
92
93
 
93
94
  def console_messages
@@ -419,11 +420,26 @@ module Capybara::Webkit
419
420
  def encode_args(args)
420
421
  args.map do |arg|
421
422
  if arg.is_a?(Capybara::Webkit::Node)
422
- { ELEMENT: arg.native }.to_json
423
+ { "element-581e-422e-8be1-884c4e116226" => arg.native }.to_json
423
424
  else
424
425
  arg.to_json
425
426
  end
426
427
  end
427
428
  end
429
+
430
+ def decode_result(result)
431
+ case result
432
+ when Array
433
+ result.map { |r| decode_result(r) }
434
+ when Hash
435
+ if element_ref = result["element-581e-422e-8be1-884c4e116226"]
436
+ Capybara::Webkit::Node.new(self, element_ref, @browser)
437
+ else
438
+ result.each { |k, v| result[k] = decode_result(v) }
439
+ end
440
+ else
441
+ result
442
+ end
443
+ end
428
444
  end
429
445
  end
@@ -48,20 +48,9 @@ module Capybara::Webkit
48
48
  end
49
49
 
50
50
  def send_keys(*keys)
51
- invoke("sendKeys", keys.map { |key|
52
- case key
53
- when :space
54
- " "
55
- when :enter
56
- "\r"
57
- when :backspace
58
- "\b"
59
- when String
60
- key.to_s
61
- else
62
- raise Capybara::NotSupportedByDriverError.new, "Unrecognized key(s) in #{key}"
63
- end
64
- }.join)
51
+ # Currently unsupported keys specified by Capybara
52
+ # :separator
53
+ invoke("sendKeys", convert_to_named_keys(keys).to_json)
65
54
  end
66
55
 
67
56
  def select_option
@@ -172,5 +161,46 @@ module Capybara::Webkit
172
161
  def ==(other)
173
162
  invoke("equals", other.native) == "true"
174
163
  end
164
+
165
+ private
166
+
167
+ def convert_to_named_keys(key)
168
+ if key.is_a? Array
169
+ key.map { |k| convert_to_named_keys(k)}
170
+ else
171
+ case key
172
+ when :cancel, :help, :backspace, :tab, :clear, :return, :enter, :insert, :delete, :pause, :escape,
173
+ :space, :end, :home, :left, :up, :right, :down, :semicolon,
174
+ :f1, :f2, :f3, :f4, :f5, :f6, :f7, :f8, :f9, :f10, :f11, :f12,
175
+ :shift, :control, :alt, :meta
176
+ { "key" => key.to_s.capitalize }
177
+ when :equals
178
+ { "key" => "Equal" }
179
+ when :page_up
180
+ { "key" => "PageUp" }
181
+ when :page_down
182
+ { "key" => "PageDown" }
183
+ when :numpad0, :numpad1, :numpad2, :numpad3, :numpad4,
184
+ :numpad5, :numpad6, :numpad7, :numpad9, :numpad9
185
+ { "key" => key[-1], "modifier" => "keypad" }
186
+ when :multiply
187
+ { "key" => "Asterisk", "modifier" => "keypad" }
188
+ when :divide
189
+ { "key" => "Slash", "modifier" => "keypad" }
190
+ when :add
191
+ { "key" => "Plus", "modifier" => "keypad" }
192
+ when :subtract
193
+ { "key" => "Minus", "modifier" => "keypad" }
194
+ when :decimal
195
+ { "key" => "Period", "modifier" => "keypad" }
196
+ when :command
197
+ { "key" => "Meta" }
198
+ when String
199
+ key.to_s
200
+ else
201
+ raise Capybara::NotSupportedByDriverError.new
202
+ end
203
+ end
204
+ end
175
205
  end
176
206
  end
@@ -1,7 +1,7 @@
1
1
  module Capybara
2
2
  module Driver
3
3
  class Webkit
4
- VERSION = "1.13.0".freeze
4
+ VERSION = "1.14.0".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -49,8 +49,7 @@ module CapybaraWebkitBuilder
49
49
  end
50
50
 
51
51
  def path_to_binary
52
- case RUBY_PLATFORM
53
- when /mingw32/
52
+ if Gem.win_platform?
54
53
  "src/debug/webkit_server.exe"
55
54
  else
56
55
  "src/webkit_server"
@@ -522,6 +522,21 @@ describe Capybara::Webkit::Driver do
522
522
  expect(result).to eq 1.5
523
523
  end
524
524
 
525
+ it "evaluates Javascript and returns an element" do
526
+ result = driver.evaluate_script(%<document.getElementById('greeting')>)
527
+ expect(result).to eq driver.find_css("#greeting").first
528
+ end
529
+
530
+ it "evaluates Javascript and returns a structure containing elements" do
531
+ result = driver.evaluate_script(%<({ 'a': document.getElementById('greeting'), 'b': { 'c': document.querySelectorAll('#greeting, #checktest') } })>)
532
+ expect(result).to eq(
533
+ "a" => driver.find_css("#greeting").first,
534
+ "b" => {
535
+ "c" => driver.find_css("#greeting, #checktest")
536
+ },
537
+ )
538
+ end
539
+
525
540
  it "evaluates Javascript and returns null" do
526
541
  result = driver.evaluate_script(%<(function () {})()>)
527
542
  expect(result).to eq nil
@@ -1273,6 +1288,17 @@ describe Capybara::Webkit::Driver do
1273
1288
  <input type="radio" id="only-radio" value="1"/>
1274
1289
  <button type="reset">Reset Form</button>
1275
1290
  </form>
1291
+ <div id="key_events"></div>
1292
+ <script>
1293
+ var form = document.getElementsByTagName('form')[0];
1294
+ var output = document.getElementById('key_events');
1295
+ form.addEventListener('keydown', function(e){
1296
+ output.innerHTML = output.innerHTML + " d:" + (e.key || e.which);
1297
+ });
1298
+ form.addEventListener('keyup', function(e){
1299
+ output.innerHTML = output.innerHTML + " u:" + (e.key || e.which);
1300
+ });
1301
+ </script>
1276
1302
  </body></html>
1277
1303
  HTML
1278
1304
  end
@@ -1341,6 +1367,21 @@ describe Capybara::Webkit::Driver do
1341
1367
  input.send_keys(*[:backspace])
1342
1368
  expect(input.value).to eq "do"
1343
1369
  end
1370
+
1371
+ it "should support :modifiers" do
1372
+ input = driver.find_xpath("//input").first
1373
+ input.send_keys("abc", [:shift, :left], "def")
1374
+ expect(input.value).to eq "abdef"
1375
+ input.send_keys([:control, "a"], [:shift, "upper"])
1376
+ expect(input.value).to eq "UPPER"
1377
+ end
1378
+
1379
+ it "releases modifiers correctly" do
1380
+ input = driver.find_xpath("//input").first
1381
+ input.send_keys("a", [:shift, :left], "a")
1382
+ event_text = driver.find_css("#key_events").first.text
1383
+ expect(event_text).to eq "d:65 u:65 d:16 d:37 u:37 u:16 d:65 u:65"
1384
+ end
1344
1385
  end
1345
1386
 
1346
1387
  let(:monkey_option) { driver.find_xpath("//option[@id='select-option-monkey']").first }
@@ -325,6 +325,16 @@ describe Capybara::Session do
325
325
  end
326
326
  end
327
327
  end
328
+
329
+ it "can swap to the same frame multiple times" do
330
+ subject.visit("/")
331
+ subject.within_frame("a_frame") do
332
+ expect(subject).to have_content("Page A")
333
+ end
334
+ subject.within_frame("a_frame") do
335
+ expect(subject).to have_content("Page A")
336
+ end
337
+ end
328
338
  end
329
339
 
330
340
  context 'click tests' do
@@ -52,15 +52,13 @@ RSpec.configure do |c|
52
52
  # Accessing unattached nodes is allowed when reload is disabled - Legacy behavior
53
53
  # Node#send_keys does not support modifiers and only supports a subset of special keys
54
54
  c.filter_run_excluding :full_description => lambda { |description, metadata|
55
- (description !~ /Capybara::Session webkit node #send_keys should send a string of keys to an element/) && (
56
- description =~ /Capybara::Session webkit node #send_keys/ ||
57
- description =~ /Capybara::Session webkit node #reload without automatic reload should not automatically reload/ ||
58
- if Gem::Version.new(Capybara::VERSION) < Gem::Version.new("2.12.0")
59
- description =~ /Capybara::Session webkit Capybara::Window\s*#(size|resize_to|maximize|close.*no_such_window_error|send_keys)/ ||
60
- description =~ /Capybara::Session webkit node\s*#set should allow me to change the contents of a contenteditable elements child/
61
- else
62
- description =~ /Capybara::Session webkit Capybara::Window\s*#close.*no_such_window_error/
63
- end
55
+ (description =~ /Capybara::Session webkit node #reload without automatic reload should not automatically reload/ ||
56
+ if Gem::Version.new(Capybara::VERSION) < Gem::Version.new("2.12.0")
57
+ description =~ /Capybara::Session webkit Capybara::Window\s*#(size|resize_to|maximize|close.*no_such_window_error)/ ||
58
+ description =~ /Capybara::Session webkit node\s*#set should allow me to change the contents of a contenteditable elements child/
59
+ else
60
+ description =~ /Capybara::Session webkit Capybara::Window\s*#close.*no_such_window_error/
61
+ end
64
62
  )
65
63
  }
66
64
  end
@@ -18,12 +18,14 @@ void Evaluate::start() {
18
18
  QString eval_script = QString("(function(){"
19
19
  " for(var i=0; i<arguments.length; i++) {"
20
20
  " arguments[i] = JSON.parse(arguments[i]);"
21
- " if (arguments[i]['ELEMENT']) {"
22
- " arguments[i] = Capybara.getNode(arguments[i]['ELEMENT']);"
21
+ " var elem_id;"
22
+ " if (elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226']) {"
23
+ " arguments[i] = Capybara.getNode(elem_id);"
23
24
  " };"
24
25
  " };"
25
- " return eval(\"%1\");"
26
- " }).apply(null, %2)").arg(script.replace("\"","\\\"").remove("\n"), jsonArgs);
26
+ " var _result = eval(\"%1\");"
27
+ " return Capybara.wrapResult(_result);"
28
+ " }).apply(null, %2)").arg(script.replace("\"","\\\"").remove("\n"), jsonArgs);
27
29
  QObject invocation_stub;
28
30
  invocation_stub.setProperty("allowUnattached", false);
29
31
  page()->currentFrame()->addToJavaScriptWindowObject("CapybaraInvocation", &invocation_stub);
@@ -16,8 +16,9 @@ void Execute::start() {
16
16
  QString script = QString("(function(){"
17
17
  " for(var i=0; i<arguments.length; i++) {"
18
18
  " arguments[i] = JSON.parse(arguments[i]);"
19
- " if (arguments[i]['ELEMENT']) {"
20
- " arguments[i] = Capybara.getNode(arguments[i]['ELEMENT']);"
19
+ " var elem_id;"
20
+ " if (elem_id = arguments[i]['element-581e-422e-8be1-884c4e116226']) {"
21
+ " arguments[i] = Capybara.getNode(elem_id);"
21
22
  " };"
22
23
  " };"
23
24
  " %1 }).apply(null, %2); 'success'").arg(arguments()[0], jsonArgs);
@@ -134,14 +134,79 @@ int JavascriptInvocation::keyCodeFor(const QChar &key) {
134
134
  }
135
135
  }
136
136
 
137
+ int JavascriptInvocation::keyCodeForName(const QString &keyName) {
138
+ const QMetaObject &mo = JavascriptInvocation::staticMetaObject;
139
+ int prop_index = mo.indexOfProperty("key_enum");
140
+ QMetaProperty metaProperty = mo.property(prop_index);
141
+ QMetaEnum metaEnum = metaProperty.enumerator();
142
+
143
+ QByteArray array ((QString("Key_") + keyName).toStdString().c_str());
144
+ return metaEnum.keyToValue(array);
145
+ // return Qt::Key_unknown;
146
+ }
147
+
137
148
  void JavascriptInvocation::keypress(QChar key) {
138
149
  int keyCode = keyCodeFor(key);
139
- QKeyEvent event(QKeyEvent::KeyPress, keyCode, Qt::NoModifier, key);
150
+ QKeyEvent event(QKeyEvent::KeyPress, keyCode, m_currentModifiers, (m_currentModifiers ? QString() : key));
151
+ QApplication::sendEvent(m_page, &event);
152
+ event = QKeyEvent(QKeyEvent::KeyRelease, keyCode, m_currentModifiers);
153
+ QApplication::sendEvent(m_page, &event);
154
+ }
155
+
156
+ void JavascriptInvocation::namedKeypress(QString keyName, QString modifiers){
157
+ Qt::KeyboardModifiers key_modifiers(m_currentModifiers);
158
+ if (modifiers == "Keypad") {
159
+ key_modifiers |= Qt::KeypadModifier;
160
+ };
161
+ int keyCode = keyCodeForName(keyName);
162
+ QKeyEvent event(QKeyEvent::KeyPress, keyCode, key_modifiers);
140
163
  QApplication::sendEvent(m_page, &event);
141
- event = QKeyEvent(QKeyEvent::KeyRelease, keyCode, Qt::NoModifier, key);
164
+ event = QKeyEvent(QKeyEvent::KeyRelease, keyCode, key_modifiers);
142
165
  QApplication::sendEvent(m_page, &event);
143
166
  }
144
167
 
168
+ void JavascriptInvocation::namedKeydown(QString keyName){
169
+ int keyCode = keyCodeForName(keyName);
170
+ QKeyEvent event(QKeyEvent::KeyPress, keyCode, m_currentModifiers);
171
+ QApplication::sendEvent(m_page, &event);
172
+
173
+ switch(keyCode){
174
+ case Qt::Key_Shift:
175
+ m_currentModifiers |= Qt::ShiftModifier;
176
+ break;
177
+ case Qt::Key_Control:
178
+ m_currentModifiers |= Qt::ControlModifier;
179
+ break;
180
+ case Qt::Key_Alt:
181
+ m_currentModifiers |= Qt::AltModifier;
182
+ break;
183
+ case Qt::Key_Meta:
184
+ m_currentModifiers |= Qt::MetaModifier;
185
+ break;
186
+ };
187
+ }
188
+
189
+ void JavascriptInvocation::namedKeyup(QString keyName){
190
+ int keyCode = keyCodeForName(keyName);
191
+ QKeyEvent event(QKeyEvent::KeyRelease, keyCode, m_currentModifiers, 0);
192
+ QApplication::sendEvent(m_page, &event);
193
+
194
+ switch(keyCode){
195
+ case Qt::Key_Shift:
196
+ m_currentModifiers &= ~Qt::ShiftModifier;
197
+ break;
198
+ case Qt::Key_Control:
199
+ m_currentModifiers &= ~Qt::ControlModifier;
200
+ break;
201
+ case Qt::Key_Alt:
202
+ m_currentModifiers &= ~Qt::AltModifier;
203
+ break;
204
+ case Qt::Key_Meta:
205
+ m_currentModifiers &= ~Qt::MetaModifier;
206
+ break;
207
+ };
208
+ }
209
+
145
210
  const QString JavascriptInvocation::render(void) {
146
211
  QString pathTemplate =
147
212
  QDir::temp().absoluteFilePath("./click_failed_XXXXXX.png");
@@ -13,6 +13,7 @@ class JavascriptInvocation : public QObject {
13
13
  Q_PROPERTY(bool allowUnattached READ allowUnattached)
14
14
  Q_PROPERTY(QStringList arguments READ arguments)
15
15
  Q_PROPERTY(QVariant error READ getError WRITE setError)
16
+ Q_PROPERTY(Qt::Key key_enum)
16
17
 
17
18
  public:
18
19
  JavascriptInvocation(const QString &functionName, bool allowUnattached, const QStringList &arguments, WebPage *page, QObject *parent = 0);
@@ -26,6 +27,9 @@ class JavascriptInvocation : public QObject {
26
27
  Q_INVOKABLE QVariantMap clickPosition(QWebElement element, int left, int top, int width, int height);
27
28
  Q_INVOKABLE void hover(int absoluteX, int absoluteY);
28
29
  Q_INVOKABLE void keypress(QChar);
30
+ Q_INVOKABLE void namedKeydown(QString keyName);
31
+ Q_INVOKABLE void namedKeyup(QString keyName);
32
+ Q_INVOKABLE void namedKeypress(QString keyName, QString modifiers);
29
33
  Q_INVOKABLE const QString render(void);
30
34
  QVariant getError();
31
35
  void setError(QVariant error);
@@ -39,5 +43,8 @@ class JavascriptInvocation : public QObject {
39
43
  QVariant m_error;
40
44
  void hover(const QPoint &);
41
45
  int keyCodeFor(const QChar &);
46
+ int keyCodeForName(const QString &);
47
+ Qt::Key key_enum;
48
+ Qt::KeyboardModifiers m_currentModifiers;
42
49
  };
43
50
 
@@ -11,7 +11,7 @@ void Node::start() {
11
11
  QString functionName = functionArguments.takeFirst();
12
12
  QString allowUnattached = functionArguments.takeFirst();
13
13
  InvocationResult result = page()->invokeCapybaraFunction(functionName, allowUnattached == "true", functionArguments);
14
- if (functionName == "focus") {
14
+ if (functionName == "focus_frame") {
15
15
  page()->setCurrentFrameParent(page()->currentFrame()->parentFrame());
16
16
  }
17
17
  finish(&result);
@@ -1,5 +1,9 @@
1
1
  #include "SocketCommand.h"
2
2
 
3
+ #ifndef QTWEBKIT_VERSION_STR
4
+ #include "qtwebkitversion.h"
5
+ #endif
6
+
3
7
  class Version : public SocketCommand {
4
8
  Q_OBJECT
5
9
 
@@ -40,13 +40,6 @@ WebPage::WebPage(WebPageManager *manager, QObject *parent) : QWebPage(parent) {
40
40
  settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
41
41
  settings()->setAttribute(QWebSettings::JavascriptCanCloseWindows, true);
42
42
  settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
43
-
44
- if(QFileInfo("tmp").isDir()) {
45
- settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, true);
46
- settings()->setOfflineWebApplicationCachePath("tmp");
47
- }
48
-
49
- createWindow();
50
43
  }
51
44
 
52
45
  void WebPage::createWindow() {
@@ -7,12 +7,14 @@
7
7
  #include "MissingContentHeaderRequestHandler.h"
8
8
  #include "UnknownUrlHandler.h"
9
9
  #include "NetworkRequestFactory.h"
10
+ #include <QWebSettings>
10
11
 
11
12
  WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
12
13
  m_ignoreSslErrors = false;
13
14
  m_cookieJar = new NetworkCookieJar(this);
14
15
  m_success = true;
15
16
  m_loggingEnabled = false;
17
+ m_isCacheInitialized = false;
16
18
  m_ignoredOutput = new QFile(this);
17
19
  m_timeout = -1;
18
20
  m_customHeadersRequestHandler = new CustomHeadersRequestHandler(
@@ -55,6 +57,9 @@ WebPage *WebPageManager::currentPage() const {
55
57
 
56
58
  WebPage *WebPageManager::createPage() {
57
59
  WebPage *page = new WebPage(this);
60
+ initOfflineWebApplicationCache();
61
+ page->createWindow();
62
+
58
63
  connect(page, SIGNAL(loadStarted()),
59
64
  this, SLOT(emitLoadStarted()));
60
65
  connect(page, SIGNAL(pageFinished(bool)),
@@ -217,3 +222,11 @@ void WebPageManager::allowUrl(const QString &url) {
217
222
  void WebPageManager::blockUrl(const QString &url) {
218
223
  m_blacklistedRequestHandler->blockUrl(url);
219
224
  }
225
+
226
+ void WebPageManager::initOfflineWebApplicationCache() {
227
+ if (!m_isCacheInitialized && QFileInfo("tmp").isDir()) {
228
+ QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, true);
229
+ QWebSettings::globalSettings()->setOfflineWebApplicationCachePath("tmp");
230
+ m_isCacheInitialized = true;
231
+ }
232
+ }
@@ -57,6 +57,7 @@ class WebPageManager : public QObject {
57
57
  private:
58
58
  void emitPageFinished();
59
59
  static void handleDebugMessage(QtMsgType type, const char *message);
60
+ void initOfflineWebApplicationCache();
60
61
 
61
62
  QList<WebPage *> m_pages;
62
63
  QList<QNetworkReply *> m_pendingReplies;
@@ -66,6 +67,7 @@ class WebPageManager : public QObject {
66
67
  QSet<WebPage *> m_started;
67
68
  bool m_success;
68
69
  bool m_loggingEnabled;
70
+ bool m_isCacheInitialized;
69
71
  QFile *m_ignoredOutput;
70
72
  int m_timeout;
71
73
  NetworkAccessManager *m_networkAccessManager;
@@ -2,6 +2,7 @@ Capybara = {
2
2
  nextIndex: 0,
3
3
  nodes: {},
4
4
  attachedFiles: [],
5
+ keyModifiersStack: [],
5
6
 
6
7
  invoke: function () {
7
8
  try {
@@ -36,9 +37,7 @@ Capybara = {
36
37
  var node;
37
38
  var results = [];
38
39
  while (node = iterator.iterateNext()) {
39
- this.nextIndex++;
40
- this.nodes[this.nextIndex] = node;
41
- results.push(this.nextIndex);
40
+ results.push(this.registerNode(node));
42
41
  }
43
42
  return results.join(",");
44
43
  },
@@ -47,9 +46,7 @@ Capybara = {
47
46
  var elements = reference.querySelectorAll(selector);
48
47
  var results = [];
49
48
  for (var i = 0; i < elements.length; i++) {
50
- this.nextIndex++;
51
- this.nodes[this.nextIndex] = elements[i];
52
- results.push(this.nextIndex);
49
+ results.push(this.registerNode(elements[i]));
53
50
  }
54
51
  return results.join(",");
55
52
  },
@@ -285,17 +282,45 @@ Capybara = {
285
282
  return true;
286
283
  },
287
284
 
288
- sendKeys: function (index, keys) {
289
- var strindex, length;
290
-
285
+ sendKeys: function (elem_index, json_keys) {
286
+ var idx, length, keys;
287
+ keys = JSON.parse(json_keys);
291
288
  length = keys.length;
292
289
 
293
290
  if (length) {
294
- this.focus(index);
291
+ this.focus(elem_index);
295
292
  }
296
293
 
297
- for (strindex = 0; strindex < length; strindex++) {
298
- CapybaraInvocation.keypress(keys[strindex]);
294
+ for (idx = 0; idx < length; idx++) {
295
+ this._sendKeys(keys[idx]);
296
+ }
297
+ },
298
+
299
+ _sendKeys: function(keys) {
300
+ if (typeof keys == "string") {
301
+ var str_len = keys.length;
302
+ var str_idx;
303
+ for (str_idx = 0; str_idx < str_len; str_idx++) {
304
+ CapybaraInvocation.keypress(keys[str_idx]);
305
+ }
306
+ } else if (Array.isArray(keys)) {
307
+ this.keyModifiersStack.push([]);
308
+ var idx;
309
+ for (idx = 0; idx < keys.length; idx++) {
310
+ this._sendKeys(keys[idx]);
311
+ }
312
+ var mods = this.keyModifiersStack.pop();
313
+ while (mods.length) {
314
+ CapybaraInvocation.namedKeyup(mods.pop().key);
315
+ }
316
+ } else {
317
+ key = keys.key;
318
+ if (["Shift", "Control", "Alt", "Meta"].indexOf(key) > -1){
319
+ CapybaraInvocation.namedKeydown(key);
320
+ this.keyModifiersStack[this.keyModifiersStack.length-1].push(keys);
321
+ } else {
322
+ CapybaraInvocation.namedKeypress(key, keys.modifier);
323
+ }
299
324
  }
300
325
  },
301
326
 
@@ -357,6 +382,14 @@ Capybara = {
357
382
  this.getNode(index).focus();
358
383
  },
359
384
 
385
+ focus_frame: function(index) {
386
+ var elem = this.getNode(index);
387
+ if (elem === document.activeElement) {
388
+ elem.blur();
389
+ }
390
+ elem.focus();
391
+ },
392
+
360
393
  selectOption: function(index) {
361
394
  var optionNode = this.getNode(index);
362
395
  var selectNode = optionNode.parentNode;
@@ -440,9 +473,34 @@ Capybara = {
440
473
  mouseTrigger('mousemove', options);
441
474
  mouseTrigger('mouseup', options);
442
475
  },
443
-
476
+ registerNode: function(node) {
477
+ this.nextIndex++;
478
+ this.nodes[this.nextIndex] = node;
479
+ return this.nextIndex;
480
+ },
444
481
  equals: function(index, targetIndex) {
445
482
  return this.getNode(index) === this.getNode(targetIndex);
483
+ },
484
+ _visitedObjects: [],
485
+ wrapResult: function(arg) {
486
+ if (this._visitedObjects.indexOf(arg) >= 0) { return '(cyclic structure)'; }
487
+ if (arg instanceof NodeList) { arg = Array.prototype.slice.call(arg, 0); }
488
+ if (Array.isArray(arg)) {
489
+ for(var _j = 0; _j < arg.length; _j++) {
490
+ arg[_j] = this.wrapResult(arg[_j]);
491
+ }
492
+ } else if (arg && arg.nodeType == 1 && arg.tagName) {
493
+ return {'element-581e-422e-8be1-884c4e116226': this.registerNode(arg)};
494
+ } else if (arg === null) {
495
+ return undefined;
496
+ } else if ( typeof arg == 'object' ) {
497
+ this._visitedObjects.push(arg);
498
+ for(var _k in arg){
499
+ arg[_k] = this.wrapResult(arg[_k]);
500
+ }
501
+ this._visitedObjects.pop();
502
+ }
503
+ return arg;
446
504
  }
447
505
  };
448
506
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-webkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.0
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoughtbot
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2017-03-20 00:00:00.000000000 Z
16
+ date: 2017-03-26 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: capybara
@@ -24,7 +24,7 @@ dependencies:
24
24
  version: 2.3.0
25
25
  - - "<"
26
26
  - !ruby/object:Gem::Version
27
- version: 2.13.0
27
+ version: 2.14.0
28
28
  type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
@@ -34,7 +34,7 @@ dependencies:
34
34
  version: 2.3.0
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
- version: 2.13.0
37
+ version: 2.14.0
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: json
40
40
  requirement: !ruby/object:Gem::Requirement
@@ -155,7 +155,7 @@ files:
155
155
  - bin/Info.plist
156
156
  - capybara-webkit.gemspec
157
157
  - extconf.rb
158
- - gemfiles/2.12.gemfile
158
+ - gemfiles/2.13.gemfile
159
159
  - gemfiles/2.7.gemfile
160
160
  - gemfiles/master.gemfile
161
161
  - lib/capybara-webkit.rb
@@ -385,26 +385,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
385
385
  requirements:
386
386
  - Qt >= 4.8
387
387
  rubyforge_project:
388
- rubygems_version: 2.6.8
388
+ rubygems_version: 2.4.5.1
389
389
  signing_key:
390
390
  specification_version: 4
391
391
  summary: Headless Webkit driver for Capybara
392
- test_files:
393
- - spec/browser_spec.rb
394
- - spec/capybara_webkit_builder_spec.rb
395
- - spec/configuration_spec.rb
396
- - spec/connection_spec.rb
397
- - spec/cookie_jar_spec.rb
398
- - spec/driver_rendering_spec.rb
399
- - spec/driver_resize_window_spec.rb
400
- - spec/driver_spec.rb
401
- - spec/errors_spec.rb
402
- - spec/fixtures/fake_server.sh
403
- - spec/integration/session_spec.rb
404
- - spec/selenium_compatibility_spec.rb
405
- - spec/self_signed_ssl_cert.rb
406
- - spec/server_spec.rb
407
- - spec/spec_helper.rb
408
- - spec/support/app_runner.rb
409
- - spec/support/matchers/include_response.rb
410
- - spec/support/output_writer.rb
392
+ test_files: []