Fix focus/blur event compatibility with Selenium while filling out forms

This commit is contained in:
Joe Ferris 2012-07-09 17:34:09 -07:00
parent d8020ce3a4
commit ba28a2a20a
4 changed files with 79 additions and 16 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
};