diff --git a/lib/capybara/cuprite/browser.rb b/lib/capybara/cuprite/browser.rb index 192d312..533b680 100644 --- a/lib/capybara/cuprite/browser.rb +++ b/lib/capybara/cuprite/browser.rb @@ -192,6 +192,18 @@ def drag_by(node, dx, dy, steps, delay = nil, scroll = true) mouse.up end + def drop(node, *args) + if args[0].is_a?(String) + execute("_cuprite.attachDropInput()") + input = find(:css, "#_cuprite_drop_file").first + select_file(input, args) + evaluate_on(node: node, expression: "_cuprite.dropFile(this)") + else + strings = args.flat_map { |arg| arg.map { |type, data| { "type" => type, "data" => data } } } + evaluate_on(node: node, expression: "_cuprite.dropString(#{strings.to_json}, this)") + end + end + def select_file(node, value) node.select_file(value) end diff --git a/lib/capybara/cuprite/javascripts/index.js b/lib/capybara/cuprite/javascripts/index.js index 80865e4..7c3d3b8 100644 --- a/lib/capybara/cuprite/javascripts/index.js +++ b/lib/capybara/cuprite/javascripts/index.js @@ -556,6 +556,47 @@ class Cuprite { return true; } + // Ported from Capybara's Selenium html5_drag.rb (DROP_STRING). + dropString(strings, target) { + let dt = new DataTransfer(); + let opts = { cancelable: true, bubbles: true, dataTransfer: dt }; + for (let i = 0; i < strings.length; i++) { + if (dt.items) { + dt.items.add(strings[i]["data"], strings[i]["type"]); + } else { + dt.setData(strings[i]["type"], strings[i]["data"]); + } + } + target.dispatchEvent(new DragEvent("drop", opts)); + } + + // Ported from Capybara's Selenium html5_drag.rb (ATTACH_FILE). + attachDropInput() { + document.getElementById("_cuprite_drop_file")?.remove(); + let input = document.createElement("INPUT"); + input.type = "file"; + input.id = "_cuprite_drop_file"; + input.multiple = true; + document.body.appendChild(input); + } + + // Ported from Capybara's Selenium html5_drag.rb (DROP_FILE). + dropFile(target) { + let input = document.getElementById("_cuprite_drop_file"); + let files = input.files; + let dt = new DataTransfer(); + let opts = { cancelable: true, bubbles: true, dataTransfer: dt }; + input.parentElement.removeChild(input); + if (dt.items) { + for (let i = 0; i < files.length; i++) { + dt.items.add(files[i]); + } + } else { + Object.defineProperty(dt, "files", { value: files, writable: false }); + } + target.dispatchEvent(new DragEvent("drop", opts)); + } + // This command is purely for testing error handling browserError() { throw new Error("zomg"); diff --git a/lib/capybara/cuprite/node.rb b/lib/capybara/cuprite/node.rb index 62ef3f5..849bb2a 100644 --- a/lib/capybara/cuprite/node.rb +++ b/lib/capybara/cuprite/node.rb @@ -193,6 +193,8 @@ def drag_by(x, y, **options) command(:drag_by, x, y, options[:steps], options[:delay], options[:scroll]) end + def drop(...) = command(:drop, ...) + def trigger(event) command(:trigger, event) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 77572d1..208344c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -36,11 +36,6 @@ module TestSessions RSpec.configure do |config| config.define_derived_metadata do |metadata| regexes = <<~REGEXP.split("\n").map { |s| Regexp.quote(s.strip) }.join("|") - node Element#drop can drop a file - node Element#drop can drop multiple files - node Element#drop can drop strings - node Element#drop can drop multiple strings - node Element#drop can drop a pathname node #set should submit single text input forms if ended with #has_field with valid should be false if field is invalid #has_element? should be true if the given element is on the page