Merge pull request #1036 from twalpole/webdriver_spec_select_events

Make select elements generate the events specified by WebDriver spec
This commit is contained in:
Thomas Walpole 2017-11-06 10:05:25 -08:00 committed by GitHub
commit 3777152c9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 30 deletions

View File

@ -1619,35 +1619,49 @@ describe Capybara::Webkit::Driver do
<textarea class="watch"></textarea> <textarea class="watch"></textarea>
<input class="watch" type="checkbox"/> <input class="watch" type="checkbox"/>
<input class="watch" type="radio"/> <input class="watch" type="radio"/>
<select id="single" class="watch">
<option>Single Option 1</option>
<option>Single Option 2</option>
</select>
<select id="multiple" class="watch" multiple="multiple">
<option class="watch" selected="selected">Multiple Option 1</option>
<option class="watch" selected="selected">Multiple Option 2</option>
<option class="watch">Multiple Option 3</option>
<optgroup>
<option class="watch">Multiple Option 4</option>
</optgroup>
</select>
</form> </form>
<ul id="events"></ul> <ul id="events"></ul>
<script type="text/javascript"> <script type="text/javascript">
var events = document.getElementById("events"); var events = document.getElementById("events");
var recordEvent = function (event) { var recordEvent = function (event) {
var element = document.createElement("li"); var element = document.createElement("li");
element.innerHTML = event.type; var event_description = "";
if (event.target.id)
event_description += event.target.id + '.';
event_description += event.type;
element.innerHTML = event_description;
events.appendChild(element); events.appendChild(element);
}; };
var elements = document.getElementsByClassName("watch"); var elements = document.getElementsByClassName("watch");
var watched_events = ["focus", "keydown", "keypress", "keyup", "input", "change",
"blur", "mousedown", "mouseup", "click"];
for (var i = 0; i < elements.length; i++) { for (var i = 0; i < elements.length; i++) {
var element = elements[i]; for (var j = 0; j < watched_events.length; j++) {
element.addEventListener("focus", recordEvent); elements[i].addEventListener(watched_events[j], recordEvent);
element.addEventListener("keydown", recordEvent); }
element.addEventListener("keypress", recordEvent);
element.addEventListener("keyup", recordEvent);
element.addEventListener("input", recordEvent);
element.addEventListener("change", recordEvent);
element.addEventListener("blur", recordEvent);
element.addEventListener("mousedown", recordEvent);
element.addEventListener("mouseup", recordEvent);
element.addEventListener("click", recordEvent);
} }
</script> </script>
</body></html> </body></html>
HTML HTML
end end
def logged_events
driver.find_xpath("//li").map(&:visible_text)
end
before { visit("/") } before { visit("/") }
let(:newtext) { '12345' } let(:newtext) { '12345' }
@ -1664,29 +1678,49 @@ describe Capybara::Webkit::Driver do
it "triggers text input events on inputs of type #{field_type}" do it "triggers text input events on inputs of type #{field_type}" do
driver.find_xpath("//input[@type='#{field_type}']").first.set(newtext) driver.find_xpath("//input[@type='#{field_type}']").first.set(newtext)
driver.find_xpath("//body").first.click driver.find_xpath("//body").first.click
expect(driver.find_xpath("//li").map(&:visible_text)).to eq textevents expect(logged_events).to eq textevents
end end
end end
it "triggers events for cleared inputs" do it "triggers events for cleared inputs" do
driver.find_xpath("//input[@type='text']").first.set('') driver.find_xpath("//input[@type='text']").first.set('')
driver.find_xpath("//body").first.click driver.find_xpath("//body").first.click
expect(driver.find_xpath("//li").map(&:visible_text)).to include('change') expect(logged_events).to include("change")
end end
it "triggers textarea input events" do it "triggers textarea input events" do
driver.find_xpath("//textarea").first.set(newtext) driver.find_xpath("//textarea").first.set(newtext)
expect(driver.find_xpath("//li").map(&:visible_text)).to eq keyevents expect(logged_events).to eq keyevents
end end
it "triggers radio input events" do it "triggers radio input events" do
driver.find_xpath("//input[@type='radio']").first.set(true) driver.find_xpath("//input[@type='radio']").first.set(true)
expect(driver.find_xpath("//li").map(&:visible_text)).to eq %w(mousedown focus mouseup change click) expect(logged_events).to eq %w(mousedown focus mouseup change click)
end end
it "triggers checkbox events" do it "triggers checkbox events" do
driver.find_xpath("//input[@type='checkbox']").first.set(true) driver.find_xpath("//input[@type='checkbox']").first.set(true)
expect(driver.find_xpath("//li").map(&:visible_text)).to eq %w(mousedown focus mouseup change click) expect(logged_events).to eq %w(mousedown focus mouseup change click)
end
it "triggers select events" do
driver.find_xpath("//option[text() = 'Single Option 2']").first.select_option
expect(logged_events).to eq %w[single.mousedown single.focus single.input single.change single.mouseup single.click]
end
it "triggers correct unselect events for multiple selects" do
driver.find_xpath("//option[text() = 'Multiple Option 2']").first.unselect_option
expect(logged_events).to eq %w[multiple.mousedown multiple.focus multiple.input multiple.change multiple.mouseup multiple.click]
end
it "triggers correct unselect events for multiple selects when already unselected" do
driver.find_xpath("//option[text() = 'Multiple Option 3']").first.unselect_option
expect(logged_events).to eq %w[multiple.mousedown multiple.focus multiple.input multiple.mouseup multiple.click]
end
it "triggers correct select events for multiple selects when additional option is selected" do
driver.find_xpath("//option[text() = 'Multiple Option 4']").first.select_option
expect(logged_events).to eq %w[multiple.mousedown multiple.focus multiple.input multiple.change multiple.mouseup multiple.click]
end end
end end

View File

@ -391,7 +391,15 @@ Capybara = {
elem.focus(); elem.focus();
}, },
selectOption: function(index) { selectOption: function(index){
this._setOption(index, true);
},
unselectOption: function(index){
this._setOption(index, false);
},
_setOption: function(index, state) {
var optionNode = this.getNode(index); var optionNode = this.getNode(index);
var selectNode = optionNode.parentNode; var selectNode = optionNode.parentNode;
if (selectNode.tagName == "OPTGROUP") if (selectNode.tagName == "OPTGROUP")
@ -400,23 +408,22 @@ Capybara = {
if (optionNode.disabled) if (optionNode.disabled)
return; return;
if ((!selectNode.multiple) && (!state))
return;
// click on select list // click on select list
this.triggerOnNode(selectNode, 'mousedown'); this.triggerOnNode(selectNode, 'mousedown');
selectNode.focus(); selectNode.focus();
this.triggerOnNode(selectNode, 'input');
// select/deselect option from list
if (optionNode.selected != state){
optionNode.selected = state;
this.triggerOnNode(selectNode, 'change');
}
this.triggerOnNode(selectNode, 'mouseup'); this.triggerOnNode(selectNode, 'mouseup');
this.triggerOnNode(selectNode, 'click'); this.triggerOnNode(selectNode, 'click');
// select option from list
this.triggerOnNode(optionNode, 'mousedown');
optionNode.selected = true;
this.triggerOnNode(selectNode, 'change');
this.triggerOnNode(optionNode, 'mouseup');
this.triggerOnNode(optionNode, 'click');
},
unselectOption: function(index) {
this.getNode(index).selected = false;
this.trigger(index, "change");
}, },
centerPosition: function(element) { centerPosition: function(element) {