1
0
Fork 0
mirror of https://github.com/teamcapybara/capybara.git synced 2022-11-09 12:08:07 -05:00

Merge pull request #1722 from jnicklas/frame_api

new frame api for drivers
This commit is contained in:
Thomas Walpole 2016-07-18 11:36:43 -07:00 committed by GitHub
commit d690c8815e
5 changed files with 67 additions and 32 deletions

View file

@ -11,6 +11,7 @@ Release date: Unreleased
* Raise error if Capybara.app_host/default_host are specified incorrectly [Thomas Walpole] * Raise error if Capybara.app_host/default_host are specified incorrectly [Thomas Walpole]
* Capybara::Selector::FilterSet allows for sharing filter definitions between selectors [Thomas Walpole] * Capybara::Selector::FilterSet allows for sharing filter definitions between selectors [Thomas Walpole]
* Remove need to pass nil locator in most node actions when locator is not needed [Thomas Walpole] * Remove need to pass nil locator in most node actions when locator is not needed [Thomas Walpole]
* New frames API for drivers - Issue #1365 [Thomas Walpole]
#Version 2.7.1 #Version 2.7.1
Release date: 2016-05-01 Release date: 2016-05-01

View file

@ -48,8 +48,12 @@ class Capybara::Driver::Base
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#status_code' raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#status_code'
end end
def within_frame(frame_handle) ##
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_frame' #
# @param frame [Capybara::Node::Element, :parent, :top] The iframe element to switch to
#
def switch_to_frame(frame)
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#switch_to_frame'
end end
def current_window_handle def current_window_handle

View file

@ -131,29 +131,22 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
end end
end end
## def switch_to_frame(frame)
# case frame
# Webdriver supports frame name, id, index(zero-based) or {Capybara::Node::Element} to find iframe when :top
# @frame_handles[browser.window_handle] = []
# @overload within_frame(index) browser.switch_to.default_content
# @param [Integer] index index of a frame when :parent
# @overload within_frame(name_or_id) # would love to use browser.switch_to.parent_frame here
# @param [String] name_or_id name or id of a frame # but it has an issue if the current frame is removed from within it
# @overload within_frame(element) @frame_handles[browser.window_handle].pop
# @param [Capybara::Node::Base] a_node frame element browser.switch_to.default_content
# @frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
def within_frame(frame_handle) else
frame_handle = frame_handle.native if frame_handle.is_a?(Capybara::Node::Base) @frame_handles[browser.window_handle] ||= []
@frame_handles[browser.window_handle] ||= [] @frame_handles[browser.window_handle] << frame.native
@frame_handles[browser.window_handle] << frame_handle browser.switch_to.frame(frame.native)
browser.switch_to.frame(frame_handle) end
yield
ensure
# would love to use browser.switch_to.parent_frame here
# but it has an issue if the current frame is removed from within it
@frame_handles[browser.window_handle].pop
browser.switch_to.default_content
@frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
end end
def current_window_handle def current_window_handle

View file

@ -327,18 +327,48 @@ module Capybara
## ##
# #
# Execute the given block within the given iframe using given frame name or index. # Execute the given block within the given iframe using given frame, frame name/id or index.
# May be supported by not all drivers. Drivers that support it, may provide additional options. # May not be supported by all drivers.
# #
# @overload within_frame(element)
# @param [Capybara::Node::Element] frame element
# @overload within_frame(name)
# @param [String] name name/id of a frame
# @overload within_frame(index) # @overload within_frame(index)
# @param [Integer] index index of a frame # @param [Integer] index index of a frame
# @overload within_frame(name)
# @param [String] name name of a frame
# #
def within_frame(frame_handle) def within_frame(locator)
scopes.push(nil) scopes.push(nil)
driver.within_frame(frame_handle) do
yield #support older driver frame api for now
frame = case locator
when Capybara::Node::Element
locator
when String
find(:xpath, XPath.descendant(:iframe)[XPath.attr(:id).equals(locator) | XPath.attr(:name).equals(locator)].to_xpath(:exact))
when Integer
all(:css, 'iframe', minimum: locator+1)[locator]
else
raise ArgumentError
end
begin
driver.switch_to_frame(frame)
begin
yield
ensure
driver.switch_to_frame(:parent)
end
rescue Capybara::NotSupportedByDriverError
# Support older driver frame API for now
if driver.respond_to?(:within_frame)
warn "Your driver (#{driver.class.name}) is using an older version of Capybara's frame API - please update your driver"
driver.within_frame(frame) do
yield
end
else
raise
end
end end
ensure ensure
scopes.pop scopes.pop

View file

@ -9,32 +9,38 @@ Capybara::SpecHelper.spec '#within_frame', :requires => [:frames] do
expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne' expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
end end
end end
it "should find the div in FrameTwo" do it "should find the div in FrameTwo" do
@session.within_frame("frameTwo") do @session.within_frame("frameTwo") do
expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo' expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo'
end end
end end
it "should find the text div in the main window after finding text in frameOne" do it "should find the text div in the main window after finding text in frameOne" do
@session.within_frame("frameOne") do @session.within_frame("frameOne") do
expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne' expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
end end
expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow' expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow'
end end
it "should find the text div in the main window after finding text in frameTwo" do it "should find the text div in the main window after finding text in frameTwo" do
@session.within_frame("frameTwo") do @session.within_frame("frameTwo") do
expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo' expect(@session.find("//*[@id='divInFrameTwo']").text).to eql 'This is the text of divInFrameTwo'
end end
expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow' expect(@session.find("//*[@id='divInMainWindow']").text).to eql 'This is the text for divInMainWindow'
end end
it "should return the result of executing the block" do it "should return the result of executing the block" do
expect(@session.within_frame("frameOne") { "return value" }).to eql "return value" expect(@session.within_frame("frameOne") { "return value" }).to eql "return value"
end end
it "should find the div given Element" do it "should find the div given Element" do
element = @session.find(:id, 'frameOne') element = @session.find(:id, 'frameOne')
@session.within_frame element do @session.within_frame element do
expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne' expect(@session.find("//*[@id='divInFrameOne']").text).to eql 'This is the text of divInFrameOne'
end end
end end
it "should find multiple nested frames" do it "should find multiple nested frames" do
@session.within_frame 'parentFrame' do @session.within_frame 'parentFrame' do
@session.within_frame 'childFrame' do @session.within_frame 'childFrame' do
@ -43,6 +49,7 @@ Capybara::SpecHelper.spec '#within_frame', :requires => [:frames] do
end end
end end
end end
it "should reset scope when changing frames" do it "should reset scope when changing frames" do
@session.within(:css, '#divInMainWindow') do @session.within(:css, '#divInMainWindow') do
@session.within_frame 'parentFrame' do @session.within_frame 'parentFrame' do