Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rb] implement navigation commands with BiDi #14094

Merged
merged 8 commits into from
Nov 20, 2024
110 changes: 61 additions & 49 deletions rb/lib/selenium/webdriver/bidi/browsing_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,72 +17,84 @@
# specific language governing permissions and limitations
# under the License.

require_relative 'navigate_result'
require_relative 'browsing_context_info'

module Selenium
module WebDriver
class BiDi
# Implements the browsingContext Module of the WebDriver-BiDi specification
#
# @api private
#
class BrowsingContext
attr_accessor :id

READINESS_STATE = {
none: 'none',
interactive: 'interactive',
complete: 'complete'
'none' => 'none',
'eager' => 'interactive',
'normal' => 'complete'
}.freeze

def initialize(driver:, browsing_context_id: nil, type: nil, reference_context: nil)
unless driver.capabilities.web_socket_url
raise Error::WebDriverError,
'WebDriver instance must support BiDi protocol'
end

unless type.nil? || %i[window tab].include?(type)
raise ArgumentError,
"Valid types are :window & :tab. Received: #{type.inspect}"
end

@bidi = driver.bidi
@id = browsing_context_id.nil? ? create(type, reference_context)['context'] : browsing_context_id
# TODO: store current window handle in bridge object instead of always calling it
def initialize(bridge)
@bridge = bridge
@bidi = @bridge.bidi
page_load_strategy = bridge.capabilities[:page_load_strategy]
@readiness = READINESS_STATE[page_load_strategy]
end

def navigate(url:, readiness_state: nil)
unless readiness_state.nil? || READINESS_STATE.key?(readiness_state)
raise ArgumentError,
"Valid readiness states are :none, :interactive & :complete. Received: #{readiness_state.inspect}"
end

navigate_result = @bidi.send_cmd('browsingContext.navigate', context: @id, url: url,
wait: READINESS_STATE[readiness_state])

NavigateResult.new(
url: navigate_result['url'],
navigation_id: navigate_result['navigation']
)
# Navigates to the specified URL in the given browsing context.
#
# @param url [String] The URL to navigate to.
# @param context_id [String, NilClass] The ID of the browsing context to navigate in.
# Defaults to the window handle of the current context.
def navigate(url, context_id: nil)
context_id ||= @bridge.window_handle
@bidi.send_cmd('browsingContext.navigate', context: context_id, url: url, wait: @readiness)
end

def get_tree(max_depth: nil)
result = @bidi.send_cmd('browsingContext.getTree', root: @id, maxDepth: max_depth).dig('contexts', 0)

BrowsingContextInfo.new(
id: result['context'],
url: result['url'],
children: result['children'],
parent_context: result['parent']
)
# Traverses the browsing context history by a given delta.
#
# @param delta [Integer] The number of steps to traverse.
# Positive values go forwards, negative values go backwards.
# @param context_id [String, NilClass] The ID of the context to traverse.
# Defaults to the window handle of the current context.
def traverse_history(delta, context_id: nil)
context_id ||= @bridge.window_handle
@bidi.send_cmd('browsingContext.traverseHistory', context: context_id, delta: delta)
end

def close
@bidi.send_cmd('browsingContext.close', context: @id)
# Reloads the browsing context.
# @param [String, NilClass] context_id The ID of the context to reload.
# Defaults to the window handle of the current context.
# @param [Boolean] ignore_cache Whether to bypass the cache when reloading.
# Defaults to false.
def reload(context_id: nil, ignore_cache: false)
context_id ||= @bridge.window_handle
params = {context: context_id, ignore_cache: ignore_cache, wait: @readiness}
@bidi.send_cmd('browsingContext.reload', **params)
end

private
# Closes the browsing context.
#
# @param [String] context_id The ID of the context to close.
# Defaults to the window handle of the current context.
def close(context_id: nil)
context_id ||= @bridge.window_handle
@bidi.send_cmd('browsingContext.close', context: context_id)
end

def create(type, reference_context)
@bidi.send_cmd('browsingContext.create', type: type.to_s, referenceContext: reference_context)
# Create a new browsing context.
#
# @param [Symbol] type The type of browsing context to create.
# Valid options are :tab and :window with :window being the default
# @param [String] context_id The reference context for the new browsing context.
# Defaults to the current window handle.
#
# @return [String] The context ID of the created browsing context.
def create(type: nil, context_id: nil)
type ||= :window
context_id ||= @bridge.window_handle
result = @bidi.send_cmd('browsingContext.create', type: type.to_s, referenceContext: context_id)
result['context']
end
end # BrowsingContext
end
end # BiDi
end # WebDriver
end # Selenium
35 changes: 0 additions & 35 deletions rb/lib/selenium/webdriver/bidi/browsing_context_info.rb

This file was deleted.

33 changes: 0 additions & 33 deletions rb/lib/selenium/webdriver/bidi/navigate_result.rb

This file was deleted.

22 changes: 22 additions & 0 deletions rb/lib/selenium/webdriver/remote/bidi_bridge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ def create_session(capabilities)
@bidi = Selenium::WebDriver::BiDi.new(url: socket_url)
end

def get(url)
browsing_context.navigate(url)
end

def go_back
browsing_context.traverse_history(-1)
end

def go_forward
browsing_context.traverse_history(1)
end

def refresh
browsing_context.reload
end

def quit
super
ensure
Expand All @@ -38,6 +54,12 @@ def quit
def close
execute(:close_window).tap { |handles| bidi.close if handles.empty? }
end

private

def browsing_context
@browsing_context ||= WebDriver::BiDi::BrowsingContext.new(self)
end
end # BiDiBridge
end # Remote
end # WebDriver
Expand Down
20 changes: 8 additions & 12 deletions rb/sig/lib/selenium/webdriver/bidi/browsing_context.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,21 @@ module Selenium
module WebDriver
class BiDi
class BrowsingContext
@bidi: untyped
@bidi: BiDi

@id: untyped
READINESS_STATE: Hash[String, String]

attr_accessor id: untyped
def initialize: (Remote::Bridge bridge) -> void

READINESS_STATE: Hash[Symbol, String]
def navigate: (String url, String? context_id) -> void

def initialize: (driver: untyped, ?browsing_context_id: untyped?, ?type: untyped?, ?reference_context: untyped?) -> void
def traverse_history: (Integer delta, String? context_id) -> void

def navigate: (url: untyped, ?readiness_state: untyped?) -> untyped
def reload: (String? context_id, ?ignore_cache: bool) -> void

def get_tree: (?max_depth: untyped?) -> untyped
def close: (String? context_id) -> void

def close: () -> untyped

private

def create: (untyped type, untyped reference_context) -> untyped
def create: (?type: Symbol | String | nil, ?context_id: String | nil) -> String
end
end
end
Expand Down
24 changes: 18 additions & 6 deletions rb/sig/lib/selenium/webdriver/remote/bidi_bridge.rbs
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
module Selenium
module WebDriver
module Remote
class BiDiBridge < Bridge
@bidi: untyped
class BiDiBridge
@browsing_context: BiDi::BrowsingContext

attr_reader bidi: untyped
attr_reader bidi: BiDi

def create_session: (Hash[Symbol, String] capabilities) -> BiDi
def create_session: (untyped capabilities) -> void

def quit: () -> nil
def get: (String url) -> void

def close: () -> untyped
def go_back: () -> void

def go_forward: () -> void

def refresh: () -> void

def quit: () -> void

def close: () -> void

private

def browsing_context: () -> BiDi::BrowsingContext
end
end
end
Expand Down
Loading
Loading