Node#[] should prefer properties over attributes

This commit is contained in:
Thomas Walpole 2017-11-08 09:11:56 -08:00
parent d53cf7c214
commit 7ce97f2539
5 changed files with 101 additions and 30 deletions

View File

@ -15,16 +15,18 @@ module Capybara::Webkit
end end
def [](name) def [](name)
value = invoke("attribute", name) name = name.to_s
if name == 'checked' || name == 'disabled' || name == 'multiple' tn = tag_name
value == 'true' if (tn == "img" && name == "src") || (tn == "a" && name == "href")
# Although the attribute matters, the property is consistent. Return that in
# preference to the attribute for links and images.
# if attribute exists get the property
val = invoke(:attribute, name) && invoke(:property, name)
else else
if invoke("hasAttribute", name) == 'true' val = invoke(:property, name)
value val = invoke(:attribute, name) if val.nil? || val.is_a?(Hash)
else
nil
end
end end
val
end end
def value def value
@ -91,15 +93,15 @@ module Capybara::Webkit
end end
def visible? def visible?
invoke("visible") == "true" invoke("visible") == true
end end
def selected? def selected?
invoke("selected") == "true" invoke("selected") == true
end end
def checked? def checked?
self['checked'] !!self["checked"]
end end
def disabled? def disabled?
@ -139,7 +141,8 @@ module Capybara::Webkit
end end
def invoke(name, *args) def invoke(name, *args)
@browser.command "Node", name, allow_unattached_nodes?, native, *args result = @browser.command "Node", name, allow_unattached_nodes?, native, *args
JSON.parse(result, quirks_mode: true)
end end
def allow_unattached_nodes? def allow_unattached_nodes?
@ -153,7 +156,8 @@ module Capybara::Webkit
def attached? def attached?
warn "[DEPRECATION] The Capybara::Webkit::Node#attached? " \ warn "[DEPRECATION] The Capybara::Webkit::Node#attached? " \
"method is deprecated without replacement." "method is deprecated without replacement."
@browser.command("Node", "isAttached", native) == "true" result = @browser.command("Node", "isAttached", native)
JSON.parse(result, quirks_mode: true)
end end
def multiple_select? def multiple_select?
@ -161,7 +165,7 @@ module Capybara::Webkit
end end
def ==(other) def ==(other)
invoke("equals", other.native) == "true" invoke("equals", other.native)
end end
private private

View File

@ -1439,7 +1439,7 @@ describe Capybara::Webkit::Driver do
end end
it "does not modify the selected attribute of a new selection" do it "does not modify the selected attribute of a new selection" do
expect(monkey_option['selected']).to be_nil expect(driver.evaluate_script("arguments[0].getAttribute('selected')", monkey_option)).to be_nil
end end
it "returns the old value when a reset button is clicked" do it "returns the old value when a reset button is clicked" do

66
spec/node_spec.rb Normal file
View File

@ -0,0 +1,66 @@
# -*- encoding: UTF-8 -*-
require "spec_helper"
require "capybara/webkit/driver"
require "base64"
require "self_signed_ssl_cert"
describe Capybara::Webkit::Node do
include AppRunner
def visit(path, driver = self.driver)
driver.visit(url(path))
end
def url(path)
"#{AppRunner.app_host}#{path}"
end
context "html app" do
let(:driver) do
driver_for_html(<<-HTML)
<html>
<head>
<title>Hello HTML</title>
</head>
<body>
<form action="/" method="GET">
<input type="text" name="foo" value="bar"/>
<input type="checkbox" name="checkedbox" value="1" checked="checked"/>
<input type="checkbox" name="uncheckedbox" value="2"/>
<input type="checkbox" name="falsecheckedbox" value="3" checked="false"/>
<input type="text" name="styled" style="font-size: 150%;"/>
</form>
</body>
</html>
HTML
end
before { visit("/") }
context "Node#[]" do
it "gets boolean properties" do
box1 = driver.find_css('input[name="checkedbox"]').first
box2 = driver.find_css('input[name="uncheckedbox"]').first
box3 = driver.find_css('input[name="falsecheckedbox"]').first
expect(box1["checked"]).to eq true
expect(box2["checked"]).to eq false
expect(box3["checked"]).to eq true
box1.set(false)
expect(box1["checked"]).to eq false
end
it "prefers property over attribute" do
input = driver.find_css('input[name="foo"]').first
expect(input["value"]).to eq "bar"
input.set("new value")
expect(input["value"]).to eq "new value"
end
it "returns attribute when property is an object" do
input = driver.find_css('input[name="styled"]').first
expect(input["style"]).to eq "font-size: 150%;"
end
end
end
end

View File

@ -1,6 +1,7 @@
#include "Node.h" #include "Node.h"
#include "WebPage.h" #include "WebPage.h"
#include "WebPageManager.h" #include "WebPageManager.h"
#include "JsonSerializer.h"
#include "InvocationResult.h" #include "InvocationResult.h"
Node::Node(WebPageManager *manager, QStringList &arguments, QObject *parent) : JavascriptCommand(manager, arguments, parent) { Node::Node(WebPageManager *manager, QStringList &arguments, QObject *parent) : JavascriptCommand(manager, arguments, parent) {
@ -14,7 +15,14 @@ void Node::start() {
if (functionName == "focus_frame") { if (functionName == "focus_frame") {
page()->setCurrentFrameParent(page()->currentFrame()->parentFrame()); page()->setCurrentFrameParent(page()->currentFrame()->parentFrame());
} }
finish(&result);
if (result.hasError()) {
finish(&result);
} else {
JsonSerializer serializer;
InvocationResult jsonResult = InvocationResult(serializer.serialize(result.result()));
finish(&jsonResult);
}
} }
QString Node::toString() const { QString Node::toString() const {

View File

@ -85,22 +85,15 @@ Capybara = {
attribute: function (index, name) { attribute: function (index, name) {
var node = this.getNode(index); var node = this.getNode(index);
switch(name) { if (node.hasAttribute(name)) {
case 'checked':
return node.checked;
break;
case 'disabled':
return node.disabled;
break;
case 'multiple':
return node.multiple;
break;
default:
return node.getAttribute(name); return node.getAttribute(name);
} }
return void 0;
},
property: function (index, name) {
var node = this.getNode(index);
return node[name];
}, },
hasAttribute: function(index, name) { hasAttribute: function(index, name) {