Add execute/evaluate_script as Element methods

This commit is contained in:
Thomas Walpole 2018-05-18 14:13:53 -07:00
parent a16defe121
commit a5b757d6d9
3 changed files with 81 additions and 0 deletions

View File

@ -1,9 +1,14 @@
# Version 3.2.0
Release date: unreleased
### Changed
* Ruby 2.3.0+ is now required
### Added
* New global configuration `default_set_options` used in `Capybara::Node::Element#set` as default `options` hash [Champier Cyril]
* `execute_javascript' and `evaluate_javascript` can now be called on elements to run the JS in the context of the element [Thomas Walpole]
# Version 3.1.0
Release date: 2018-05-10

View File

@ -347,6 +347,40 @@ module Capybara
self
end
##
#
# Execute the given JS in the context of the element not returning a result. This is useful for scripts that return
# complex objects, such as jQuery statements. +execute_script+ should be used over
# +evaluate_script+ whenever possible. `this` in the script will refer to the element this is called on.
#
# @param [String] script A string of JavaScript to execute
# @param args Optional arguments that will be passed to the script. Driver support for this is optional and types of objects supported may differ between drivers
#
def execute_script(script, *args)
session.execute_script(<<~JS, self, *args)
(function (){
#{script}
}).apply(arguments[0], Array.prototype.slice.call(arguments,1));
JS
end
##
#
# Evaluate the given JS in the context of the element and return the result. Be careful when using this with
# scripts that return complex objects, such as jQuery statements. +execute_script+ might
# be a better alternative. `this` in the script will refer to the element this is called on.
#
# @param [String] script A string of JavaScript to evaluate
# @return [Object] The result of the evaluated JavaScript (may be driver specific)
#
def evaluate_script(script, *args)
session.evaluate_script(<<~JS, self, *args)
(function(){
return #{script}
}).apply(arguments[0], Array.prototype.slice.call(arguments,1));
JS
end
def reload
if @allow_reload
begin

View File

@ -455,6 +455,48 @@ Capybara::SpecHelper.spec "node" do
end
end
describe "#execute_script", requires: %i[js es_args] do
it "should execute the given script in the context of the element and return nothing" do
@session.visit('/with_js')
expect(@session.find(:css, '#change').execute_script("this.textContent = 'Funky Doodle'")).to be_nil
expect(@session).to have_css('#change', text: 'Funky Doodle')
end
it "should pass arguments to the script" do
@session.visit('/with_js')
@session.find(:css, '#change').execute_script("this.textContent = arguments[0]", "Doodle Funk")
expect(@session).to have_css('#change', text: 'Doodle Funk')
end
end
describe "#evaluate_script", requires: %i[js es_args] do
it "should evaluate the given script in the context of the element and return whatever it produces" do
@session.visit('/with_js')
el = @session.find(:css, '#with_change_event')
expect(el.evaluate_script("this.value")).to eq('default value')
end
it "should pass arguments to the script" do
@session.visit('/with_js')
@session.find(:css, '#change').evaluate_script("this.textContent = arguments[0]", "Doodle Funk")
expect(@session).to have_css('#change', text: 'Doodle Funk')
end
it "should pass multiple arguments" do
@session.visit('/with_js')
change = @session.find(:css, '#change')
expect(change.evaluate_script("arguments[0] + arguments[1]", 2, 3)).to eq 5
end
it "should support returning elements" do
@session.visit('/with_js')
change = @session.find(:css, '#change') # ensure page has loaded and element is available
el = change.evaluate_script("this")
expect(el).to be_instance_of(Capybara::Node::Element)
expect(el).to eq(change)
end
end
describe '#reload', requires: [:js] do
context "without automatic reload" do
before { Capybara.automatic_reload = false }