capybara-webkit 1.13.0 → 1.14.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.
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: []