Fix focus/blur event compatibility with Selenium while filling out forms
This commit is contained in:
parent
d8020ce3a4
commit
ba28a2a20a
|
@ -690,7 +690,7 @@ describe Capybara::Webkit::Driver do
|
|||
let(:keyevents) do
|
||||
(%w{focus} +
|
||||
newtext.length.times.collect { %w{keydown keypress keyup input} } +
|
||||
%w{change blur}).flatten
|
||||
%w{change}).flatten
|
||||
end
|
||||
|
||||
%w(email number password search tel text url).each do | field_type |
|
||||
|
@ -707,12 +707,12 @@ describe Capybara::Webkit::Driver do
|
|||
|
||||
it "triggers radio input events" do
|
||||
driver.find("//input[@type='radio']").first.set(true)
|
||||
driver.find("//li").map(&:text).should == %w(mousedown mouseup change click)
|
||||
driver.find("//li").map(&:text).should == %w(mousedown focus mouseup change click)
|
||||
end
|
||||
|
||||
it "triggers checkbox events" do
|
||||
driver.find("//input[@type='checkbox']").first.set(true)
|
||||
driver.find("//li").map(&:text).should == %w(mousedown mouseup change click)
|
||||
driver.find("//li").map(&:text).should == %w(mousedown focus mouseup change click)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Capybara::Webkit, 'compatibility with selenium' do
|
||||
include AppRunner
|
||||
|
||||
it 'generates the same events as selenium when filling out forms' do
|
||||
run_application_for_html(<<-HTML)
|
||||
<html><body>
|
||||
<form onsubmit="return false">
|
||||
<label for="one">One</label><input type="text" name="one" id="one" />
|
||||
<label for="two">Two</label><input type="text" name="two" id="two" />
|
||||
<input type="submit" value="Submit" id="submit" />
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
window.log = [];
|
||||
var recordEvent = function (event) {
|
||||
log.push(event.target.id + '.' + event.type);
|
||||
};
|
||||
var elements = document.getElementsByTagName("input");
|
||||
var events = ["mousedown", "mouseup", "click", "keyup", "keydown",
|
||||
"keypress", "focus", "blur"];
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
elements[i].addEventListener(events[j], recordEvent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body></html>
|
||||
HTML
|
||||
|
||||
compare_events_for_drivers(:reusable_webkit, :selenium) do
|
||||
visit "/"
|
||||
fill_in "One", :with => "some value"
|
||||
fill_in "Two", :with => "other value"
|
||||
click_button "Submit"
|
||||
end
|
||||
end
|
||||
|
||||
def compare_events_for_drivers(first, second, &block)
|
||||
events_for_driver(first, &block).should == events_for_driver(second, &block)
|
||||
end
|
||||
|
||||
def events_for_driver(name, &block)
|
||||
session = Capybara::Session.new(name, AppRunner.app)
|
||||
session.instance_eval(&block)
|
||||
session.evaluate_script("window.log")
|
||||
end
|
||||
end
|
|
@ -32,13 +32,16 @@ module AppRunner
|
|||
end
|
||||
|
||||
def driver_for_html(html)
|
||||
app = lambda do |env|
|
||||
[200, { 'Content-Type' => 'text/html', 'Content-Length' => html.size.to_s }, [html]]
|
||||
end
|
||||
run_application app
|
||||
run_application_for_html html
|
||||
build_driver
|
||||
end
|
||||
|
||||
def run_application_for_html(html)
|
||||
run_application lambda { |env|
|
||||
[200, { 'Content-Type' => 'text/html', 'Content-Length' => html.size.to_s }, [html]]
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_driver
|
||||
|
|
|
@ -110,6 +110,7 @@ Capybara = {
|
|||
|
||||
click: function (index) {
|
||||
this.mousedown(index);
|
||||
this.focus(index);
|
||||
this.mouseup(index);
|
||||
var clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
|
@ -214,7 +215,7 @@ Capybara = {
|
|||
textTypes = ["email", "number", "password", "search", "tel", "text", "textarea", "url"];
|
||||
|
||||
if (textTypes.indexOf(type) != -1) {
|
||||
this.trigger(index, "focus");
|
||||
this.focus(index);
|
||||
|
||||
maxLength = this.attribute(index, "maxlength");
|
||||
if (maxLength && value.length > maxLength) {
|
||||
|
@ -233,22 +234,28 @@ Capybara = {
|
|||
this.trigger(index, "input");
|
||||
}
|
||||
this.trigger(index, "change");
|
||||
this.trigger(index, "blur");
|
||||
|
||||
} else if (type === "checkbox" || type === "radio") {
|
||||
if (node.checked != (value === "true")) {
|
||||
this.click(index)
|
||||
this.click(index);
|
||||
}
|
||||
|
||||
} else if (type === "file") {
|
||||
this.lastAttachedFile = value;
|
||||
this.click(index)
|
||||
this.click(index);
|
||||
|
||||
} else {
|
||||
node.value = value;
|
||||
}
|
||||
},
|
||||
|
||||
focus: function(index) {
|
||||
if (this.focusedIndex)
|
||||
this.trigger(this.focusedIndex, "blur");
|
||||
this.focusedIndex = index;
|
||||
this.trigger(index, "focus");
|
||||
},
|
||||
|
||||
selectOption: function(index) {
|
||||
this.nodes[index].selected = true;
|
||||
this.trigger(index, "change");
|
||||
|
@ -270,7 +277,8 @@ Capybara = {
|
|||
position.x += element.offsetLeft;
|
||||
position.y += element.offsetTop;
|
||||
} while ((element = element.offsetParent));
|
||||
position.x = Math.floor(position.x), position.y = Math.floor(position.y);
|
||||
position.x = Math.floor(position.x);
|
||||
position.y = Math.floor(position.y);
|
||||
|
||||
return position;
|
||||
},
|
||||
|
@ -282,7 +290,9 @@ Capybara = {
|
|||
oldStyle[prop] = element.style[prop];
|
||||
element.style[prop] = newStyle[prop];
|
||||
}
|
||||
element.offsetWidth, element.offsetHeight; // force reflow
|
||||
// force reflow
|
||||
element.offsetWidth;
|
||||
element.offsetHeight;
|
||||
for (prop in oldStyle)
|
||||
element.style[prop] = oldStyle[prop];
|
||||
}
|
||||
|
@ -299,12 +309,14 @@ Capybara = {
|
|||
var eventObject = document.createEvent("MouseEvents");
|
||||
eventObject.initMouseEvent(eventName, true, true, window, 0, 0, 0, options.clientX || 0, options.clientY || 0, false, false, false, false, 0, null);
|
||||
element.dispatchEvent(eventObject);
|
||||
}
|
||||
};
|
||||
mouseTrigger('mousedown', options);
|
||||
options.clientX += 1, options.clientY += 1;
|
||||
options.clientX += 1;
|
||||
options.clientY += 1;
|
||||
mouseTrigger('mousemove', options);
|
||||
|
||||
position = this.centerPostion(target), options = {
|
||||
position = this.centerPostion(target);
|
||||
options = {
|
||||
clientX: position.x,
|
||||
clientY: position.y
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue