From 7ef9d83c1b5e789f8af9881c0f0a9770c0445669 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 14 Dec 2024 15:22:28 +0100 Subject: [PATCH 01/35] Add response handler --- rb/lib/selenium/webdriver/bidi/network.rb | 12 +++++++ rb/lib/selenium/webdriver/common/network.rb | 32 +++++++++++++------ .../lib/selenium/webdriver/bidi/network.rbs | 4 ++- .../lib/selenium/webdriver/common/network.rbs | 2 ++ .../selenium/webdriver/bidi/network_spec.rb | 15 ++++++++- .../selenium/webdriver/network_spec.rb | 27 ++++++++++++++++ 6 files changed, 80 insertions(+), 12 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index ae55f9200efe4..73000d749ee90 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -72,6 +72,18 @@ def continue_with_request(**args) ) end + def continue_with_response(**args) + @bidi.send_cmd( + 'network.continueWithResponse', + response: args[:response_id], + 'body' => args[:body], + 'cookies' => args[:cookies], + 'credentials' => args[:credentials], + 'headers' => args[:headers], + 'status' => args[:status] + ) + end + def on(event, &) event = EVENTS[event] if event.is_a?(Symbol) @bidi.add_callback(event, &) diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 91bc0525c8340..0a60c3d16f98a 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -27,6 +27,16 @@ def initialize(bridge) @callbacks = {} end + def remove_handler(id) + intercept = @callbacks[id] + @network.remove_intercept(intercept['intercept']) + @callbacks.delete(id) + end + + def clear_handlers + @callbacks.each_key { |id| remove_handler(id) } + end + def add_authentication_handler(username, password) intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:auth_required]]) auth_id = @network.on(:auth_required) do |event| @@ -38,16 +48,6 @@ def add_authentication_handler(username, password) auth_id end - def remove_handler(id) - intercept = @callbacks[id] - @network.remove_intercept(intercept['intercept']) - @callbacks.delete(id) - end - - def clear_handlers - @callbacks.each_key { |id| remove_handler(id) } - end - def add_request_handler intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:before_request]]) request_id = @network.on(:before_request) do |event| @@ -59,6 +59,18 @@ def add_request_handler request_id end + + def add_response_handler + intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:response_started]]) + response_id = @network.on(:response_started) do |event| + request_id = event['requestId'] + @network.continue_with_response(request_id: request_id) + end + + @callbacks[response_id] = intercept + + response_id + end end # Network end # WebDriver end # Selenium diff --git a/rb/sig/lib/selenium/webdriver/bidi/network.rbs b/rb/sig/lib/selenium/webdriver/bidi/network.rbs index 44645cf05d250..7d2524f039fb6 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network.rbs @@ -12,7 +12,9 @@ module Selenium def add_intercept: (?phases: Array[String], ?contexts: BrowsingContext?, ?url_patterns: untyped?) -> Hash[String, String] - def continue_with_request: -> untyped + def continue_with_request: (**untyped args) -> untyped + + def continue_with_response: (**untyped args) -> untyped def remove_intercept: (String intercept) -> untyped diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index 2ad03a748167e..4d89e797a4d3a 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -13,6 +13,8 @@ module Selenium def add_request_handler: -> Integer + def add_response_handler: -> String + def clear_handlers: -> Hash[nil, nil] def remove_handler: (Integer id) -> nil diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index 80aad4de78e31..6c6e7ec97c216 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -17,7 +17,6 @@ # specific language governing permissions and limitations # under the License. - require_relative '../spec_helper' module Selenium @@ -70,6 +69,20 @@ class BiDi expect(driver.find_element(name: 'login')).to be_displayed end end + + it 'continues with response' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + network.add_intercept(phases: [described_class::PHASES[:response_started]]) + network.on(:response_started) do |event| + request_id = event['requestId'] + network.continue_with_response(request_id: request_id) + end + + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + end + end end end end diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 2ad4bc9f5365c..78f7a41b951de 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -79,6 +79,33 @@ module WebDriver expect(network.callbacks.count).to be 0 end end + + it 'adds a response handler' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler + expect(network.callbacks.count).to be 1 + end + end + + it 'removes a response handler' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + id = network.add_response_handler + network.remove_handler(id) + expect(network.callbacks.count).to be 0 + end + end + + it 'clears all response handlers' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler + network.add_response_handler + network.clear_handlers + expect(network.callbacks.count).to be 0 + end + end end end end From 2f2012ab93c5c86bc3f60ce84a15d32009033193 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 16:05:08 +0100 Subject: [PATCH 02/35] Update auth handlers and improve the :on method --- rb/lib/selenium/webdriver/bidi/network.rb | 29 +++++--------- rb/lib/selenium/webdriver/common/network.rb | 40 +++++++++---------- .../selenium/webdriver/bidi/network_spec.rb | 9 ++++- .../selenium/webdriver/network_spec.rb | 2 + 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index 73000d749ee90..d3530653445fb 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -60,33 +60,26 @@ def continue_with_auth(request_id, username, password) ) end - def continue_with_request(**args) + def continue_with_auth_no_credentials(request_id) @bidi.send_cmd( - 'network.continueWithRequest', - request: args[:request_id], - 'body' => args[:body], - 'cookies' => args[:cookies], - 'headers' => args[:headers], - 'method' => args[:method], - 'url' => args[:url] + 'network.continueWithAuth', + 'request' => request_id, + 'action' => 'default' ) end - def continue_with_response(**args) + def cancel_auth(request_id) @bidi.send_cmd( - 'network.continueWithResponse', - response: args[:response_id], - 'body' => args[:body], - 'cookies' => args[:cookies], - 'credentials' => args[:credentials], - 'headers' => args[:headers], - 'status' => args[:status] + 'network.continueWithAuth', + 'request' => request_id, + 'action' => 'cancel' ) end - def on(event, &) + def on(event, &block) event = EVENTS[event] if event.is_a?(Symbol) - @bidi.add_callback(event, &) + @bidi.add_callback(event, &block) + @bidi.session.subscribe(event) end end # Network end # BiDi diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 0a60c3d16f98a..5eb542bb6e1e0 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -20,7 +20,7 @@ module Selenium module WebDriver class Network - attr_reader :callbacks + attr_reader :callbacks, :network def initialize(bridge) @network = BiDi::Network.new(bridge.bidi) @@ -28,46 +28,46 @@ def initialize(bridge) end def remove_handler(id) - intercept = @callbacks[id] - @network.remove_intercept(intercept['intercept']) - @callbacks.delete(id) + intercept = callbacks[id] + network.remove_intercept(intercept['intercept']) + callbacks.delete(id) end def clear_handlers - @callbacks.each_key { |id| remove_handler(id) } + callbacks.each_key { |id| remove_handler(id) } end def add_authentication_handler(username, password) - intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:auth_required]]) - auth_id = @network.on(:auth_required) do |event| - request_id = event['requestId'] - @network.continue_with_auth(request_id, username, password) + intercept = network.add_intercept(phases: [Selenium::WebDriver::BiDi::Network::PHASES[:auth_required]]) + auth_id = network.on(:auth_required) do |event| + request_id = event['request']['request'] + network.continue_with_auth(request_id, username, password) end - @callbacks[auth_id] = intercept + callbacks[auth_id] = intercept auth_id end def add_request_handler - intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:before_request]]) - request_id = @network.on(:before_request) do |event| - request_id = event['requestId'] - @network.continue_with_request(request_id: request_id) + intercept = network.add_intercept(phases: [BiDi::Network::PHASES[:before_request]]) + request_id = network.on(:before_request) do |event| + request_id = event['request']['request'] + network.continue_with_request(request_id: request_id) end - @callbacks[request_id] = intercept + callbacks[request_id] = intercept request_id end def add_response_handler - intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:response_started]]) - response_id = @network.on(:response_started) do |event| - request_id = event['requestId'] - @network.continue_with_response(request_id: request_id) + intercept = network.add_intercept(phases: [BiDi::Network::PHASES[:response_started]]) + response_id = network.on(:response_started) do |event| + request_id = event['request']['request'] + network.continue_with_response(request_id: request_id) end - @callbacks[response_id] = intercept + callbacks[response_id] = intercept response_id end diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index 6c6e7ec97c216..446a8e136e5cd 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -45,9 +45,10 @@ class BiDi password = SpecSupport::RackServer::TestApp::BASIC_AUTH_CREDENTIALS.last reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) - network.add_intercept(phases: [described_class::PHASES[:auth_required]]) + phases = [Selenium::WebDriver::BiDi::Network::PHASES[:auth_required]] + network.add_intercept(phases: phases) network.on(:auth_required) do |event| - request_id = event['requestId'] + request_id = event['request']['request'] network.continue_with_auth(request_id, username, password) end @@ -56,16 +57,20 @@ class BiDi end end + it 'continues with request' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) network.add_intercept(phases: [described_class::PHASES[:before_request]]) network.on(:before_request) do |event| request_id = event['requestId'] + pp 'cheese' network.continue_with_request(request_id: request_id) end + sleep 2 driver.navigate.to url_for('formPage.html') + sleep 2 expect(driver.find_element(name: 'login')).to be_displayed end end diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 78f7a41b951de..be7d879a5f40d 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -30,6 +30,8 @@ module WebDriver reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) network.add_authentication_handler(username, password) + driver.navigate.to url_for('basicAuth') + expect(driver.find_element(tag_name: 'h1').text).to eq('authorized') expect(network.callbacks.count).to be 1 end end From 28cf3635408b1db6923fec5fb915f1551d110fd3 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 20:44:41 +0100 Subject: [PATCH 03/35] Request and response working as expected --- rb/lib/selenium/webdriver/bidi/network.rb | 25 +++++++++++++++++++ .../lib/selenium/webdriver/bidi/network.rbs | 4 +++ .../lib/selenium/webdriver/common/network.rbs | 2 ++ .../selenium/webdriver/bidi/network_spec.rb | 8 ++---- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index d3530653445fb..43f9d5ff837e8 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -76,6 +76,31 @@ def cancel_auth(request_id) ) end + def continue_with_request(**args) + response = @bidi.send_cmd( + 'network.continueRequest', + request: args[:request_id], + 'body' => args[:body], + 'cookies' => args[:cookies], + 'headers' => args[:headers], + 'method' => args[:method], + 'url' => args[:url] + ) + response.inspect + end + + def continue_with_response(**args) + @bidi.send_cmd( + 'network.continueResponse', + request: args[:request_id], + 'body' => args[:body], + 'cookies' => args[:cookies], + 'credentials' => args[:credentials], + 'headers' => args[:headers], + 'status' => args[:status] + ) + end + def on(event, &block) event = EVENTS[event] if event.is_a?(Symbol) @bidi.add_callback(event, &block) diff --git a/rb/sig/lib/selenium/webdriver/bidi/network.rbs b/rb/sig/lib/selenium/webdriver/bidi/network.rbs index 7d2524f039fb6..64163bc529aaf 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network.rbs @@ -12,6 +12,10 @@ module Selenium def add_intercept: (?phases: Array[String], ?contexts: BrowsingContext?, ?url_patterns: untyped?) -> Hash[String, String] + def cancel_auth: -> untyped + + def continue_with_auth_no_credentials: -> untyped + def continue_with_request: (**untyped args) -> untyped def continue_with_response: (**untyped args) -> untyped diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index 4d89e797a4d3a..8cc204b06c514 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -7,6 +7,8 @@ module Selenium attr_reader callbacks: Hash[String, String] + attr_reader network: untyped + def initialize: (Remote::Bridge bridge) -> void def add_authentication_handler: (String username, String password) -> String diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index 446a8e136e5cd..371597a5502bd 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -57,20 +57,16 @@ class BiDi end end - it 'continues with request' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) network.add_intercept(phases: [described_class::PHASES[:before_request]]) network.on(:before_request) do |event| - request_id = event['requestId'] - pp 'cheese' + request_id = event['request']['request'] network.continue_with_request(request_id: request_id) end - sleep 2 driver.navigate.to url_for('formPage.html') - sleep 2 expect(driver.find_element(name: 'login')).to be_displayed end end @@ -80,7 +76,7 @@ class BiDi network = described_class.new(driver.bidi) network.add_intercept(phases: [described_class::PHASES[:response_started]]) network.on(:response_started) do |event| - request_id = event['requestId'] + request_id = event['request']['request'] network.continue_with_response(request_id: request_id) end From 314b458373af9db9d40b3b01a630364f815b8a0e Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 21:04:11 +0100 Subject: [PATCH 04/35] Add test for continue without auth and cancel auth --- rb/lib/selenium/webdriver/bidi/network.rb | 2 +- .../lib/selenium/webdriver/bidi/network.rbs | 4 +-- .../selenium/webdriver/bidi/network_spec.rb | 27 +++++++++++++++++++ .../selenium/webdriver/network_spec.rb | 4 +++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index 43f9d5ff837e8..1f497433185f6 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -60,7 +60,7 @@ def continue_with_auth(request_id, username, password) ) end - def continue_with_auth_no_credentials(request_id) + def continue_without_auth(request_id) @bidi.send_cmd( 'network.continueWithAuth', 'request' => request_id, diff --git a/rb/sig/lib/selenium/webdriver/bidi/network.rbs b/rb/sig/lib/selenium/webdriver/bidi/network.rbs index 64163bc529aaf..31a9859797eaf 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network.rbs @@ -14,12 +14,12 @@ module Selenium def cancel_auth: -> untyped - def continue_with_auth_no_credentials: -> untyped - def continue_with_request: (**untyped args) -> untyped def continue_with_response: (**untyped args) -> untyped + def continue_without_auth: -> untyped + def remove_intercept: (String intercept) -> untyped def continue_with_auth: (String request_id, String username, String password) -> untyped diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index 371597a5502bd..7f8f9d0bd30c9 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -57,6 +57,33 @@ class BiDi end end + it 'continues without auth' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + network.add_intercept(phases: [described_class::PHASES[:auth_required]]) + network.on(:auth_required) do |event| + request_id = event['request']['request'] + network.continue_without_auth(request_id) + end + + expect { driver.navigate.to url_for('basicAuth') }.to raise_error(Error::WebDriverError) + end + end + + it 'cancels auth' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + network.add_intercept(phases: [described_class::PHASES[:auth_required]]) + network.on(:auth_required) do |event| + request_id = event['request']['request'] + network.cancel_auth(request_id) + end + + driver.navigate.to url_for('basicAuth') + expect(driver.find_element(tag_name: 'pre').text).to eq('Login please') + end + end + it 'continues with request' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index be7d879a5f40d..7df323bec04b1 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -59,6 +59,8 @@ module WebDriver reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) network.add_request_handler + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed expect(network.callbacks.count).to be 1 end end @@ -86,6 +88,8 @@ module WebDriver reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) network.add_response_handler + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed expect(network.callbacks.count).to be 1 end end From 305135e18a008dd67952ba63ef05a5fd9cf9236a Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 21:54:39 +0100 Subject: [PATCH 05/35] Finish implementation --- rb/lib/selenium/webdriver/bidi/network.rb | 3 +-- rb/lib/selenium/webdriver/common/network.rb | 26 +++++++++++-------- .../lib/selenium/webdriver/common/network.rbs | 2 ++ .../selenium/webdriver/network_spec.rb | 4 +-- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index 1f497433185f6..cc99b864c07c9 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -77,7 +77,7 @@ def cancel_auth(request_id) end def continue_with_request(**args) - response = @bidi.send_cmd( + @bidi.send_cmd( 'network.continueRequest', request: args[:request_id], 'body' => args[:body], @@ -86,7 +86,6 @@ def continue_with_request(**args) 'method' => args[:method], 'url' => args[:url] ) - response.inspect end def continue_with_response(**args) diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 5eb542bb6e1e0..fad4186c6821e 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -17,11 +17,17 @@ # specific language governing permissions and limitations # under the License. +require 'forwardable' + module Selenium module WebDriver class Network + extend Forwardable + attr_reader :callbacks, :network + def_delegators :network, :continue_with_auth, :continue_with_request, :continue_with_response + def initialize(bridge) @network = BiDi::Network.new(bridge.bidi) @callbacks = {} @@ -40,7 +46,7 @@ def clear_handlers def add_authentication_handler(username, password) intercept = network.add_intercept(phases: [Selenium::WebDriver::BiDi::Network::PHASES[:auth_required]]) auth_id = network.on(:auth_required) do |event| - request_id = event['request']['request'] + request_id = fetch_id(event) network.continue_with_auth(request_id, username, password) end @@ -48,29 +54,27 @@ def add_authentication_handler(username, password) auth_id end - def add_request_handler + def add_request_handler(&) intercept = network.add_intercept(phases: [BiDi::Network::PHASES[:before_request]]) - request_id = network.on(:before_request) do |event| - request_id = event['request']['request'] - network.continue_with_request(request_id: request_id) - end + request_id = network.on(:before_request, &) callbacks[request_id] = intercept request_id end - def add_response_handler + def add_response_handler(&) intercept = network.add_intercept(phases: [BiDi::Network::PHASES[:response_started]]) - response_id = network.on(:response_started) do |event| - request_id = event['request']['request'] - network.continue_with_response(request_id: request_id) - end + response_id = network.on(:response_started, &) callbacks[response_id] = intercept response_id end + + def fetch_id(event) + event['request']['request'] + end end # Network end # WebDriver end # Selenium diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index 8cc204b06c514..b31e21fdf622f 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -19,6 +19,8 @@ module Selenium def clear_handlers: -> Hash[nil, nil] + def fetch_id: -> String + def remove_handler: (Integer id) -> nil end end diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 7df323bec04b1..2f3be8111924a 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -58,7 +58,7 @@ module WebDriver it 'adds a request handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_request_handler + network.add_request_handler { |event| network.continue_with_request(request_id: network.fetch_id(event)) } driver.navigate.to url_for('formPage.html') expect(driver.find_element(name: 'login')).to be_displayed expect(network.callbacks.count).to be 1 @@ -87,7 +87,7 @@ module WebDriver it 'adds a response handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_response_handler + network.add_response_handler { |event| network.continue_with_response(request_id: network.fetch_id(event)) } driver.navigate.to url_for('formPage.html') expect(driver.find_element(name: 'login')).to be_displayed expect(network.callbacks.count).to be 1 From ff2ba0d901850d4115179c3ed00bd394e420a29c Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 21:55:40 +0100 Subject: [PATCH 06/35] Correct rubocop offenses --- rb/lib/selenium/webdriver/bidi/network.rb | 4 ++-- rb/sig/lib/selenium/webdriver/bidi.rbs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index cc99b864c07c9..46fb17b7160bc 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -100,9 +100,9 @@ def continue_with_response(**args) ) end - def on(event, &block) + def on(event, &) event = EVENTS[event] if event.is_a?(Symbol) - @bidi.add_callback(event, &block) + @bidi.add_callback(event, &) @bidi.session.subscribe(event) end end # Network diff --git a/rb/sig/lib/selenium/webdriver/bidi.rbs b/rb/sig/lib/selenium/webdriver/bidi.rbs index 314dc70fdd5f3..d5c257921d144 100644 --- a/rb/sig/lib/selenium/webdriver/bidi.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi.rbs @@ -7,7 +7,7 @@ module Selenium def initialize: (url: String) -> void - def add_callback: (String event) { () -> void } -> Integer + def add_callback: (String | Symbol event) { () -> void } -> Integer def close: () -> nil From 0b4126691546770f13cfcd0d184bbc706a070f82 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 22:04:03 +0100 Subject: [PATCH 07/35] Add alias for user to do network.bidi instead of network.network --- rb/lib/selenium/webdriver/common/network.rb | 1 + rb/sig/lib/selenium/webdriver/common/network.rbs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index fad4186c6821e..b4a604dc55761 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -25,6 +25,7 @@ class Network extend Forwardable attr_reader :callbacks, :network + alias bidi network def_delegators :network, :continue_with_auth, :continue_with_request, :continue_with_response diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index b31e21fdf622f..8e7bb42d4c564 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -17,6 +17,8 @@ module Selenium def add_response_handler: -> String + alias bidi network + def clear_handlers: -> Hash[nil, nil] def fetch_id: -> String From 25c201b1f91b945c975fca6d61149e0d205917d7 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 18 Dec 2024 22:37:52 +0100 Subject: [PATCH 08/35] Fix rust file causing formatting error --- rust/src/lock.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rust/src/lock.rs b/rust/src/lock.rs index dfb987acbf82b..cd074b94ceab0 100644 --- a/rust/src/lock.rs +++ b/rust/src/lock.rs @@ -1,3 +1,20 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + use crate::logger::Logger; use anyhow::Error; use std::fs::File; From 7e222398cae58a6d90eae25e218ffbb90effa8f2 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sun, 22 Dec 2024 15:06:54 +0100 Subject: [PATCH 09/35] Handle requests and responses in block --- rb/lib/selenium/webdriver/bidi.rb | 4 ++ rb/lib/selenium/webdriver/bidi/network.rb | 2 +- .../bidi/network/intercepted_auth.rb | 39 +++++++++++++++ .../bidi/network/intercepted_item.rb | 46 ++++++++++++++++++ .../bidi/network/intercepted_request.rb | 31 ++++++++++++ .../bidi/network/intercepted_response.rb | 31 ++++++++++++ rb/lib/selenium/webdriver/common/network.rb | 37 ++++++--------- .../selenium/webdriver/network_spec.rb | 47 ++++++++++++++----- 8 files changed, 202 insertions(+), 35 deletions(-) create mode 100644 rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb create mode 100644 rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb create mode 100644 rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb create mode 100644 rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb diff --git a/rb/lib/selenium/webdriver/bidi.rb b/rb/lib/selenium/webdriver/bidi.rb index 214091791fc45..ed3bcc7b12098 100644 --- a/rb/lib/selenium/webdriver/bidi.rb +++ b/rb/lib/selenium/webdriver/bidi.rb @@ -26,6 +26,10 @@ class BiDi autoload :BrowsingContext, 'selenium/webdriver/bidi/browsing_context' autoload :Struct, 'selenium/webdriver/bidi/struct' autoload :Network, 'selenium/webdriver/bidi/network' + autoload :InterceptedRequest, 'selenium/webdriver/bidi/network/intercepted_request' + autoload :InterceptedResponse, 'selenium/webdriver/bidi/network/intercepted_response' + autoload :InterceptedAuth, 'selenium/webdriver/bidi/network/intercepted_auth' + autoload :InterceptedItem, 'selenium/webdriver/bidi/network/intercepted_item' def initialize(url:) @ws = WebSocketConnection.new(url: url) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index 46fb17b7160bc..6eaa45b5cb116 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -91,7 +91,7 @@ def continue_with_request(**args) def continue_with_response(**args) @bidi.send_cmd( 'network.continueResponse', - request: args[:request_id], + request: args[:response_id], 'body' => args[:body], 'cookies' => args[:cookies], 'credentials' => args[:credentials], diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb new file mode 100644 index 0000000000000..ed219197ff65d --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + class InterceptedAuth < InterceptedItem + def authenticate(username, password) + network.continue_with_auth(id, username, password) + end + + def skip + network.continue_without_auth(id) + end + + def cancel + network.cancel_auth(id) + end + end + end # BiDi + end # WebDriver +end # Selenium + diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb new file mode 100644 index 0000000000000..b755ae523af46 --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + class InterceptedItem + attr_reader :network, :request + + def initialize(network, request) + @network = network + @request = request + end + + def id + @id ||= @request['request'] + end + + def headers + request['headers'] + end + + def headers=(new_headers) + request['headers'] = new_headers + end + end + end # BiDi + end # WebDriver +end # Selenium + diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb new file mode 100644 index 0000000000000..63253b2a7ae43 --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + class InterceptedRequest < InterceptedItem + def continue + network.continue_with_request(request_id: id) + end + end + end # BiDi + end # WebDriver +end # Selenium + diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb new file mode 100644 index 0000000000000..ff297614c5132 --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + class InterceptedResponse < InterceptedItem + def continue + network.continue_with_response(response_id: id) + end + end + end # BiDi + end # WebDriver +end # Selenium + diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index b4a604dc55761..5cf052bcfff5a 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -44,37 +44,30 @@ def clear_handlers callbacks.each_key { |id| remove_handler(id) } end - def add_authentication_handler(username, password) - intercept = network.add_intercept(phases: [Selenium::WebDriver::BiDi::Network::PHASES[:auth_required]]) - auth_id = network.on(:auth_required) do |event| - request_id = fetch_id(event) - network.continue_with_auth(request_id, username, password) - end - - callbacks[auth_id] = intercept - auth_id + def add_authentication_handler(&) + add_handler(:auth_required, BiDi::Network::PHASES[:auth_required], BiDi::InterceptedAuth, &) end def add_request_handler(&) - intercept = network.add_intercept(phases: [BiDi::Network::PHASES[:before_request]]) - request_id = network.on(:before_request, &) - - callbacks[request_id] = intercept - - request_id + add_handler(:before_request, BiDi::Network::PHASES[:before_request], BiDi::InterceptedRequest, &) end def add_response_handler(&) - intercept = network.add_intercept(phases: [BiDi::Network::PHASES[:response_started]]) - response_id = network.on(:response_started, &) + add_handler(:response_started, BiDi::Network::PHASES[:response_started], BiDi::InterceptedResponse, &) + end - callbacks[response_id] = intercept + private - response_id - end + def add_handler(event_type, phase, intercept_type, &block) + intercept = network.add_intercept(phases: [phase]) + callback_id = network.on(event_type) do |event| + request = event['request'] + intercepted_item = intercept_type.new(network, request) + block.call(intercepted_item) + end - def fetch_id(event) - event['request']['request'] + callbacks[callback_id] = intercept + callback_id end end # Network end # WebDriver diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 2f3be8111924a..d40636e4000e9 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -29,7 +29,9 @@ module WebDriver it 'adds an auth handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_authentication_handler(username, password) + network.add_authentication_handler do |response| + response.authenticate(username, password) + end driver.navigate.to url_for('basicAuth') expect(driver.find_element(tag_name: 'h1').text).to eq('authorized') expect(network.callbacks.count).to be 1 @@ -39,7 +41,9 @@ module WebDriver it 'removes an auth handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - id = network.add_authentication_handler(username, password) + id = network.add_authentication_handler do |response| + response.authenticate(username, password) + end network.remove_handler(id) expect(network.callbacks.count).to be 0 end @@ -48,17 +52,37 @@ module WebDriver it 'clears all auth handlers' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_authentication_handler(username, password) - network.add_authentication_handler(username, password) + 2.times do + network.add_authentication_handler do |response| + response.authenticate(username, password) + end + end network.clear_handlers expect(network.callbacks.count).to be 0 end end + it 'continues without auth' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_authentication_handler(&:skip) + expect { driver.navigate.to url_for('basicAuth') }.to raise_error(Error::WebDriverError) + end + end + + it 'cancels auth' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_authentication_handler(&:cancel) + driver.navigate.to url_for('basicAuth') + expect(driver.find_element(tag_name: 'pre').text).to eq('Login please') + end + end + it 'adds a request handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_request_handler { |event| network.continue_with_request(request_id: network.fetch_id(event)) } + network.add_request_handler(&:continue) driver.navigate.to url_for('formPage.html') expect(driver.find_element(name: 'login')).to be_displayed expect(network.callbacks.count).to be 1 @@ -68,7 +92,7 @@ module WebDriver it 'removes a request handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - id = network.add_request_handler + id = network.add_request_handler(&:continue) network.remove_handler(id) expect(network.callbacks.count).to be 0 end @@ -77,8 +101,7 @@ module WebDriver it 'clears all request handlers' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_request_handler - network.add_request_handler + 2.times { network.add_request_handler(&:continue) } network.clear_handlers expect(network.callbacks.count).to be 0 end @@ -87,7 +110,7 @@ module WebDriver it 'adds a response handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_response_handler { |event| network.continue_with_response(request_id: network.fetch_id(event)) } + network.add_response_handler(&:continue) driver.navigate.to url_for('formPage.html') expect(driver.find_element(name: 'login')).to be_displayed expect(network.callbacks.count).to be 1 @@ -97,8 +120,9 @@ module WebDriver it 'removes a response handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - id = network.add_response_handler + id = network.add_response_handler(&:continue) network.remove_handler(id) + network.clear_handlers expect(network.callbacks.count).to be 0 end end @@ -106,8 +130,7 @@ module WebDriver it 'clears all response handlers' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_response_handler - network.add_response_handler + 2.times { network.add_response_handler(&:continue) } network.clear_handlers expect(network.callbacks.count).to be 0 end From ae8083239c5c9382389d3a837c68b02e1e8c1273 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Mon, 23 Dec 2024 23:51:59 +0100 Subject: [PATCH 10/35] Add ability to pass handlers to each different intercepted element --- rb/lib/selenium/webdriver/bidi/network.rb | 19 +++++++++++----- .../bidi/network/intercepted_item.rb | 14 +++--------- .../bidi/network/intercepted_request.rb | 17 +++++++++++++- .../bidi/network/intercepted_response.rb | 12 +++++++++- rb/lib/selenium/webdriver/common/network.rb | 2 +- .../selenium/webdriver/bidi/network_spec.rb | 21 ++++++++++++++---- .../selenium/webdriver/network_spec.rb | 22 +++++++++++++++++++ 7 files changed, 83 insertions(+), 24 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index 6eaa45b5cb116..c4fff8bcbe250 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -76,10 +76,10 @@ def cancel_auth(request_id) ) end - def continue_with_request(**args) + def continue_request(**args) @bidi.send_cmd( 'network.continueRequest', - request: args[:request_id], + request: args[:id], 'body' => args[:body], 'cookies' => args[:cookies], 'headers' => args[:headers], @@ -88,15 +88,22 @@ def continue_with_request(**args) ) end - def continue_with_response(**args) + def fail_request(request_id) + @bidi.send_cmd( + 'network.failRequest', + request: request_id + ) + end + + def continue_response(**args) @bidi.send_cmd( 'network.continueResponse', - request: args[:response_id], - 'body' => args[:body], + request: args[:id], 'cookies' => args[:cookies], 'credentials' => args[:credentials], 'headers' => args[:headers], - 'status' => args[:status] + 'reasonPhrase' => args[:reason], + 'statusCode' => args[:status] ) end diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb index b755ae523af46..3d8d2e6edde7c 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb @@ -23,22 +23,14 @@ class BiDi class InterceptedItem attr_reader :network, :request - def initialize(network, request) - @network = network - @request = request + def initialize(**args) + @network = args[:network] + @request = args[:request] end def id @id ||= @request['request'] end - - def headers - request['headers'] - end - - def headers=(new_headers) - request['headers'] = new_headers - end end end # BiDi end # WebDriver diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index 63253b2a7ae43..4ca64419919a6 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -21,8 +21,23 @@ module Selenium module WebDriver class BiDi class InterceptedRequest < InterceptedItem + attr_accessor :body, :cookies, :headers, :method, :url + + def new(**args) + super(args[:network], args[:request]) + @body = args[:body] + @cookies = args[:cookies] + @headers = args[:headers] + @method = args[:method] + @url = args[:url] + end + def continue - network.continue_with_request(request_id: id) + network.continue_request(id:, body:, cookies:, headers:, method:, url:) + end + + def fail + network.fail_request(id) end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index ff297614c5132..ff728b13f529a 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -21,8 +21,18 @@ module Selenium module WebDriver class BiDi class InterceptedResponse < InterceptedItem + attr_accessor :cookies, :headers, :credentials, :reason + + def new + super(args[:network], args[:request]) + @cookies = args[:cookies] + @headers = args[:headers] + @credentials = args[:credentials] + @reason = args[:reason] + end + def continue - network.continue_with_response(response_id: id) + network.continue_response(id:, cookies:, headers:, credentials:, reason:) end end end # BiDi diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 5cf052bcfff5a..8b7a844c275bc 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -62,7 +62,7 @@ def add_handler(event_type, phase, intercept_type, &block) intercept = network.add_intercept(phases: [phase]) callback_id = network.on(event_type) do |event| request = event['request'] - intercepted_item = intercept_type.new(network, request) + intercepted_item = intercept_type.new(network: network, request: request) block.call(intercepted_item) end diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index 7f8f9d0bd30c9..d9ce113a30ea0 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -84,13 +84,13 @@ class BiDi end end - it 'continues with request' do + it 'continues request' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) network.add_intercept(phases: [described_class::PHASES[:before_request]]) network.on(:before_request) do |event| request_id = event['request']['request'] - network.continue_with_request(request_id: request_id) + network.continue_request(id: request_id) end driver.navigate.to url_for('formPage.html') @@ -98,13 +98,26 @@ class BiDi end end - it 'continues with response' do + it 'fails request' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + network.add_intercept(phases: [described_class::PHASES[:before_request]]) + network.on(:before_request) do |event| + request_id = event['request']['request'] + network.fail_request(request_id) + end + + expect { driver.navigate.to url_for('formPage.html') }.to raise_error(Error::WebDriverError) + end + end + + it 'continues response' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) network.add_intercept(phases: [described_class::PHASES[:response_started]]) network.on(:response_started) do |event| request_id = event['request']['request'] - network.continue_with_response(request_id: request_id) + network.continue_response(id: request_id) end driver.navigate.to url_for('formPage.html') diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index d40636e4000e9..aceeb5a694837 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -89,6 +89,28 @@ module WebDriver end end + it 'adds a request handler with attributes' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler do |request| + request.method = 'GET' + request.continue + end + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + + it 'fails a request' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler(&:fail) + expect(network.callbacks.count).to be 1 + expect { driver.navigate.to url_for('formPage.html') }.to raise_error(Error::WebDriverError) + end + end + it 'removes a request handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) From c21f64307546329abdacdd5d8c64b1d3f3ef5b1f Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 1 Jan 2025 15:32:42 +0100 Subject: [PATCH 11/35] Headers working --- .../webdriver/bidi/network/intercepted_item.rb | 6 +++--- .../webdriver/bidi/network/intercepted_request.rb | 14 ++++++++++++-- .../webdriver/bidi/network/intercepted_response.rb | 2 +- .../integration/selenium/webdriver/network_spec.rb | 3 +++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb index 3d8d2e6edde7c..6bc2539bad149 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb @@ -23,9 +23,9 @@ class BiDi class InterceptedItem attr_reader :network, :request - def initialize(**args) - @network = args[:network] - @request = args[:request] + def initialize(network, request) + @network = network + @request = request end def id diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index 4ca64419919a6..ad507ae0cc4d1 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -23,11 +23,11 @@ class BiDi class InterceptedRequest < InterceptedItem attr_accessor :body, :cookies, :headers, :method, :url - def new(**args) + def initialize(**args) super(args[:network], args[:request]) @body = args[:body] @cookies = args[:cookies] - @headers = args[:headers] + @headers = args[:headers] || [] @method = args[:method] @url = args[:url] end @@ -39,6 +39,16 @@ def continue def fail network.fail_request(id) end + + def add_header(name, value) + headers.push( + 'name' => name, + 'value' => { + 'type' => 'string', + 'value' => value + } + ) + end end end # BiDi end # WebDriver diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index ff728b13f529a..5bad854883fa5 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -23,7 +23,7 @@ class BiDi class InterceptedResponse < InterceptedItem attr_accessor :cookies, :headers, :credentials, :reason - def new + def initialize(**args) super(args[:network], args[:request]) @cookies = args[:cookies] @headers = args[:headers] diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index aceeb5a694837..2506b548cc945 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -94,6 +94,9 @@ module WebDriver network = described_class.new(driver) network.add_request_handler do |request| request.method = 'GET' + request.url = url_for('formPage.html') + request.add_header('foo', 'bar') + request.add_header('baz', 'qux') request.continue end driver.navigate.to url_for('formPage.html') From 69b5690922378570eb28265ff658fd2341faf773 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 1 Jan 2025 17:34:52 +0100 Subject: [PATCH 12/35] All tests passing and signatures simplified --- rb/lib/selenium/webdriver/bidi/network.rb | 4 +- .../webdriver/bidi/network/cookies.rb | 41 +++++++++++++++++++ .../webdriver/bidi/network/headers.rb | 41 +++++++++++++++++++ .../bidi/network/intercepted_request.rb | 38 +++++++++-------- .../bidi/network/intercepted_response.rb | 12 +++--- rb/lib/selenium/webdriver/common/error.rb | 2 +- rb/lib/selenium/webdriver/common/manager.rb | 6 +-- rb/lib/selenium/webdriver/common/network.rb | 2 +- rb/lib/selenium/webdriver/remote/bridge.rb | 2 +- .../webdriver/remote/bridge/commands.rb | 2 +- .../selenium/webdriver/network_spec.rb | 24 +++++++++++ 11 files changed, 142 insertions(+), 32 deletions(-) create mode 100644 rb/lib/selenium/webdriver/bidi/network/cookies.rb create mode 100644 rb/lib/selenium/webdriver/bidi/network/headers.rb diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index c4fff8bcbe250..d1335d27ba349 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -81,7 +81,7 @@ def continue_request(**args) 'network.continueRequest', request: args[:id], 'body' => args[:body], - 'cookies' => args[:cookies], + 'cookies.rb' => args[:cookies], 'headers' => args[:headers], 'method' => args[:method], 'url' => args[:url] @@ -99,7 +99,7 @@ def continue_response(**args) @bidi.send_cmd( 'network.continueResponse', request: args[:id], - 'cookies' => args[:cookies], + 'cookies.rb' => args[:cookies], 'credentials' => args[:credentials], 'headers' => args[:headers], 'reasonPhrase' => args[:reason], diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb new file mode 100644 index 0000000000000..8f40abad9d751 --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + module Cookies + def add_cookie(name, value) + cookies.push( + 'name' => name, + 'value' => { + 'type' => 'string', + 'value' => value + } + ) + end + + def remove_cookie(name) + cookies.delete_if { |cookie| cookie['name'] == name } + end + end + end # BiDi + end # WebDriver +end # Selenium + diff --git a/rb/lib/selenium/webdriver/bidi/network/headers.rb b/rb/lib/selenium/webdriver/bidi/network/headers.rb new file mode 100644 index 0000000000000..3b81d5b5d891d --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/headers.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + module Headers + def add_header(name, value) + headers.push( + 'name' => name, + 'value' => { + 'type' => 'string', + 'value' => value + } + ) + end + + def remove_header(name) + headers.delete_if { |header| header['name'] == name } + end + end + end # BiDi + end # WebDriver +end # Selenium + diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index ad507ae0cc4d1..cd869fd63e8d0 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -17,19 +17,26 @@ # specific language governing permissions and limitations # under the License. +require_relative 'cookies' +require_relative 'headers' + module Selenium module WebDriver class BiDi class InterceptedRequest < InterceptedItem - attr_accessor :body, :cookies, :headers, :method, :url - - def initialize(**args) - super(args[:network], args[:request]) - @body = args[:body] - @cookies = args[:cookies] - @headers = args[:headers] || [] - @method = args[:method] - @url = args[:url] + include Cookies + include Headers + + attr_accessor :cookies, :headers, :method, :url + attr_reader :body + + def initialize(network, request) + super + @body = nil + @cookies = [] + @headers = [] + @method = nil + @url = nil end def continue @@ -40,14 +47,11 @@ def fail network.fail_request(id) end - def add_header(name, value) - headers.push( - 'name' => name, - 'value' => { - 'type' => 'string', - 'value' => value - } - ) + def body=(value) + @body = { + 'type' => 'string', + 'value' => value.to_json + } end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 5bad854883fa5..dda1e02122fa8 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -23,12 +23,12 @@ class BiDi class InterceptedResponse < InterceptedItem attr_accessor :cookies, :headers, :credentials, :reason - def initialize(**args) - super(args[:network], args[:request]) - @cookies = args[:cookies] - @headers = args[:headers] - @credentials = args[:credentials] - @reason = args[:reason] + def initialize(network, request) + super + @cookies = [] + @headers = [] + @credentials = nil + @reason = nil end def continue diff --git a/rb/lib/selenium/webdriver/common/error.rb b/rb/lib/selenium/webdriver/common/error.rb index ed452cb7377df..ee30c94425ca5 100644 --- a/rb/lib/selenium/webdriver/common/error.rb +++ b/rb/lib/selenium/webdriver/common/error.rb @@ -189,7 +189,7 @@ class InsecureCertificateError < WebDriverError; end class InvalidArgumentError < WebDriverError; end # - # No cookie matching the given path name was found amongst the associated cookies of the + # No cookie matching the given path name was found amongst the associated cookies.rb of the # current browsing context's active document. # diff --git a/rb/lib/selenium/webdriver/common/manager.rb b/rb/lib/selenium/webdriver/common/manager.rb index 99181d7700f67..6b09b4740b2f0 100644 --- a/rb/lib/selenium/webdriver/common/manager.rb +++ b/rb/lib/selenium/webdriver/common/manager.rb @@ -83,7 +83,7 @@ def delete_cookie(name) end # - # Delete all cookies + # Delete all cookies.rb # def delete_all_cookies @@ -91,9 +91,9 @@ def delete_all_cookies end # - # Get all cookies + # Get all cookies.rb # - # @return [Array] list of cookies + # @return [Array] list of cookies.rb # def all_cookies diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 8b7a844c275bc..5cf052bcfff5a 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -62,7 +62,7 @@ def add_handler(event_type, phase, intercept_type, &block) intercept = network.add_intercept(phases: [phase]) callback_id = network.on(event_type) do |event| request = event['request'] - intercepted_item = intercept_type.new(network: network, request: request) + intercepted_item = intercept_type.new(network, request) block.call(intercepted_item) end diff --git a/rb/lib/selenium/webdriver/remote/bridge.rb b/rb/lib/selenium/webdriver/remote/bridge.rb index 2c26285a780e0..c19d59700d335 100644 --- a/rb/lib/selenium/webdriver/remote/bridge.rb +++ b/rb/lib/selenium/webdriver/remote/bridge.rb @@ -373,7 +373,7 @@ def execute_async_script(script, *args) end # - # cookies + # cookies.rb # def manage diff --git a/rb/lib/selenium/webdriver/remote/bridge/commands.rb b/rb/lib/selenium/webdriver/remote/bridge/commands.rb index 5eeb61f755961..0412af7f19614 100644 --- a/rb/lib/selenium/webdriver/remote/bridge/commands.rb +++ b/rb/lib/selenium/webdriver/remote/bridge/commands.rb @@ -96,7 +96,7 @@ class Bridge execute_async_script: [:post, 'session/:session_id/execute/async'], # - # cookies + # cookies.rb # get_all_cookies: [:get, 'session/:session_id/cookie'], diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 2506b548cc945..d17c94872574c 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -97,6 +97,8 @@ module WebDriver request.url = url_for('formPage.html') request.add_header('foo', 'bar') request.add_header('baz', 'qux') + request.add_cookie('foo', 'bar') + request.body = ({test: 'example'}) request.continue end driver.navigate.to url_for('formPage.html') @@ -105,6 +107,28 @@ module WebDriver end end + it 'removes a header from a request handler' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler do |request| + request.add_header('foo', 'bar') + request.remove_header('foo') + expect(request.headers).to be_empty + end + end + end + + it 'removes a cookie from a request handler' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler do |request| + request.add_cookie('foo', 'bar') + request.remove_cookie('foo') + expect(request.cookies).to be_empty + end + end + end + it 'fails a request' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) From bb1ece5d2a2f471c4af07ef1e4750a54de306428 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 1 Jan 2025 17:35:45 +0100 Subject: [PATCH 13/35] remove unnecessary changes --- rb/lib/selenium/webdriver/remote/bridge/commands.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rb/lib/selenium/webdriver/remote/bridge/commands.rb b/rb/lib/selenium/webdriver/remote/bridge/commands.rb index 0412af7f19614..5eeb61f755961 100644 --- a/rb/lib/selenium/webdriver/remote/bridge/commands.rb +++ b/rb/lib/selenium/webdriver/remote/bridge/commands.rb @@ -96,7 +96,7 @@ class Bridge execute_async_script: [:post, 'session/:session_id/execute/async'], # - # cookies.rb + # cookies # get_all_cookies: [:get, 'session/:session_id/cookie'], From 996c527bbd1bfadbf9757ddcc48bcefdfaef1a87 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Wed, 1 Jan 2025 17:37:50 +0100 Subject: [PATCH 14/35] remove unnecessary changes --- rb/lib/selenium/webdriver/bidi/network.rb | 4 ++-- rb/lib/selenium/webdriver/common/error.rb | 2 +- rb/lib/selenium/webdriver/common/manager.rb | 6 +++--- rb/lib/selenium/webdriver/remote/bridge.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index d1335d27ba349..c4fff8bcbe250 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -81,7 +81,7 @@ def continue_request(**args) 'network.continueRequest', request: args[:id], 'body' => args[:body], - 'cookies.rb' => args[:cookies], + 'cookies' => args[:cookies], 'headers' => args[:headers], 'method' => args[:method], 'url' => args[:url] @@ -99,7 +99,7 @@ def continue_response(**args) @bidi.send_cmd( 'network.continueResponse', request: args[:id], - 'cookies.rb' => args[:cookies], + 'cookies' => args[:cookies], 'credentials' => args[:credentials], 'headers' => args[:headers], 'reasonPhrase' => args[:reason], diff --git a/rb/lib/selenium/webdriver/common/error.rb b/rb/lib/selenium/webdriver/common/error.rb index ee30c94425ca5..ed452cb7377df 100644 --- a/rb/lib/selenium/webdriver/common/error.rb +++ b/rb/lib/selenium/webdriver/common/error.rb @@ -189,7 +189,7 @@ class InsecureCertificateError < WebDriverError; end class InvalidArgumentError < WebDriverError; end # - # No cookie matching the given path name was found amongst the associated cookies.rb of the + # No cookie matching the given path name was found amongst the associated cookies of the # current browsing context's active document. # diff --git a/rb/lib/selenium/webdriver/common/manager.rb b/rb/lib/selenium/webdriver/common/manager.rb index 6b09b4740b2f0..99181d7700f67 100644 --- a/rb/lib/selenium/webdriver/common/manager.rb +++ b/rb/lib/selenium/webdriver/common/manager.rb @@ -83,7 +83,7 @@ def delete_cookie(name) end # - # Delete all cookies.rb + # Delete all cookies # def delete_all_cookies @@ -91,9 +91,9 @@ def delete_all_cookies end # - # Get all cookies.rb + # Get all cookies # - # @return [Array] list of cookies.rb + # @return [Array] list of cookies # def all_cookies diff --git a/rb/lib/selenium/webdriver/remote/bridge.rb b/rb/lib/selenium/webdriver/remote/bridge.rb index c19d59700d335..2c26285a780e0 100644 --- a/rb/lib/selenium/webdriver/remote/bridge.rb +++ b/rb/lib/selenium/webdriver/remote/bridge.rb @@ -373,7 +373,7 @@ def execute_async_script(script, *args) end # - # cookies.rb + # cookies # def manage From f2f9e01c0249628df051b376d097d84a2ed3e04c Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Thu, 2 Jan 2025 22:48:17 +0100 Subject: [PATCH 15/35] Added credentials and set cookie header to intercepted response --- .../webdriver/bidi/network/cookies.rb | 21 ++++++++++++++++- .../bidi/network/intercepted_response.rb | 21 +++++++++++++++-- .../selenium/webdriver/network_spec.rb | 23 +++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index 8f40abad9d751..63a3c12369017 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -34,8 +34,27 @@ def add_cookie(name, value) def remove_cookie(name) cookies.delete_if { |cookie| cookie['name'] == name } end + + def set_cookie_header(**args) + cookies.push( + 'name' => args[:name], + 'value' => { + 'type' => 'string', + 'value' => 'input' + }, + 'domain' => args[:domain], + 'httpOnly' => args[:http_only], + 'expiry' => args[:expiry], + 'maxAge' => args[:max_age], + 'path' => args[:path], + 'sameSite' => args[:same_site], + 'secure' => args[:secure] + ) + end end - end # BiDi + end + + # BiDi end # WebDriver end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index dda1e02122fa8..2a6f510908e16 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -17,11 +17,18 @@ # specific language governing permissions and limitations # under the License. +require_relative 'cookies' +require_relative 'headers' + module Selenium module WebDriver class BiDi class InterceptedResponse < InterceptedItem - attr_accessor :cookies, :headers, :credentials, :reason + include Cookies + include Headers + + attr_accessor :cookies, :headers, :reason + attr_reader :credentials def initialize(network, request) super @@ -34,8 +41,18 @@ def initialize(network, request) def continue network.continue_response(id:, cookies:, headers:, credentials:, reason:) end + + def add_credentials(username, password) + @credentials = { + 'type' => 'password', + 'username' => username, + 'password' => password + } + end end - end # BiDi + end + + # BiDi end # WebDriver end # Selenium diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index d17c94872574c..5e43e8cc9cbb7 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -166,6 +166,29 @@ module WebDriver end end + it 'adds a response handler with attributes' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler do |response| + response.reason = 'OK' + response.add_header('foo', 'bar') + response.set_cookie_header(name: 'foo', + domain: 'localhost', + http_only: true, + expiry: '1_000_000', + max_age: 1_000, + path: '/', + same_site: 'none', + secure: false) + response.add_credentials('foo', 'bar') + response.continue + end + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + it 'removes a response handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) From 71f5fa656b6d32c155dba0e4af9630cf1c4a6b98 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Fri, 3 Jan 2025 00:02:57 +0100 Subject: [PATCH 16/35] Fix rubocop issues --- rb/lib/selenium/webdriver/bidi/network/cookies.rb | 1 - rb/lib/selenium/webdriver/bidi/network/headers.rb | 1 - rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb | 1 - rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb | 1 - rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb | 1 - .../selenium/webdriver/bidi/network/intercepted_response.rb | 1 - rb/lib/selenium/webdriver/common/network.rb | 4 ++-- 7 files changed, 2 insertions(+), 8 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index 63a3c12369017..b21540225c3b3 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -57,4 +57,3 @@ def set_cookie_header(**args) # BiDi end # WebDriver end # Selenium - diff --git a/rb/lib/selenium/webdriver/bidi/network/headers.rb b/rb/lib/selenium/webdriver/bidi/network/headers.rb index 3b81d5b5d891d..329f8069cf582 100644 --- a/rb/lib/selenium/webdriver/bidi/network/headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/headers.rb @@ -38,4 +38,3 @@ def remove_header(name) end # BiDi end # WebDriver end # Selenium - diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb index ed219197ff65d..71c5d7bcac785 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_auth.rb @@ -36,4 +36,3 @@ def cancel end # BiDi end # WebDriver end # Selenium - diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb index 6bc2539bad149..1f7445ebbe78b 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_item.rb @@ -35,4 +35,3 @@ def id end # BiDi end # WebDriver end # Selenium - diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index cd869fd63e8d0..9e683a6652901 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -57,4 +57,3 @@ def body=(value) end # BiDi end # WebDriver end # Selenium - diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 2a6f510908e16..230c4a9a442a7 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -55,4 +55,3 @@ def add_credentials(username, password) # BiDi end # WebDriver end # Selenium - diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 5cf052bcfff5a..6ac1d64fde02c 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -58,12 +58,12 @@ def add_response_handler(&) private - def add_handler(event_type, phase, intercept_type, &block) + def add_handler(event_type, phase, intercept_type) intercept = network.add_intercept(phases: [phase]) callback_id = network.on(event_type) do |event| request = event['request'] intercepted_item = intercept_type.new(network, request) - block.call(intercepted_item) + yield(intercepted_item) end callbacks[callback_id] = intercept From d9e0ffc999aa056ae0d4f41a46d41e5bcc615c44 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Fri, 3 Jan 2025 13:54:29 +0100 Subject: [PATCH 17/35] Make auth handler more user friendly --- rb/lib/selenium/webdriver/common/network.rb | 11 +++++++++-- .../integration/selenium/webdriver/network_spec.rb | 14 +++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 6ac1d64fde02c..1228f6ff82444 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -44,8 +44,15 @@ def clear_handlers callbacks.each_key { |id| remove_handler(id) } end - def add_authentication_handler(&) - add_handler(:auth_required, BiDi::Network::PHASES[:auth_required], BiDi::InterceptedAuth, &) + def add_authentication_handler(username = nil, password = nil, &block) + selected_block = + if username && password + proc { |auth| auth.authenticate(username, password) } + else + block + end + + add_handler(:auth_required, BiDi::Network::PHASES[:auth_required], BiDi::InterceptedAuth, &selected_block) end def add_request_handler(&) diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 5e43e8cc9cbb7..9dcc2b97fe249 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -29,9 +29,7 @@ module WebDriver it 'adds an auth handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - network.add_authentication_handler do |response| - response.authenticate(username, password) - end + network.add_authentication_handler(username, password) driver.navigate.to url_for('basicAuth') expect(driver.find_element(tag_name: 'h1').text).to eq('authorized') expect(network.callbacks.count).to be 1 @@ -41,9 +39,7 @@ module WebDriver it 'removes an auth handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - id = network.add_authentication_handler do |response| - response.authenticate(username, password) - end + id = network.add_authentication_handler(username, password) network.remove_handler(id) expect(network.callbacks.count).to be 0 end @@ -52,11 +48,7 @@ module WebDriver it 'clears all auth handlers' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) - 2.times do - network.add_authentication_handler do |response| - response.authenticate(username, password) - end - end + 2.times { network.add_authentication_handler(username, password) } network.clear_handlers expect(network.callbacks.count).to be 0 end From 87dc1e6102059916ad3a6ef2771defca6fde2373 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 4 Jan 2025 17:53:16 +0100 Subject: [PATCH 18/35] Add filtering an url pattern support --- rb/lib/selenium/webdriver/bidi/network.rb | 9 +- .../webdriver/bidi/network/url_pattern.rb | 48 ++++++++++ rb/lib/selenium/webdriver/common/network.rb | 37 ++++++-- .../lib/selenium/webdriver/bidi/network.rbs | 6 +- .../webdriver/bidi/network/cookies.rbs | 13 +++ .../webdriver/bidi/network/headers.rbs | 11 +++ .../webdriver/bidi/network/url_pattern.rbs | 13 +++ .../lib/selenium/webdriver/common/network.rbs | 6 +- .../selenium/webdriver/bidi/network_spec.rb | 20 +++++ .../selenium/webdriver/network_spec.rb | 90 +++++++++++++++++++ 10 files changed, 239 insertions(+), 14 deletions(-) create mode 100644 rb/lib/selenium/webdriver/bidi/network/url_pattern.rb create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index c4fff8bcbe250..fcb49359db268 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -16,6 +16,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +require_relative 'network/url_pattern' module Selenium module WebDriver @@ -39,8 +40,12 @@ def initialize(bidi) @bidi = bidi end - def add_intercept(phases: [], contexts: nil, url_patterns: nil) - @bidi.send_cmd('network.addIntercept', phases: phases, contexts: contexts, urlPatterns: url_patterns) + def add_intercept(phases: [], contexts: nil, url_patterns: nil, pattern_type: :string) + url_patterns = url_patterns && pattern_type ? UrlPattern.format_pattern(url_patterns, pattern_type) : nil + @bidi.send_cmd('network.addIntercept', + phases: phases, + contexts: contexts, + urlPatterns: url_patterns) end def remove_intercept(intercept) diff --git a/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb b/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb new file mode 100644 index 0000000000000..c50dbfd52473e --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'uri' + +module Selenium + module WebDriver + class BiDi + module UrlPattern + module_function + + def format_pattern(url_patterns, pattern_type) + case pattern_type + when :string + to_url_string_pattern(url_patterns) + when :url + to_url_pattern(url_patterns) + else + raise ArgumentError, "Unknown pattern type: #{pattern_type}" + end + end + + def to_url_pattern(*url_patterns) + url_patterns.flatten.map do |url_pattern| + uri = URI.parse(url_pattern) + + { + type: 'pattern', + protocol: uri.scheme || '', + hostname: uri.host || '', + port: uri.port.to_s || '', + pathname: uri.path || '', + search: uri.query || '' + } + end + end + + def to_url_string_pattern(*url_patterns) + url_patterns.flatten.map do |url_pattern| + { + type: 'string', + pattern: url_pattern + } + end + end + end + end + end +end diff --git a/rb/lib/selenium/webdriver/common/network.rb b/rb/lib/selenium/webdriver/common/network.rb index 1228f6ff82444..3ac30b6eb68f6 100644 --- a/rb/lib/selenium/webdriver/common/network.rb +++ b/rb/lib/selenium/webdriver/common/network.rb @@ -44,7 +44,7 @@ def clear_handlers callbacks.each_key { |id| remove_handler(id) } end - def add_authentication_handler(username = nil, password = nil, &block) + def add_authentication_handler(username = nil, password = nil, *filter, pattern_type: nil, &block) selected_block = if username && password proc { |auth| auth.authenticate(username, password) } @@ -52,21 +52,42 @@ def add_authentication_handler(username = nil, password = nil, &block) block end - add_handler(:auth_required, BiDi::Network::PHASES[:auth_required], BiDi::InterceptedAuth, &selected_block) + add_handler( + :auth_required, + BiDi::Network::PHASES[:auth_required], + BiDi::InterceptedAuth, + filter, + pattern_type: pattern_type, + &selected_block + ) end - def add_request_handler(&) - add_handler(:before_request, BiDi::Network::PHASES[:before_request], BiDi::InterceptedRequest, &) + def add_request_handler(*filter, pattern_type: nil, &) + add_handler( + :before_request, + BiDi::Network::PHASES[:before_request], + BiDi::InterceptedRequest, + filter, + pattern_type: pattern_type, + & + ) end - def add_response_handler(&) - add_handler(:response_started, BiDi::Network::PHASES[:response_started], BiDi::InterceptedResponse, &) + def add_response_handler(*filter, pattern_type: nil, &) + add_handler( + :response_started, + BiDi::Network::PHASES[:response_started], + BiDi::InterceptedResponse, + filter, + pattern_type: pattern_type, + & + ) end private - def add_handler(event_type, phase, intercept_type) - intercept = network.add_intercept(phases: [phase]) + def add_handler(event_type, phase, intercept_type, filter, pattern_type: nil) + intercept = network.add_intercept(phases: [phase], url_patterns: [filter].flatten, pattern_type: pattern_type) callback_id = network.on(event_type) do |event| request = event['request'] intercepted_item = intercept_type.new(network, request) diff --git a/rb/sig/lib/selenium/webdriver/bidi/network.rbs b/rb/sig/lib/selenium/webdriver/bidi/network.rbs index 31a9859797eaf..659222b52d0a3 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network.rbs @@ -14,12 +14,14 @@ module Selenium def cancel_auth: -> untyped - def continue_with_request: (**untyped args) -> untyped + def continue_request: -> untyped - def continue_with_response: (**untyped args) -> untyped + def continue_response: -> untyped def continue_without_auth: -> untyped + def fail_request: -> untyped + def remove_intercept: (String intercept) -> untyped def continue_with_auth: (String request_id, String username, String password) -> untyped diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs new file mode 100644 index 0000000000000..d803eae4e96ca --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs @@ -0,0 +1,13 @@ +module Selenium + module WebDriver + class BiDi + module Cookies + def add_cookie: (untyped name, untyped value) -> untyped + + def remove_cookie: (untyped name) -> untyped + + def set_cookie_header: (**untyped args) -> untyped + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs new file mode 100644 index 0000000000000..09bf7375ea309 --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs @@ -0,0 +1,11 @@ +module Selenium + module WebDriver + class BiDi + module Headers + def add_header: (untyped name, untyped value) -> untyped + + def remove_header: (untyped name) -> untyped + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs new file mode 100644 index 0000000000000..dcb5af993d51b --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs @@ -0,0 +1,13 @@ +module Selenium + module WebDriver + class BiDi + module UrlPattern + def self?.format_pattern: (untyped url_patterns, untyped pattern_type) -> untyped + + def self?.to_url_pattern: (*untyped url_patterns) -> untyped + + def self?.to_url_string_pattern: (*untyped url_patterns) -> untyped + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index 8e7bb42d4c564..3004f45d30b16 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -21,9 +21,11 @@ module Selenium def clear_handlers: -> Hash[nil, nil] - def fetch_id: -> String - def remove_handler: (Integer id) -> nil + + private + + def add_handler: -> untyped end end end diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index d9ce113a30ea0..c02eee189450d 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -32,6 +32,26 @@ class BiDi end end + it 'adds an intercept with a default pattern type' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + pattern = 'http://localhost:4444/formPage.html' + intercept = network.add_intercept(phases: [described_class::PHASES[:before_request]], url_patterns: pattern) + expect(intercept).not_to be_nil + end + end + + it 'adds an intercept with a url pattern' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + pattern = 'http://localhost:4444/formPage.html' + intercept = network.add_intercept(phases: [described_class::PHASES[:before_request]], + url_patterns: pattern, + pattern_type: :url) + expect(intercept).not_to be_nil + end + end + it 'removes an intercept' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver.bidi) diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 9dcc2b97fe249..48899ce91ac39 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -36,6 +36,36 @@ module WebDriver end end + it 'adds an auth handler with a filter' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_authentication_handler(username, password, url_for('basicAuth')) + driver.navigate.to url_for('basicAuth') + expect(driver.find_element(tag_name: 'h1').text).to eq('authorized') + expect(network.callbacks.count).to be 1 + end + end + + it 'adds an auth handler with multiple filters' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_authentication_handler(username, password, url_for('basicAuth'), url_for('formPage.html')) + driver.navigate.to url_for('basicAuth') + expect(driver.find_element(tag_name: 'h1').text).to eq('authorized') + expect(network.callbacks.count).to be 1 + end + end + + it 'adds an auth handler with a pattern type' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_authentication_handler(username, password, url_for('basicAuth'), pattern_type: :url) + driver.navigate.to url_for('basicAuth') + expect(driver.find_element(tag_name: 'h1').text).to eq('authorized') + expect(network.callbacks.count).to be 1 + end + end + it 'removes an auth handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) @@ -81,6 +111,36 @@ module WebDriver end end + it 'adds a request handler with a filter' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler(url_for('formPage.html'), &:continue) + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + + it 'adds a request handler with multiple filters' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler(url_for('formPage.html'), url_for('basicAuth'), &:continue) + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + + it 'adds a request handler with a pattern type' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_request_handler(url_for('formPage.html'), pattern_type: :url, &:continue) + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + it 'adds a request handler with attributes' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) @@ -158,6 +218,36 @@ module WebDriver end end + it 'adds a response handler with a filter' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler(url_for('formPage.html'), &:continue) + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + + it 'adds a response handler with multiple filters' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler(url_for('formPage.html'), url_for('basicAuth'), &:continue) + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + + it 'adds a response handler with a pattern type' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler(url_for('formPage.html'), pattern_type: :url, &:continue) + driver.navigate.to url_for('formPage.html') + expect(driver.find_element(name: 'login')).to be_displayed + expect(network.callbacks.count).to be 1 + end + end + it 'adds a response handler with attributes' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) From 7c49b935b154988790ba642f4d3c5261217589c4 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 4 Jan 2025 18:11:00 +0100 Subject: [PATCH 19/35] Fix formatting issues --- .../webdriver/bidi/network/url_pattern.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb b/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb index c50dbfd52473e..5008465e63c17 100644 --- a/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb +++ b/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb @@ -1,5 +1,22 @@ # frozen_string_literal: true +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + require 'uri' module Selenium From 37728446055f15f0854976e3c99a48d2e5734185 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 4 Jan 2025 21:12:38 +0100 Subject: [PATCH 20/35] Modify tests to avoid element related failures on firefox --- .../selenium/webdriver/network_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index 48899ce91ac39..be8c85e567060 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -106,7 +106,7 @@ module WebDriver network = described_class.new(driver) network.add_request_handler(&:continue) driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -116,7 +116,7 @@ module WebDriver network = described_class.new(driver) network.add_request_handler(url_for('formPage.html'), &:continue) driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -126,7 +126,7 @@ module WebDriver network = described_class.new(driver) network.add_request_handler(url_for('formPage.html'), url_for('basicAuth'), &:continue) driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -136,7 +136,7 @@ module WebDriver network = described_class.new(driver) network.add_request_handler(url_for('formPage.html'), pattern_type: :url, &:continue) driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -154,7 +154,7 @@ module WebDriver request.continue end driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -213,7 +213,7 @@ module WebDriver network = described_class.new(driver) network.add_response_handler(&:continue) driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -243,7 +243,7 @@ module WebDriver network = described_class.new(driver) network.add_response_handler(url_for('formPage.html'), pattern_type: :url, &:continue) driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end @@ -266,7 +266,7 @@ module WebDriver response.continue end driver.navigate.to url_for('formPage.html') - expect(driver.find_element(name: 'login')).to be_displayed + expect(driver.current_url).to eq(url_for('formPage.html')) expect(network.callbacks.count).to be 1 end end From 0515131865c551ff56a6e9b73c724efb4b8580b2 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 4 Jan 2025 21:35:12 +0100 Subject: [PATCH 21/35] Fix styling of comments --- rb/lib/selenium/webdriver/bidi/network/cookies.rb | 4 +--- .../selenium/webdriver/bidi/network/intercepted_response.rb | 4 +--- rb/lib/selenium/webdriver/bidi/network/url_pattern.rb | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index b21540225c3b3..af70ff7c3ad13 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -52,8 +52,6 @@ def set_cookie_header(**args) ) end end - end - - # BiDi + end # BiDi end # WebDriver end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 230c4a9a442a7..d53c90f9e9f24 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -50,8 +50,6 @@ def add_credentials(username, password) } end end - end - - # BiDi + end # BiDi end # WebDriver end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb b/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb index 5008465e63c17..651d7f95471b2 100644 --- a/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb +++ b/rb/lib/selenium/webdriver/bidi/network/url_pattern.rb @@ -60,6 +60,6 @@ def to_url_string_pattern(*url_patterns) end end end - end - end -end + end # BiDi + end # WebDriver +end # Selenium From eb3f378aef1d5ecacf6fc843358bcd0b4a2b524b Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sun, 5 Jan 2025 16:43:19 +0100 Subject: [PATCH 22/35] Improve types and hash consistency --- rb/lib/selenium/webdriver/bidi/network.rb | 40 +++++++++---------- .../webdriver/bidi/network/cookies.rb | 32 +++++++-------- .../webdriver/bidi/network/headers.rb | 10 ++--- .../bidi/network/intercepted_request.rb | 4 +- .../bidi/network/intercepted_response.rb | 6 +-- .../lib/selenium/webdriver/bidi/network.rbs | 18 ++++----- .../webdriver/bidi/network/cookies.rbs | 6 +-- .../webdriver/bidi/network/headers.rbs | 4 +- .../bidi/network/intercepted_item.rbs | 21 ++++++++++ .../bidi/network/intercepted_request.rbs | 39 ++++++++++++++++++ .../bidi/network/intercepted_response.rbs | 33 +++++++++++++++ .../webdriver/bidi/network/url_pattern.rbs | 6 +-- .../lib/selenium/webdriver/bidi/session.rbs | 2 +- .../lib/selenium/webdriver/common/network.rbs | 18 ++++----- 14 files changed, 166 insertions(+), 73 deletions(-) create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index fcb49359db268..f3074fb6173b7 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -55,12 +55,12 @@ def remove_intercept(intercept) def continue_with_auth(request_id, username, password) @bidi.send_cmd( 'network.continueWithAuth', - 'request' => request_id, - 'action' => 'provideCredentials', - 'credentials' => { - 'type' => 'password', - 'username' => username, - 'password' => password + request: request_id, + action: 'provideCredentials', + credentials: { + type: 'password', + username: username, + password: password } ) end @@ -68,16 +68,16 @@ def continue_with_auth(request_id, username, password) def continue_without_auth(request_id) @bidi.send_cmd( 'network.continueWithAuth', - 'request' => request_id, - 'action' => 'default' + request: request_id, + action: 'default' ) end def cancel_auth(request_id) @bidi.send_cmd( 'network.continueWithAuth', - 'request' => request_id, - 'action' => 'cancel' + request: request_id, + action: 'cancel' ) end @@ -85,11 +85,11 @@ def continue_request(**args) @bidi.send_cmd( 'network.continueRequest', request: args[:id], - 'body' => args[:body], - 'cookies' => args[:cookies], - 'headers' => args[:headers], - 'method' => args[:method], - 'url' => args[:url] + body: args[:body], + cookies: args[:cookies], + headers: args[:headers], + method: args[:method], + url: args[:url] ) end @@ -104,11 +104,11 @@ def continue_response(**args) @bidi.send_cmd( 'network.continueResponse', request: args[:id], - 'cookies' => args[:cookies], - 'credentials' => args[:credentials], - 'headers' => args[:headers], - 'reasonPhrase' => args[:reason], - 'statusCode' => args[:status] + cookies: args[:cookies], + credentials: args[:credentials], + headers: args[:headers], + reasonPhrase: args[:reason], + statusCode: args[:status] ) end diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index af70ff7c3ad13..c210aa0ab7fb8 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -23,32 +23,32 @@ class BiDi module Cookies def add_cookie(name, value) cookies.push( - 'name' => name, - 'value' => { - 'type' => 'string', - 'value' => value + name: name, + value: { + type: 'string', + value: value } ) end def remove_cookie(name) - cookies.delete_if { |cookie| cookie['name'] == name } + cookies.delete_if { |cookie| cookie[:name] == name } end def set_cookie_header(**args) cookies.push( - 'name' => args[:name], - 'value' => { - 'type' => 'string', - 'value' => 'input' + name: args[:name], + value: { + type: 'string', + value: 'input' }, - 'domain' => args[:domain], - 'httpOnly' => args[:http_only], - 'expiry' => args[:expiry], - 'maxAge' => args[:max_age], - 'path' => args[:path], - 'sameSite' => args[:same_site], - 'secure' => args[:secure] + domain: args[:domain], + httpOnly: args[:http_only], + expiry: args[:expiry], + maxAge: args[:max_age], + path: args[:path], + sameSite: args[:same_site], + secure: args[:secure] ) end end diff --git a/rb/lib/selenium/webdriver/bidi/network/headers.rb b/rb/lib/selenium/webdriver/bidi/network/headers.rb index 329f8069cf582..11a968bfcdf12 100644 --- a/rb/lib/selenium/webdriver/bidi/network/headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/headers.rb @@ -23,16 +23,16 @@ class BiDi module Headers def add_header(name, value) headers.push( - 'name' => name, - 'value' => { - 'type' => 'string', - 'value' => value + name: name, + value: { + type: 'string', + value: value } ) end def remove_header(name) - headers.delete_if { |header| header['name'] == name } + headers.delete_if { |header| header[:name] == name } end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index 9e683a6652901..abe27ac3ba7ce 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -49,8 +49,8 @@ def fail def body=(value) @body = { - 'type' => 'string', - 'value' => value.to_json + type: 'string', + value: value.to_json } end end diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index d53c90f9e9f24..765514211194c 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -44,9 +44,9 @@ def continue def add_credentials(username, password) @credentials = { - 'type' => 'password', - 'username' => username, - 'password' => password + type: 'password', + username: username, + password: password } end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network.rbs b/rb/sig/lib/selenium/webdriver/bidi/network.rbs index 659222b52d0a3..71d2588c65750 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network.rbs @@ -10,23 +10,23 @@ module Selenium def initialize: (BiDi bidi) -> void - def add_intercept: (?phases: Array[String], ?contexts: BrowsingContext?, ?url_patterns: untyped?) -> Hash[String, String] + def add_intercept: (?phases: Array[String], ?contexts: BrowsingContext?, ?url_patterns: String | Array[String]?) -> Hash[String, String] - def cancel_auth: -> untyped + def cancel_auth: -> Hash[nil, nil] - def continue_request: -> untyped + def continue_request: -> Hash[nil, nil] - def continue_response: -> untyped + def continue_response: -> Hash[nil, nil] - def continue_without_auth: -> untyped + def continue_without_auth: -> Hash[nil, nil] - def fail_request: -> untyped + def fail_request: -> Hash[nil, nil] - def remove_intercept: (String intercept) -> untyped + def remove_intercept: (String intercept) -> Hash[nil, nil] - def continue_with_auth: (String request_id, String username, String password) -> untyped + def continue_with_auth: (String request_id, String username, String password) -> Hash[nil, nil] - def on: (Symbol event) { (?) -> untyped } -> untyped + def on: (Symbol event) { (?) -> untyped } -> Hash[nil, nil] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs index d803eae4e96ca..290a9290df4eb 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs @@ -2,11 +2,11 @@ module Selenium module WebDriver class BiDi module Cookies - def add_cookie: (untyped name, untyped value) -> untyped + def add_cookie: (String name, String value) -> Array[Hash[Symbol, String]] - def remove_cookie: (untyped name) -> untyped + def remove_cookie: (String name) -> Array[Hash[Symbol, String]] - def set_cookie_header: (**untyped args) -> untyped + def set_cookie_header: (**Hash[Symbol, String | bool | Numeric] args) -> Array[Hash[Symbol, String | bool | Numeric]] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs index 09bf7375ea309..ffa8f887ba7fa 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs @@ -2,9 +2,9 @@ module Selenium module WebDriver class BiDi module Headers - def add_header: (untyped name, untyped value) -> untyped + def add_header: (String name, String value) -> Array[Hash[Symbol, String]] - def remove_header: (untyped name) -> untyped + def remove_header: (String name) -> Array[Hash[Symbol, String]] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs new file mode 100644 index 0000000000000..7babcab9c1edd --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs @@ -0,0 +1,21 @@ +module Selenium + module WebDriver + class BiDi + class InterceptedItem + @network: untyped + + @request: untyped + + @id: untyped + + attr_reader network: untyped + + attr_reader request: untyped + + def initialize: (untyped network, untyped request) -> void + + def id: () -> untyped + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs new file mode 100644 index 0000000000000..439400e5ef352 --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs @@ -0,0 +1,39 @@ +module Selenium + module WebDriver + class BiDi + class InterceptedRequest < InterceptedItem + @body: untyped + + @cookies: untyped + + @headers: untyped + + @method: untyped + + @url: untyped + + include Cookies + + include Headers + + attr_accessor cookies: untyped + + attr_accessor headers: untyped + + attr_accessor method: untyped + + attr_accessor url: untyped + + attr_reader body: untyped + + def initialize: (untyped network, untyped request) -> void + + def continue: () -> untyped + + def fail: () -> untyped + + def body=: (untyped value) -> untyped + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs new file mode 100644 index 0000000000000..db8300f27990d --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs @@ -0,0 +1,33 @@ +module Selenium + module WebDriver + class BiDi + class InterceptedResponse < InterceptedItem + @cookies: untyped + + @headers: untyped + + @credentials: untyped + + @reason: untyped + + include Cookies + + include Headers + + attr_accessor cookies: untyped + + attr_accessor headers: untyped + + attr_accessor reason: untyped + + attr_reader credentials: untyped + + def initialize: (untyped network, untyped request) -> void + + def continue: () -> untyped + + def add_credentials: (untyped username, untyped password) -> untyped + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs index dcb5af993d51b..57353479f69f7 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/url_pattern.rbs @@ -2,11 +2,11 @@ module Selenium module WebDriver class BiDi module UrlPattern - def self?.format_pattern: (untyped url_patterns, untyped pattern_type) -> untyped + def self?.format_pattern: (Array[String] | String url_patterns, Symbol pattern_type) -> Array[Hash[Symbol, String]] - def self?.to_url_pattern: (*untyped url_patterns) -> untyped + def self?.to_url_pattern: (*String url_patterns) -> Array[Hash[Symbol, String]] - def self?.to_url_string_pattern: (*untyped url_patterns) -> untyped + def self?.to_url_string_pattern: (*String url_patterns) -> Array[Hash[Symbol, String]] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/session.rbs b/rb/sig/lib/selenium/webdriver/bidi/session.rbs index 99b94c52afd5b..ecd687ba8e8e6 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/session.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/session.rbs @@ -10,7 +10,7 @@ module Selenium def status: () -> untyped - def subscribe: (untyped events, ?untyped? browsing_contexts) -> untyped + def subscribe: (untyped events, ?untyped? browsing_contexts) -> Hash[nil, nil] def unsubscribe: (untyped events, ?untyped? browsing_contexts) -> untyped end diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index 3004f45d30b16..6660cd390f6a5 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -7,25 +7,25 @@ module Selenium attr_reader callbacks: Hash[String, String] - attr_reader network: untyped + attr_reader network: BiDi::Network - def initialize: (Remote::Bridge bridge) -> void + alias bidi network - def add_authentication_handler: (String username, String password) -> String + def initialize: (Remote::Bridge bridge) -> void - def add_request_handler: -> Integer + def remove_handler: (Numeric id) -> untyped - def add_response_handler: -> String + def clear_handlers: () -> untyped - alias bidi network + def add_authentication_handler: (?String? username, ?String? password, *String filter, ?pattern_type: Symbol?) { (?) -> untyped } -> untyped - def clear_handlers: -> Hash[nil, nil] + def add_request_handler: (*String filter, ?pattern_type: Symbol?) -> Hash[String, String] - def remove_handler: (Integer id) -> nil + def add_response_handler: (*String filter, ?pattern_type: Symbol?) -> Hash[String, String] private - def add_handler: -> untyped + def add_handler: (Symbol event_type, String phase, BiDi::InterceptedItem intercept_type, Array[String] filter, ?pattern_type: Symbol?) { (untyped) -> untyped } -> untyped end end end From 296105e053f1c750ab8bc6008dba8e2d1fe639c6 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Fri, 10 Jan 2025 23:49:32 +0100 Subject: [PATCH 23/35] Update all the places that use 9.4.8.0 --- .github/workflows/ci-rbe.yml | 4 ++-- .github/workflows/ci-renovate-rbe.yml | 4 ++-- .github/workflows/ci-ruby.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-rbe.yml b/.github/workflows/ci-rbe.yml index e5b89ac0b7f59..44ac497e10906 100644 --- a/.github/workflows/ci-rbe.yml +++ b/.github/workflows/ci-rbe.yml @@ -15,7 +15,7 @@ jobs: with: name: Check format script run caching: false - ruby-version: jruby-9.4.8.0 + ruby-version: jruby-9.4.9.0 run: ./scripts/github-actions/check-format.sh test: @@ -25,5 +25,5 @@ jobs: with: name: All RBE tests caching: false - ruby-version: jruby-9.4.8.0 + ruby-version: jruby-9.4.9.0 run: ./scripts/github-actions/ci-build.sh diff --git a/.github/workflows/ci-renovate-rbe.yml b/.github/workflows/ci-renovate-rbe.yml index 46d5617758ddb..e15fb67aaf119 100644 --- a/.github/workflows/ci-renovate-rbe.yml +++ b/.github/workflows/ci-renovate-rbe.yml @@ -47,7 +47,7 @@ jobs: with: name: Check format script run caching: false - ruby-version: jruby-9.4.8.0 + ruby-version: jruby-9.4.9.0 run: ./scripts/github-actions/check-format.sh test: @@ -58,7 +58,7 @@ jobs: with: name: All RBE tests caching: false - ruby-version: jruby-9.4.8.0 + ruby-version: jruby-9.4.9.0 run: ./scripts/github-actions/ci-build.sh ci-gh: diff --git a/.github/workflows/ci-ruby.yml b/.github/workflows/ci-ruby.yml index 88cf3512ebfba..434308154a2a2 100644 --- a/.github/workflows/ci-ruby.yml +++ b/.github/workflows/ci-ruby.yml @@ -47,7 +47,7 @@ jobs: os: macos - ruby-version: 3.3.5 os: ubuntu - - ruby-version: jruby-9.4.8.0 + - ruby-version: jruby-9.4.9.0 os: ubuntu - ruby-version: truffleruby-24.1.1 os: ubuntu From c7552aa6546681ed58c35c7fb33ac7417502952f Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 11 Jan 2025 20:23:51 +0100 Subject: [PATCH 24/35] Serialize request values --- .../webdriver/bidi/network/cookies.rb | 61 +++--- .../webdriver/bidi/network/credentials.rb | 43 +++++ .../webdriver/bidi/network/headers.rb | 44 ++++- .../bidi/network/intercepted_request.rb | 27 ++- .../bidi/network/intercepted_response.rb | 36 ++-- .../bidi/network/set_cookie_headers.rb | 94 ++++++++++ .../webdriver/bidi/network/cookies.rbs | 20 +- .../webdriver/bidi/network/credentials.rbs | 19 ++ .../webdriver/bidi/network/headers.rbs | 20 +- .../bidi/network/intercepted_request.rbs | 19 +- .../bidi/network/intercepted_response.rbs | 22 +-- .../selenium/webdriver/network_spec.rb | 29 +-- .../selenium/webdriver/bidi/cookies_spec.rb | 119 ++++++++++++ .../webdriver/bidi/credentials_spec.rb | 80 ++++++++ .../selenium/webdriver/bidi/headers_spec.rb | 121 ++++++++++++ .../webdriver/bidi/set_cookie_headers_spec.rb | 176 ++++++++++++++++++ 16 files changed, 826 insertions(+), 104 deletions(-) create mode 100644 rb/lib/selenium/webdriver/bidi/network/credentials.rb create mode 100644 rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs create mode 100644 rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb create mode 100644 rb/spec/unit/selenium/webdriver/bidi/credentials_spec.rb create mode 100644 rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb create mode 100644 rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index c210aa0ab7fb8..fe21d7328bdc4 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -20,36 +20,45 @@ module Selenium module WebDriver class BiDi - module Cookies + class Cookies + def initialize + @cookies = {} + end + + def all + @cookies + end + def add_cookie(name, value) - cookies.push( - name: name, - value: { - type: 'string', - value: value - } - ) + @cookies[name] = value end def remove_cookie(name) - cookies.delete_if { |cookie| cookie[:name] == name } - end - - def set_cookie_header(**args) - cookies.push( - name: args[:name], - value: { - type: 'string', - value: 'input' - }, - domain: args[:domain], - httpOnly: args[:http_only], - expiry: args[:expiry], - maxAge: args[:max_age], - path: args[:path], - sameSite: args[:same_site], - secure: args[:secure] - ) + @cookies.delete(name) + end + + def []=(key, value) + add_cookie(key, value) + end + + def [](key) + @cookies[key] + end + + def delete(key) + remove_cookie(key) + end + + def serialize + @cookies.map do |name, value| + { + name: name.to_s, + value: { + type: 'string', + value: value.to_s + } + } + end end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/credentials.rb b/rb/lib/selenium/webdriver/bidi/network/credentials.rb new file mode 100644 index 0000000000000..7cabcb809f378 --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/credentials.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + class Credentials + attr_accessor :username, :password + + def initialize(username: nil, password: nil) + @username = username + @password = password + end + + def serialize + return nil unless username && password + + { + type: 'password', + username: username, + password: password + } + end + end + end # BiDi + end # WebDriver +end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/network/headers.rb b/rb/lib/selenium/webdriver/bidi/network/headers.rb index 11a968bfcdf12..3918d65a555ae 100644 --- a/rb/lib/selenium/webdriver/bidi/network/headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/headers.rb @@ -20,19 +20,45 @@ module Selenium module WebDriver class BiDi - module Headers + class Headers + def initialize + @headers = {} + end + + def all + @headers + end + def add_header(name, value) - headers.push( - name: name, - value: { - type: 'string', - value: value - } - ) + @headers[name] = value end def remove_header(name) - headers.delete_if { |header| header[:name] == name } + @headers.delete(name) + end + + def []=(key, value) + add_header(key, value) + end + + def [](key) + @headers[key] + end + + def delete(key) + remove_header(key) + end + + def serialize + @headers.map do |name, val| + { + name: name.to_s, + value: { + type: 'string', + value: val.to_s + } + } + end end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index abe27ac3ba7ce..7348e7886f5d3 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -24,23 +24,26 @@ module Selenium module WebDriver class BiDi class InterceptedRequest < InterceptedItem - include Cookies - include Headers - - attr_accessor :cookies, :headers, :method, :url + attr_accessor :method, :url attr_reader :body def initialize(network, request) super - @body = nil - @cookies = [] - @headers = [] + # We now rely on the modules above to initialize @headers and @cookies as Hashes @method = nil @url = nil + @body = nil end def continue - network.continue_request(id:, body:, cookies:, headers:, method:, url:) + network.continue_request( + id: id, + body: body, + cookies: cookies.serialize, + headers: headers.serialize, + method: method, + url: url + ) end def fail @@ -53,6 +56,14 @@ def body=(value) value: value.to_json } end + + def headers + @headers ||= Headers.new + end + + def cookies + @cookies ||= Cookies.new + end end end # BiDi end # WebDriver diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 765514211194c..2f3c3925acfd5 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -17,37 +17,41 @@ # specific language governing permissions and limitations # under the License. -require_relative 'cookies' +require_relative 'credentials' require_relative 'headers' +require_relative 'set_cookie_headers' module Selenium module WebDriver class BiDi class InterceptedResponse < InterceptedItem - include Cookies - include Headers - - attr_accessor :cookies, :headers, :reason - attr_reader :credentials + attr_accessor :reason def initialize(network, request) super - @cookies = [] - @headers = [] - @credentials = nil @reason = nil end def continue - network.continue_response(id:, cookies:, headers:, credentials:, reason:) + network.continue_response( + id: id, + cookies: set_cookie_headers.serialize, + headers: headers.serialize, + credentials: credentials.serialize, + reason: reason + ) + end + + def credentials(username: nil, password: nil) + @credentials ||= Credentials.new(username: username, password: password) + end + + def headers + @headers ||= Headers.new end - def add_credentials(username, password) - @credentials = { - type: 'password', - username: username, - password: password - } + def set_cookie_headers(set_cookie_headers = nil) + @set_cookie_headers ||= SetCookieHeaders.new(set_cookie_headers) end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb new file mode 100644 index 0000000000000..b7f77bfc4548a --- /dev/null +++ b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class BiDi + class SetCookieHeaders + def initialize(set_cookie_headers) + @set_cookie_headers = set_cookie_headers + end + + def all + @set_cookie_headers + end + + def add_set_cookie_header(name, value) + @set_cookie_headers[name] = {value: value} + end + + def remove_set_cookie_header(name) + @set_cookie_headers.delete(name) + end + + def set_cookie_header(**args) + set_cookie_header = args[:name] + + set_cookie_header_data = { + value: 'input', + domain: args[:domain], + httpOnly: args[:http_only], + expiry: args[:expiry], + maxAge: args[:max_age], + path: args[:path], + sameSite: args[:same_site], + secure: args[:secure] + } + + @set_cookie_headers[set_cookie_header] = set_cookie_header_data + end + + def []=(key, value) + add_set_cookie_header(key, value) + end + + def [](key) + @set_cookie_headers[key] + end + + def delete(key) + remove_set_cookie_header(key) + end + + def serialize + return [] unless @set_cookie_headers + + @set_cookie_headers.map do |name, data| + data = {value: data} unless data.is_a?(Hash) + + { + name: name.to_s, + value: { + type: 'string', + value: data[:value].to_s + }, + domain: data[:domain], + httpOnly: data[:httpOnly], + expiry: data[:expiry], + maxAge: data[:maxAge], + path: data[:path], + sameSite: data[:sameSite], + secure: data[:secure] + }.compact + end + end + end + end # BiDi + end # WebDriver +end # Selenium diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs index 290a9290df4eb..faaf62df2a6cd 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs @@ -1,12 +1,24 @@ module Selenium module WebDriver class BiDi - module Cookies - def add_cookie: (String name, String value) -> Array[Hash[Symbol, String]] + class Cookies + @cookies: untyped - def remove_cookie: (String name) -> Array[Hash[Symbol, String]] + def initialize: () -> void - def set_cookie_header: (**Hash[Symbol, String | bool | Numeric] args) -> Array[Hash[Symbol, String | bool | Numeric]] + def all: () -> untyped + + def add_cookie: (untyped name, untyped value) -> untyped + + def remove_cookie: (untyped name) -> untyped + + def []=: (untyped key, untyped value) -> untyped + + def []: (untyped key) -> untyped + + def delete: (untyped key) -> untyped + + def serialize: () -> untyped end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs new file mode 100644 index 0000000000000..5fd4e263f4107 --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs @@ -0,0 +1,19 @@ +module Selenium + module WebDriver + class BiDi + class Credentials + @username: untyped + + @password: untyped + + attr_accessor username: untyped + + attr_accessor password: untyped + + def initialize: (?username: untyped?, ?password: untyped?) -> void + + def serialize: () -> (nil | { type: "password", username: untyped, password: untyped }) + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs index ffa8f887ba7fa..cf9155eca53e1 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs @@ -1,10 +1,24 @@ module Selenium module WebDriver class BiDi - module Headers - def add_header: (String name, String value) -> Array[Hash[Symbol, String]] + class Headers + @headers: untyped - def remove_header: (String name) -> Array[Hash[Symbol, String]] + def initialize: () -> void + + def all: () -> untyped + + def add_header: (untyped name, untyped value) -> untyped + + def remove_header: (untyped name) -> untyped + + def []=: (untyped key, untyped value) -> untyped + + def []: (untyped key) -> untyped + + def delete: (untyped key) -> untyped + + def serialize: () -> untyped end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs index 439400e5ef352..b38b4288a368d 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs @@ -2,23 +2,16 @@ module Selenium module WebDriver class BiDi class InterceptedRequest < InterceptedItem - @body: untyped - - @cookies: untyped - - @headers: untyped - + # We now rely on the modules above to initialize @headers and @cookies as Hashes @method: untyped @url: untyped - include Cookies - - include Headers + @body: untyped - attr_accessor cookies: untyped + @headers: untyped - attr_accessor headers: untyped + @cookies: untyped attr_accessor method: untyped @@ -33,6 +26,10 @@ module Selenium def fail: () -> untyped def body=: (untyped value) -> untyped + + def headers: () -> untyped + + def cookies: () -> untyped end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs index db8300f27990d..6c55f8c73494d 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs @@ -2,31 +2,25 @@ module Selenium module WebDriver class BiDi class InterceptedResponse < InterceptedItem - @cookies: untyped - - @headers: untyped - - @credentials: untyped - @reason: untyped - include Cookies - - include Headers + @credentials: untyped - attr_accessor cookies: untyped + @headers: untyped - attr_accessor headers: untyped + @set_cookie_headers: untyped attr_accessor reason: untyped - attr_reader credentials: untyped - def initialize: (untyped network, untyped request) -> void def continue: () -> untyped - def add_credentials: (untyped username, untyped password) -> untyped + def credentials: (?username: untyped?, ?password: untyped?) -> untyped + + def headers: () -> untyped + + def set_cookie_headers: (?untyped? set_cookie_headers) -> untyped end end end diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index be8c85e567060..d86c670f700b4 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -147,9 +147,9 @@ module WebDriver network.add_request_handler do |request| request.method = 'GET' request.url = url_for('formPage.html') - request.add_header('foo', 'bar') - request.add_header('baz', 'qux') - request.add_cookie('foo', 'bar') + request.headers['foo'] = 'bar' + request.headers['baz'] = 'qux' + request.cookies['foo'] = 'bar' request.body = ({test: 'example'}) request.continue end @@ -253,16 +253,19 @@ module WebDriver network = described_class.new(driver) network.add_response_handler do |response| response.reason = 'OK' - response.add_header('foo', 'bar') - response.set_cookie_header(name: 'foo', - domain: 'localhost', - http_only: true, - expiry: '1_000_000', - max_age: 1_000, - path: '/', - same_site: 'none', - secure: false) - response.add_credentials('foo', 'bar') + response.headers['foo'] = 'bar' + response.credentials.username = 'foo' + response.credentials.password = 'bar' + response.set_cookie_headers({ + name: 'foo', + domain: 'localhost', + http_only: true, + expiry: '1_000_000', + max_age: 1_000, + path: '/', + same_site: 'none', + secure: false + }) response.continue end driver.navigate.to url_for('formPage.html') diff --git a/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb new file mode 100644 index 0000000000000..c034d297d41a9 --- /dev/null +++ b/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +require File.expand_path('../spec_helper', __dir__) +require File.expand_path('../../../../../lib/selenium/webdriver/bidi/network/cookies', __dir__) + +module Selenium + module WebDriver + class BiDi + describe Cookies do + let(:cookies) { described_class.new } + + describe '#initialize' do + it 'initializes an empty cookies hash' do + expect(cookies.all).to eq({}) + end + end + + describe '#all' do + it 'returns the underlying cookies hash' do + cookies.add_cookie('session_id', 'abc123') + expect(cookies.all).to eq({'session_id' => 'abc123'}) + end + end + + describe '#add_cookie' do + it 'adds a cookie to the internal store' do + cookies.add_cookie('foo', 'bar') + expect(cookies['foo']).to eq('bar') + end + + it 'updates an existing cookie if the name already exists' do + cookies.add_cookie('foo', 'bar') + cookies.add_cookie('foo', 'baz') + expect(cookies['foo']).to eq('baz') + end + end + + describe '#remove_cookie' do + it 'removes a cookie by name' do + cookies.add_cookie('foo', 'bar') + cookies.remove_cookie('foo') + expect(cookies['foo']).to be_nil + end + + it 'does not raise an error if cookie does not exist' do + expect { cookies.remove_cookie('non_existent') }.not_to raise_error + end + end + + describe '#[]=' do + it 'adds a cookie using bracket assignment' do + cookies['key1'] = 'value1' + expect(cookies['key1']).to eq('value1') + end + end + + describe '#[]' do + it 'retrieves the value of a cookie by name' do + cookies['key2'] = 'value2' + expect(cookies['key2']).to eq('value2') + end + + it 'returns nil for unknown cookies' do + expect(cookies['does_not_exist']).to be_nil + end + end + + describe '#delete' do + it 'removes a cookie via bracket-based delete' do + cookies['key3'] = 'value3' + cookies.delete('key3') + expect(cookies['key3']).to be_nil + end + end + + describe '#serialize' do + it 'returns an array of cookie hashes in the minimal format' do + cookies['key4'] = 'value4' + cookies.add_cookie('session_id', 'xyz123') + + serialized = cookies.serialize + expect(serialized).to be_an(Array) + expect(serialized.size).to eq(2) + + key4_item = serialized.find { |h| h[:name] == 'key4' } + expect(key4_item).not_to be_nil + expect(key4_item[:value][:type]).to eq('string') + expect(key4_item[:value][:value]).to eq('value4') + + session_item = serialized.find { |h| h[:name] == 'session_id' } + expect(session_item).not_to be_nil + expect(session_item[:value][:value]).to eq('xyz123') + end + + it 'returns an empty array if no cookies are set' do + expect(cookies.serialize).to eq([]) + end + end + end + end + end +end diff --git a/rb/spec/unit/selenium/webdriver/bidi/credentials_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/credentials_spec.rb new file mode 100644 index 0000000000000..3d6cc7ae17082 --- /dev/null +++ b/rb/spec/unit/selenium/webdriver/bidi/credentials_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +require File.expand_path('../spec_helper', __dir__) +require File.expand_path('../../../../../lib/selenium/webdriver/bidi/network/credentials', __dir__) + +module Selenium + module WebDriver + class BiDi + describe Credentials do + describe '#initialize' do + it 'initializes with nil username/password by default' do + creds = described_class.new + expect(creds.username).to be_nil + expect(creds.password).to be_nil + end + + it 'allows initialization with username and password' do + creds = described_class.new(username: 'alice', password: 'secret') + expect(creds.username).to eq('alice') + expect(creds.password).to eq('secret') + end + end + + describe '#username / #password' do + it 'allows setting and retrieving username' do + creds = described_class.new + creds.username = 'bob' + expect(creds.username).to eq('bob') + end + + it 'allows setting and retrieving password' do + creds = described_class.new + creds.password = 'my_password' + expect(creds.password).to eq('my_password') + end + end + + describe '#serialize' do + it 'returns nil if username is missing' do + creds = described_class.new(password: 'secret') + expect(creds.serialize).to be_nil + end + + it 'returns nil if password is missing' do + creds = described_class.new(username: 'alice') + expect(creds.serialize).to be_nil + end + + it 'returns a hash of the credentials when both username and password are present' do + creds = described_class.new(username: 'alice', password: 'secret') + serialized = creds.serialize + + expect(serialized).to eq( + type: 'password', + username: 'alice', + password: 'secret' + ) + end + end + end + end + end +end diff --git a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb new file mode 100644 index 0000000000000..51ede9de0e3b3 --- /dev/null +++ b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +require File.expand_path('../spec_helper', __dir__) +require File.expand_path('../../../../../lib/selenium/webdriver/bidi/network/headers', __dir__) + +module Selenium + module WebDriver + class BiDi + describe Headers do + let(:headers) { described_class.new } + + describe '#initialize' do + it 'initializes an empty headers hash' do + expect(headers.all).to eq({}) + end + end + + describe '#all' do + it 'returns the underlying headers hash' do + headers.add_header('Authorization', 'Bearer abc123') + expect(headers.all).to eq({'Authorization' => 'Bearer abc123'}) + end + end + + describe '#add_header' do + it 'adds a header to the internal store' do + headers.add_header('Content-Type', 'application/json') + expect(headers['Content-Type']).to eq('application/json') + end + + it 'updates an existing header if the name already exists' do + headers.add_header('Content-Type', 'text/html') + headers.add_header('Content-Type', 'application/json') + expect(headers['Content-Type']).to eq('application/json') + end + end + + describe '#remove_header' do + it 'removes a header by name' do + headers.add_header('X-Custom-Header', 'foo') + headers.remove_header('X-Custom-Header') + expect(headers['X-Custom-Header']).to be_nil + end + + it 'does not raise an error if header does not exist' do + expect { headers.remove_header('Non-Existent') }.not_to raise_error + end + end + + describe '#[]=' do + it 'adds or updates a header using bracket assignment' do + headers['Cache-Control'] = 'no-cache' + expect(headers['Cache-Control']).to eq('no-cache') + + headers['Cache-Control'] = 'private' + expect(headers['Cache-Control']).to eq('private') + end + end + + describe '#[]' do + it 'retrieves the value of a header by name' do + headers['Host'] = 'example.com' + expect(headers['Host']).to eq('example.com') + end + + it 'returns nil for unknown headers' do + expect(headers['Does-Not-Exist']).to be_nil + end + end + + describe '#delete' do + it 'removes a header via bracket-based delete' do + headers['Accept'] = 'text/html' + headers.delete('Accept') + expect(headers['Accept']).to be_nil + end + end + + describe '#serialize' do + it 'returns an array of header hashes in the correct format' do + headers['Accept'] = 'application/json' + headers.add_header('User-Agent', 'MyAgent/1.0') + + serialized = headers.serialize + expect(serialized).to be_an(Array) + expect(serialized.size).to eq(2) + + accept_item = serialized.find { |h| h[:name] == 'Accept' } + expect(accept_item).not_to be_nil + expect(accept_item[:value]).to eq({type: 'string', value: 'application/json'}) + + ua_item = serialized.find { |h| h[:name] == 'User-Agent' } + expect(ua_item).not_to be_nil + expect(ua_item[:value]).to eq({type: 'string', value: 'MyAgent/1.0'}) + end + + it 'returns an empty array if no headers are set' do + expect(headers.serialize).to eq([]) + end + end + end + end + end +end diff --git a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb new file mode 100644 index 0000000000000..9b0603acb5a5f --- /dev/null +++ b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb @@ -0,0 +1,176 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +require File.expand_path('../spec_helper', __dir__) +require File.expand_path('../../../../../lib/selenium/webdriver/bidi/network/set_cookie_headers', __dir__) + +module Selenium + module WebDriver + class BiDi + describe SetCookieHeaders do + let(:initial_hash) { {} } + let(:cookie_headers) { described_class.new(initial_hash) } + + describe '#initialize' do + it 'stores the passed set_cookie_headers hash internally' do + my_hash = {'first_cookie' => {value: 'abc123'}} + cookie_headers = described_class.new(my_hash) + expect(cookie_headers.all).to eq(my_hash) + end + end + + describe '#all' do + it 'returns the entire internal set_cookie_headers hash' do + cookie_headers.add_set_cookie_header('cookie1', 'value1') + expect(cookie_headers.all).to eq({'cookie1' => {value: 'value1'}}) + end + end + + describe '#add_set_cookie_header' do + it 'adds a cookie header to the internal store with a default hash' do + cookie_headers.add_set_cookie_header('name', 'chocolate_chip') + expect(cookie_headers['name']).to eq({value: 'chocolate_chip'}) + end + + it 'overwrites an existing cookie header if the name already exists' do + cookie_headers.add_set_cookie_header('cookie_name', 'old_value') + cookie_headers.add_set_cookie_header('cookie_name', 'new_value') + expect(cookie_headers['cookie_name']).to eq({value: 'new_value'}) + end + end + + describe '#remove_set_cookie_header' do + it 'removes the named cookie header' do + cookie_headers.add_set_cookie_header('session_id', 'abc123') + cookie_headers.remove_set_cookie_header('session_id') + expect(cookie_headers['session_id']).to be_nil + end + + it 'does not raise an error if the cookie header does not exist' do + expect { cookie_headers.remove_set_cookie_header('non_existent') }.not_to raise_error + end + end + + describe '#set_cookie_header' do + it 'stores a cookie header with extended attributes' do + cookie_headers.set_cookie_header( + name: 'test_cookie', + domain: 'example.com', + path: '/', + http_only: true, + expiry: 1_700_000_000, + max_age: 3600, + same_site: 'None', + secure: true + ) + + data = cookie_headers['test_cookie'] + expect(data[:domain]).to eq('example.com') + expect(data[:path]).to eq('/') + expect(data[:httpOnly]).to be(true) + expect(data[:expiry]).to eq(1_700_000_000) + expect(data[:maxAge]).to eq(3600) + expect(data[:sameSite]).to eq('None') + expect(data[:secure]).to be(true) + end + + it 'uses "input" as the literal value for :value, per original code' do + cookie_headers.set_cookie_header(name: 'my_cookie') + expect(cookie_headers['my_cookie'][:value]).to eq('input') + end + end + + describe '#[]=' do + it 'adds or updates a cookie header via bracket assignment' do + cookie_headers['key1'] = 'value1' + expect(cookie_headers['key1']).to eq({value: 'value1'}) + + cookie_headers['key1'] = 'updated_value' + expect(cookie_headers['key1']).to eq({value: 'updated_value'}) + end + end + + describe '#[]' do + it 'retrieves the cookie header hash by name' do + cookie_headers['key2'] = 'value2' + expect(cookie_headers['key2']).to eq({value: 'value2'}) + end + + it 'returns nil if the cookie header does not exist' do + expect(cookie_headers['does_not_exist']).to be_nil + end + end + + describe '#delete' do + it 'removes a cookie header via bracket-based delete' do + cookie_headers['key3'] = 'value3' + cookie_headers.delete('key3') + expect(cookie_headers['key3']).to be_nil + end + end + + describe '#serialize' do + context 'when set_cookie_headers is nil' do + let(:initial_hash) { nil } + + it 'returns an empty array if no set_cookie_headers are provided' do + expect(cookie_headers.serialize).to eq([]) + end + end + + context 'when set_cookie_headers is a hash' do + it 'returns an array of cookie header hashes with the specified format' do + cookie_headers.set_cookie_header( + name: 'test_cookie', + domain: 'example.com', + path: '/', + http_only: true, + expiry: 1_700_000_000 + ) + cookie_headers.add_set_cookie_header('second_cookie', 'second_value') + + serialized = cookie_headers.serialize + expect(serialized).to be_an(Array) + expect(serialized.size).to eq(2) + + # Check first cookie (extended fields) + test_item = serialized.find { |h| h[:name] == 'test_cookie' } + expect(test_item).not_to be_nil + expect(test_item[:value]).to eq(type: 'string', value: 'input') + expect(test_item[:domain]).to eq('example.com') + expect(test_item[:path]).to eq('/') + expect(test_item[:httpOnly]).to be(true) + expect(test_item[:expiry]).to eq(1_700_000_000) + + # Check second cookie (just a simple string) + second_item = serialized.find { |h| h[:name] == 'second_cookie' } + expect(second_item).not_to be_nil + expect(second_item[:value]).to eq(type: 'string', value: 'second_value') + expect(second_item[:domain]).to be_nil + end + + it 'returns an empty array if the internal hash is empty' do + expect(cookie_headers.serialize).to eq([]) + end + end + end + end + end + end +end From ab0f4c23c30726f0db3817b3d4c20e228a35eda6 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 11 Jan 2025 21:48:10 +0100 Subject: [PATCH 25/35] Refactor cookies, headers and set cookie headers --- .../webdriver/bidi/network/cookies.rb | 22 ++-- .../webdriver/bidi/network/headers.rb | 12 +- .../bidi/network/intercepted_request.rb | 4 +- .../bidi/network/intercepted_response.rb | 2 +- .../bidi/network/set_cookie_headers.rb | 31 +---- .../webdriver/bidi/network/cookies.rbs | 6 +- .../webdriver/bidi/network/headers.rbs | 4 - .../bidi/network/set_cookie_headers.rbs | 23 ++++ .../selenium/webdriver/bidi/cookies_spec.rb | 24 ++-- .../selenium/webdriver/bidi/headers_spec.rb | 16 +-- .../webdriver/bidi/set_cookie_headers_spec.rb | 116 ++++-------------- 11 files changed, 91 insertions(+), 169 deletions(-) create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index fe21d7328bdc4..9a379c457d9bc 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -21,24 +21,16 @@ module Selenium module WebDriver class BiDi class Cookies - def initialize - @cookies = {} + def initialize(cookies = {}) + @cookies = cookies end def all @cookies end - def add_cookie(name, value) - @cookies[name] = value - end - - def remove_cookie(name) - @cookies.delete(name) - end - def []=(key, value) - add_cookie(key, value) + @cookies[key] = value end def [](key) @@ -46,10 +38,12 @@ def [](key) end def delete(key) - remove_cookie(key) + @cookies.delete(key) end def serialize + return [] unless @cookies + @cookies.map do |name, value| { name: name.to_s, @@ -61,6 +55,8 @@ def serialize end end end - end # BiDi + end + + # BiDi end # WebDriver end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/network/headers.rb b/rb/lib/selenium/webdriver/bidi/network/headers.rb index 3918d65a555ae..3221f8d64a9d8 100644 --- a/rb/lib/selenium/webdriver/bidi/network/headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/headers.rb @@ -29,16 +29,8 @@ def all @headers end - def add_header(name, value) - @headers[name] = value - end - - def remove_header(name) - @headers.delete(name) - end - def []=(key, value) - add_header(key, value) + @headers[key] = value end def [](key) @@ -46,7 +38,7 @@ def [](key) end def delete(key) - remove_header(key) + @headers.delete(key) end def serialize diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index 7348e7886f5d3..a1716f2d7d3f5 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -61,8 +61,8 @@ def headers @headers ||= Headers.new end - def cookies - @cookies ||= Cookies.new + def cookies(cookies = {}) + @cookies ||= Cookies.new(cookies) end end end # BiDi diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 2f3c3925acfd5..5cc2b484a45ca 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -50,7 +50,7 @@ def headers @headers ||= Headers.new end - def set_cookie_headers(set_cookie_headers = nil) + def set_cookie_headers(set_cookie_headers = {}) @set_cookie_headers ||= SetCookieHeaders.new(set_cookie_headers) end end diff --git a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb index b7f77bfc4548a..a886389c8cf6e 100644 --- a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb @@ -21,7 +21,7 @@ module Selenium module WebDriver class BiDi class SetCookieHeaders - def initialize(set_cookie_headers) + def initialize(set_cookie_headers = {}) @set_cookie_headers = set_cookie_headers end @@ -29,33 +29,8 @@ def all @set_cookie_headers end - def add_set_cookie_header(name, value) - @set_cookie_headers[name] = {value: value} - end - - def remove_set_cookie_header(name) - @set_cookie_headers.delete(name) - end - - def set_cookie_header(**args) - set_cookie_header = args[:name] - - set_cookie_header_data = { - value: 'input', - domain: args[:domain], - httpOnly: args[:http_only], - expiry: args[:expiry], - maxAge: args[:max_age], - path: args[:path], - sameSite: args[:same_site], - secure: args[:secure] - } - - @set_cookie_headers[set_cookie_header] = set_cookie_header_data - end - def []=(key, value) - add_set_cookie_header(key, value) + @set_cookie_headers[key] = {value: value} end def [](key) @@ -63,7 +38,7 @@ def [](key) end def delete(key) - remove_set_cookie_header(key) + @set_cookie_headers.delete(key) end def serialize diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs index faaf62df2a6cd..1f1bd8beb906f 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs @@ -4,14 +4,10 @@ module Selenium class Cookies @cookies: untyped - def initialize: () -> void + def initialize: (untyped cookies) -> void def all: () -> untyped - def add_cookie: (untyped name, untyped value) -> untyped - - def remove_cookie: (untyped name) -> untyped - def []=: (untyped key, untyped value) -> untyped def []: (untyped key) -> untyped diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs index cf9155eca53e1..ce8b9068c9c82 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs @@ -8,10 +8,6 @@ module Selenium def all: () -> untyped - def add_header: (untyped name, untyped value) -> untyped - - def remove_header: (untyped name) -> untyped - def []=: (untyped key, untyped value) -> untyped def []: (untyped key) -> untyped diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs new file mode 100644 index 0000000000000..cdc9761ed7869 --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs @@ -0,0 +1,23 @@ +module Selenium + module WebDriver + class BiDi + class SetCookieHeaders + @set_cookie_headers: untyped + + def initialize: (untyped set_cookie_headers) -> void + + def all: () -> untyped + + def set_cookie_header: (**untyped args) -> untyped + + def []=: (untyped key, untyped value) -> untyped + + def []: (untyped key) -> untyped + + def delete: (untyped key) -> untyped + + def serialize: () -> (::Array[untyped] | untyped) + end + end + end +end diff --git a/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb index c034d297d41a9..0af7ec4bef471 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb @@ -27,40 +27,46 @@ class BiDi let(:cookies) { described_class.new } describe '#initialize' do - it 'initializes an empty cookies hash' do + it 'initializes with an empty hash by default' do expect(cookies.all).to eq({}) end + + it 'stores the passed cookie hash internally' do + my_hash = {'foo' => {value: 'bar'}} + cookie_headers = described_class.new(my_hash) + expect(cookie_headers.all).to eq(my_hash) + end end describe '#all' do it 'returns the underlying cookies hash' do - cookies.add_cookie('session_id', 'abc123') + cookies['session_id'] = 'abc123' expect(cookies.all).to eq({'session_id' => 'abc123'}) end end describe '#add_cookie' do it 'adds a cookie to the internal store' do - cookies.add_cookie('foo', 'bar') + cookies['foo'] = 'bar' expect(cookies['foo']).to eq('bar') end it 'updates an existing cookie if the name already exists' do - cookies.add_cookie('foo', 'bar') - cookies.add_cookie('foo', 'baz') + cookies['foo'] = 'bar' + cookies['foo'] = 'baz' expect(cookies['foo']).to eq('baz') end end describe '#remove_cookie' do it 'removes a cookie by name' do - cookies.add_cookie('foo', 'bar') - cookies.remove_cookie('foo') + cookies['foo'] = 'bar' + cookies.delete('foo') expect(cookies['foo']).to be_nil end it 'does not raise an error if cookie does not exist' do - expect { cookies.remove_cookie('non_existent') }.not_to raise_error + expect { cookies.delete('non_existent') }.not_to raise_error end end @@ -93,7 +99,7 @@ class BiDi describe '#serialize' do it 'returns an array of cookie hashes in the minimal format' do cookies['key4'] = 'value4' - cookies.add_cookie('session_id', 'xyz123') + cookies['session_id'] = 'xyz123' serialized = cookies.serialize expect(serialized).to be_an(Array) diff --git a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb index 51ede9de0e3b3..058530680547f 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb @@ -34,33 +34,33 @@ class BiDi describe '#all' do it 'returns the underlying headers hash' do - headers.add_header('Authorization', 'Bearer abc123') + headers['Authorization'] = 'Bearer abc123' expect(headers.all).to eq({'Authorization' => 'Bearer abc123'}) end end describe '#add_header' do it 'adds a header to the internal store' do - headers.add_header('Content-Type', 'application/json') + headers['Content-Type'] = 'application/json' expect(headers['Content-Type']).to eq('application/json') end it 'updates an existing header if the name already exists' do - headers.add_header('Content-Type', 'text/html') - headers.add_header('Content-Type', 'application/json') + headers['Content-Type'] = 'text/html' + headers['Content-Type'] = 'application/json' expect(headers['Content-Type']).to eq('application/json') end end describe '#remove_header' do it 'removes a header by name' do - headers.add_header('X-Custom-Header', 'foo') - headers.remove_header('X-Custom-Header') + headers['X-Custom-Header'] = 'foo' + headers.delete('X-Custom-Header') expect(headers['X-Custom-Header']).to be_nil end it 'does not raise an error if header does not exist' do - expect { headers.remove_header('Non-Existent') }.not_to raise_error + expect { headers.delete('Non-Existent') }.not_to raise_error end end @@ -96,7 +96,7 @@ class BiDi describe '#serialize' do it 'returns an array of header hashes in the correct format' do headers['Accept'] = 'application/json' - headers.add_header('User-Agent', 'MyAgent/1.0') + headers['User-Agent'] = 'MyAgent/1.0' serialized = headers.serialize expect(serialized).to be_an(Array) diff --git a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb index 9b0603acb5a5f..24b43ec8aec81 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb @@ -24,10 +24,13 @@ module Selenium module WebDriver class BiDi describe SetCookieHeaders do - let(:initial_hash) { {} } - let(:cookie_headers) { described_class.new(initial_hash) } + let(:set_cookie_headers) { described_class.new } describe '#initialize' do + it 'initializes with an empty hash by default' do + expect(set_cookie_headers.all).to eq({}) + end + it 'stores the passed set_cookie_headers hash internally' do my_hash = {'first_cookie' => {value: 'abc123'}} cookie_headers = described_class.new(my_hash) @@ -37,91 +40,62 @@ class BiDi describe '#all' do it 'returns the entire internal set_cookie_headers hash' do - cookie_headers.add_set_cookie_header('cookie1', 'value1') - expect(cookie_headers.all).to eq({'cookie1' => {value: 'value1'}}) + set_cookie_headers['cookie1'] = 'value1' + expect(set_cookie_headers.all).to eq({'cookie1' => {value: 'value1'}}) end end describe '#add_set_cookie_header' do it 'adds a cookie header to the internal store with a default hash' do - cookie_headers.add_set_cookie_header('name', 'chocolate_chip') - expect(cookie_headers['name']).to eq({value: 'chocolate_chip'}) + set_cookie_headers['name'] = 'chocolate_chip' + expect(set_cookie_headers['name']).to eq({value: 'chocolate_chip'}) end it 'overwrites an existing cookie header if the name already exists' do - cookie_headers.add_set_cookie_header('cookie_name', 'old_value') - cookie_headers.add_set_cookie_header('cookie_name', 'new_value') - expect(cookie_headers['cookie_name']).to eq({value: 'new_value'}) + set_cookie_headers['cookie_name'] = 'old_value' + set_cookie_headers['cookie_name'] = 'new_value' + expect(set_cookie_headers['cookie_name']).to eq({value: 'new_value'}) end end describe '#remove_set_cookie_header' do it 'removes the named cookie header' do - cookie_headers.add_set_cookie_header('session_id', 'abc123') - cookie_headers.remove_set_cookie_header('session_id') - expect(cookie_headers['session_id']).to be_nil + set_cookie_headers['session_id'] = 'abc123' + set_cookie_headers.delete('session_id') + expect(set_cookie_headers['session_id']).to be_nil end it 'does not raise an error if the cookie header does not exist' do - expect { cookie_headers.remove_set_cookie_header('non_existent') }.not_to raise_error - end - end - - describe '#set_cookie_header' do - it 'stores a cookie header with extended attributes' do - cookie_headers.set_cookie_header( - name: 'test_cookie', - domain: 'example.com', - path: '/', - http_only: true, - expiry: 1_700_000_000, - max_age: 3600, - same_site: 'None', - secure: true - ) - - data = cookie_headers['test_cookie'] - expect(data[:domain]).to eq('example.com') - expect(data[:path]).to eq('/') - expect(data[:httpOnly]).to be(true) - expect(data[:expiry]).to eq(1_700_000_000) - expect(data[:maxAge]).to eq(3600) - expect(data[:sameSite]).to eq('None') - expect(data[:secure]).to be(true) - end - - it 'uses "input" as the literal value for :value, per original code' do - cookie_headers.set_cookie_header(name: 'my_cookie') - expect(cookie_headers['my_cookie'][:value]).to eq('input') + expect { set_cookie_headers.delete('non_existent') }.not_to raise_error end end describe '#[]=' do it 'adds or updates a cookie header via bracket assignment' do - cookie_headers['key1'] = 'value1' - expect(cookie_headers['key1']).to eq({value: 'value1'}) + set_cookie_headers['key1'] = 'value1' + expect(set_cookie_headers['key1']).to eq({value: 'value1'}) - cookie_headers['key1'] = 'updated_value' - expect(cookie_headers['key1']).to eq({value: 'updated_value'}) + set_cookie_headers['key1'] = 'updated_value' + expect(set_cookie_headers['key1']).to eq({value: 'updated_value'}) end end describe '#[]' do it 'retrieves the cookie header hash by name' do - cookie_headers['key2'] = 'value2' - expect(cookie_headers['key2']).to eq({value: 'value2'}) + set_cookie_headers['key2'] = 'value2' + expect(set_cookie_headers['key2']).to eq({value: 'value2'}) end it 'returns nil if the cookie header does not exist' do - expect(cookie_headers['does_not_exist']).to be_nil + expect(set_cookie_headers['does_not_exist']).to be_nil end end describe '#delete' do it 'removes a cookie header via bracket-based delete' do - cookie_headers['key3'] = 'value3' - cookie_headers.delete('key3') - expect(cookie_headers['key3']).to be_nil + set_cookie_headers['key3'] = 'value3' + set_cookie_headers.delete('key3') + expect(set_cookie_headers['key3']).to be_nil end end @@ -130,43 +104,7 @@ class BiDi let(:initial_hash) { nil } it 'returns an empty array if no set_cookie_headers are provided' do - expect(cookie_headers.serialize).to eq([]) - end - end - - context 'when set_cookie_headers is a hash' do - it 'returns an array of cookie header hashes with the specified format' do - cookie_headers.set_cookie_header( - name: 'test_cookie', - domain: 'example.com', - path: '/', - http_only: true, - expiry: 1_700_000_000 - ) - cookie_headers.add_set_cookie_header('second_cookie', 'second_value') - - serialized = cookie_headers.serialize - expect(serialized).to be_an(Array) - expect(serialized.size).to eq(2) - - # Check first cookie (extended fields) - test_item = serialized.find { |h| h[:name] == 'test_cookie' } - expect(test_item).not_to be_nil - expect(test_item[:value]).to eq(type: 'string', value: 'input') - expect(test_item[:domain]).to eq('example.com') - expect(test_item[:path]).to eq('/') - expect(test_item[:httpOnly]).to be(true) - expect(test_item[:expiry]).to eq(1_700_000_000) - - # Check second cookie (just a simple string) - second_item = serialized.find { |h| h[:name] == 'second_cookie' } - expect(second_item).not_to be_nil - expect(second_item[:value]).to eq(type: 'string', value: 'second_value') - expect(second_item[:domain]).to be_nil - end - - it 'returns an empty array if the internal hash is empty' do - expect(cookie_headers.serialize).to eq([]) + expect(set_cookie_headers.serialize).to eq([]) end end end From fa0c87a8c4532915d8b4f029849014b6c9da23c9 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 11 Jan 2025 22:06:12 +0100 Subject: [PATCH 26/35] Simplify serialization --- .../webdriver/bidi/network/cookies.rb | 29 +---- .../webdriver/bidi/network/headers.rb | 24 +--- .../bidi/network/set_cookie_headers.rb | 25 +--- .../webdriver/bidi/network/cookies.rbs | 10 -- .../webdriver/bidi/network/headers.rbs | 10 -- .../bidi/network/set_cookie_headers.rbs | 14 +-- .../selenium/webdriver/bidi/cookies_spec.rb | 108 +++--------------- .../selenium/webdriver/bidi/headers_spec.rb | 97 ++-------------- .../webdriver/bidi/set_cookie_headers_spec.rb | 97 +++------------- 9 files changed, 56 insertions(+), 358 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/cookies.rb b/rb/lib/selenium/webdriver/bidi/network/cookies.rb index 9a379c457d9bc..248dbd8c8cfdb 100644 --- a/rb/lib/selenium/webdriver/bidi/network/cookies.rb +++ b/rb/lib/selenium/webdriver/bidi/network/cookies.rb @@ -20,31 +20,14 @@ module Selenium module WebDriver class BiDi - class Cookies + class Cookies < Hash def initialize(cookies = {}) - @cookies = cookies - end - - def all - @cookies - end - - def []=(key, value) - @cookies[key] = value - end - - def [](key) - @cookies[key] - end - - def delete(key) - @cookies.delete(key) + super() + merge!(cookies) end def serialize - return [] unless @cookies - - @cookies.map do |name, value| + map do |name, value| { name: name.to_s, value: { @@ -55,8 +38,6 @@ def serialize end end end - end - - # BiDi + end # BiDi end # WebDriver end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/network/headers.rb b/rb/lib/selenium/webdriver/bidi/network/headers.rb index 3221f8d64a9d8..788d0cb821a17 100644 --- a/rb/lib/selenium/webdriver/bidi/network/headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/headers.rb @@ -20,29 +20,9 @@ module Selenium module WebDriver class BiDi - class Headers - def initialize - @headers = {} - end - - def all - @headers - end - - def []=(key, value) - @headers[key] = value - end - - def [](key) - @headers[key] - end - - def delete(key) - @headers.delete(key) - end - + class Headers < Hash def serialize - @headers.map do |name, val| + map do |name, val| { name: name.to_s, value: { diff --git a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb index a886389c8cf6e..544cda43c5316 100644 --- a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb +++ b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb @@ -20,31 +20,14 @@ module Selenium module WebDriver class BiDi - class SetCookieHeaders + class SetCookieHeaders < Hash def initialize(set_cookie_headers = {}) - @set_cookie_headers = set_cookie_headers - end - - def all - @set_cookie_headers - end - - def []=(key, value) - @set_cookie_headers[key] = {value: value} - end - - def [](key) - @set_cookie_headers[key] - end - - def delete(key) - @set_cookie_headers.delete(key) + super() + merge!(set_cookie_headers) end def serialize - return [] unless @set_cookie_headers - - @set_cookie_headers.map do |name, data| + map do |name, data| data = {value: data} unless data.is_a?(Hash) { diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs index 1f1bd8beb906f..664b54de792b3 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs @@ -2,18 +2,8 @@ module Selenium module WebDriver class BiDi class Cookies - @cookies: untyped - def initialize: (untyped cookies) -> void - def all: () -> untyped - - def []=: (untyped key, untyped value) -> untyped - - def []: (untyped key) -> untyped - - def delete: (untyped key) -> untyped - def serialize: () -> untyped end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs index ce8b9068c9c82..f5a782235876b 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs @@ -2,18 +2,8 @@ module Selenium module WebDriver class BiDi class Headers - @headers: untyped - def initialize: () -> void - def all: () -> untyped - - def []=: (untyped key, untyped value) -> untyped - - def []: (untyped key) -> untyped - - def delete: (untyped key) -> untyped - def serialize: () -> untyped end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs index cdc9761ed7869..d20e5295a644e 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs @@ -2,21 +2,9 @@ module Selenium module WebDriver class BiDi class SetCookieHeaders - @set_cookie_headers: untyped - def initialize: (untyped set_cookie_headers) -> void - def all: () -> untyped - - def set_cookie_header: (**untyped args) -> untyped - - def []=: (untyped key, untyped value) -> untyped - - def []: (untyped key) -> untyped - - def delete: (untyped key) -> untyped - - def serialize: () -> (::Array[untyped] | untyped) + def serialize: () -> (Array[untyped] | untyped) end end end diff --git a/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb index 0af7ec4bef471..39ec8fe946a07 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/cookies_spec.rb @@ -26,98 +26,22 @@ class BiDi describe Cookies do let(:cookies) { described_class.new } - describe '#initialize' do - it 'initializes with an empty hash by default' do - expect(cookies.all).to eq({}) - end - - it 'stores the passed cookie hash internally' do - my_hash = {'foo' => {value: 'bar'}} - cookie_headers = described_class.new(my_hash) - expect(cookie_headers.all).to eq(my_hash) - end - end - - describe '#all' do - it 'returns the underlying cookies hash' do - cookies['session_id'] = 'abc123' - expect(cookies.all).to eq({'session_id' => 'abc123'}) - end - end - - describe '#add_cookie' do - it 'adds a cookie to the internal store' do - cookies['foo'] = 'bar' - expect(cookies['foo']).to eq('bar') - end - - it 'updates an existing cookie if the name already exists' do - cookies['foo'] = 'bar' - cookies['foo'] = 'baz' - expect(cookies['foo']).to eq('baz') - end - end - - describe '#remove_cookie' do - it 'removes a cookie by name' do - cookies['foo'] = 'bar' - cookies.delete('foo') - expect(cookies['foo']).to be_nil - end - - it 'does not raise an error if cookie does not exist' do - expect { cookies.delete('non_existent') }.not_to raise_error - end - end - - describe '#[]=' do - it 'adds a cookie using bracket assignment' do - cookies['key1'] = 'value1' - expect(cookies['key1']).to eq('value1') - end - end - - describe '#[]' do - it 'retrieves the value of a cookie by name' do - cookies['key2'] = 'value2' - expect(cookies['key2']).to eq('value2') - end - - it 'returns nil for unknown cookies' do - expect(cookies['does_not_exist']).to be_nil - end - end - - describe '#delete' do - it 'removes a cookie via bracket-based delete' do - cookies['key3'] = 'value3' - cookies.delete('key3') - expect(cookies['key3']).to be_nil - end - end - - describe '#serialize' do - it 'returns an array of cookie hashes in the minimal format' do - cookies['key4'] = 'value4' - cookies['session_id'] = 'xyz123' - - serialized = cookies.serialize - expect(serialized).to be_an(Array) - expect(serialized.size).to eq(2) - - key4_item = serialized.find { |h| h[:name] == 'key4' } - expect(key4_item).not_to be_nil - expect(key4_item[:value][:type]).to eq('string') - expect(key4_item[:value][:value]).to eq('value4') - - session_item = serialized.find { |h| h[:name] == 'session_id' } - expect(session_item).not_to be_nil - expect(session_item[:value][:value]).to eq('xyz123') - end - - it 'returns an empty array if no cookies are set' do - expect(cookies.serialize).to eq([]) - end + it 'returns a serialized array of cookie hashes' do + cookies['key4'] = 'value4' + cookies['session_id'] = 'xyz123' + + serialized = cookies.serialize + expect(serialized).to be_an(Array) + expect(serialized.size).to eq(2) + + key4_item = serialized.find { |h| h[:name] == 'key4' } + expect(key4_item).not_to be_nil + expect(key4_item[:value][:type]).to eq('string') + expect(key4_item[:value][:value]).to eq('value4') + + session_item = serialized.find { |h| h[:name] == 'session_id' } + expect(session_item).not_to be_nil + expect(session_item[:value][:value]).to eq('xyz123') end end end diff --git a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb index 058530680547f..d0eb22c558328 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb @@ -26,94 +26,21 @@ class BiDi describe Headers do let(:headers) { described_class.new } - describe '#initialize' do - it 'initializes an empty headers hash' do - expect(headers.all).to eq({}) - end - end - - describe '#all' do - it 'returns the underlying headers hash' do - headers['Authorization'] = 'Bearer abc123' - expect(headers.all).to eq({'Authorization' => 'Bearer abc123'}) - end - end - - describe '#add_header' do - it 'adds a header to the internal store' do - headers['Content-Type'] = 'application/json' - expect(headers['Content-Type']).to eq('application/json') - end - - it 'updates an existing header if the name already exists' do - headers['Content-Type'] = 'text/html' - headers['Content-Type'] = 'application/json' - expect(headers['Content-Type']).to eq('application/json') - end - end - - describe '#remove_header' do - it 'removes a header by name' do - headers['X-Custom-Header'] = 'foo' - headers.delete('X-Custom-Header') - expect(headers['X-Custom-Header']).to be_nil - end - - it 'does not raise an error if header does not exist' do - expect { headers.delete('Non-Existent') }.not_to raise_error - end - end - - describe '#[]=' do - it 'adds or updates a header using bracket assignment' do - headers['Cache-Control'] = 'no-cache' - expect(headers['Cache-Control']).to eq('no-cache') - - headers['Cache-Control'] = 'private' - expect(headers['Cache-Control']).to eq('private') - end - end - - describe '#[]' do - it 'retrieves the value of a header by name' do - headers['Host'] = 'example.com' - expect(headers['Host']).to eq('example.com') - end - - it 'returns nil for unknown headers' do - expect(headers['Does-Not-Exist']).to be_nil - end - end - - describe '#delete' do - it 'removes a header via bracket-based delete' do - headers['Accept'] = 'text/html' - headers.delete('Accept') - expect(headers['Accept']).to be_nil - end - end - - describe '#serialize' do - it 'returns an array of header hashes in the correct format' do - headers['Accept'] = 'application/json' - headers['User-Agent'] = 'MyAgent/1.0' - - serialized = headers.serialize - expect(serialized).to be_an(Array) - expect(serialized.size).to eq(2) + it 'returns an array of serialized array of header hashes' do + headers['Accept'] = 'application/json' + headers['User-Agent'] = 'MyAgent/1.0' - accept_item = serialized.find { |h| h[:name] == 'Accept' } - expect(accept_item).not_to be_nil - expect(accept_item[:value]).to eq({type: 'string', value: 'application/json'}) + serialized = headers.serialize + expect(serialized).to be_an(Array) + expect(serialized.size).to eq(2) - ua_item = serialized.find { |h| h[:name] == 'User-Agent' } - expect(ua_item).not_to be_nil - expect(ua_item[:value]).to eq({type: 'string', value: 'MyAgent/1.0'}) - end + accept_item = serialized.find { |h| h[:name] == 'Accept' } + expect(accept_item).not_to be_nil + expect(accept_item[:value]).to eq({ type: 'string', value: 'application/json' }) - it 'returns an empty array if no headers are set' do - expect(headers.serialize).to eq([]) - end + ua_item = serialized.find { |h| h[:name] == 'User-Agent' } + expect(ua_item).not_to be_nil + expect(ua_item[:value]).to eq({ type: 'string', value: 'MyAgent/1.0' }) end end end diff --git a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb index 24b43ec8aec81..8aae3d59150f5 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb @@ -26,87 +26,22 @@ class BiDi describe SetCookieHeaders do let(:set_cookie_headers) { described_class.new } - describe '#initialize' do - it 'initializes with an empty hash by default' do - expect(set_cookie_headers.all).to eq({}) - end - - it 'stores the passed set_cookie_headers hash internally' do - my_hash = {'first_cookie' => {value: 'abc123'}} - cookie_headers = described_class.new(my_hash) - expect(cookie_headers.all).to eq(my_hash) - end - end - - describe '#all' do - it 'returns the entire internal set_cookie_headers hash' do - set_cookie_headers['cookie1'] = 'value1' - expect(set_cookie_headers.all).to eq({'cookie1' => {value: 'value1'}}) - end - end - - describe '#add_set_cookie_header' do - it 'adds a cookie header to the internal store with a default hash' do - set_cookie_headers['name'] = 'chocolate_chip' - expect(set_cookie_headers['name']).to eq({value: 'chocolate_chip'}) - end - - it 'overwrites an existing cookie header if the name already exists' do - set_cookie_headers['cookie_name'] = 'old_value' - set_cookie_headers['cookie_name'] = 'new_value' - expect(set_cookie_headers['cookie_name']).to eq({value: 'new_value'}) - end - end - - describe '#remove_set_cookie_header' do - it 'removes the named cookie header' do - set_cookie_headers['session_id'] = 'abc123' - set_cookie_headers.delete('session_id') - expect(set_cookie_headers['session_id']).to be_nil - end - - it 'does not raise an error if the cookie header does not exist' do - expect { set_cookie_headers.delete('non_existent') }.not_to raise_error - end - end - - describe '#[]=' do - it 'adds or updates a cookie header via bracket assignment' do - set_cookie_headers['key1'] = 'value1' - expect(set_cookie_headers['key1']).to eq({value: 'value1'}) - - set_cookie_headers['key1'] = 'updated_value' - expect(set_cookie_headers['key1']).to eq({value: 'updated_value'}) - end - end - - describe '#[]' do - it 'retrieves the cookie header hash by name' do - set_cookie_headers['key2'] = 'value2' - expect(set_cookie_headers['key2']).to eq({value: 'value2'}) - end - - it 'returns nil if the cookie header does not exist' do - expect(set_cookie_headers['does_not_exist']).to be_nil - end - end - - describe '#delete' do - it 'removes a cookie header via bracket-based delete' do - set_cookie_headers['key3'] = 'value3' - set_cookie_headers.delete('key3') - expect(set_cookie_headers['key3']).to be_nil - end - end - - describe '#serialize' do - context 'when set_cookie_headers is nil' do - let(:initial_hash) { nil } - - it 'returns an empty array if no set_cookie_headers are provided' do - expect(set_cookie_headers.serialize).to eq([]) - end - end + it 'returns an array of serialized array of set-cookie header hashes' do + set_cookie_headers['key4'] = 'value4' + set_cookie_headers['session_id'] = 'xyz123' + + serialized = set_cookie_headers.serialize + expect(serialized).to be_an(Array) + expect(serialized.size).to eq(2) + + key4_item = serialized.find { |h| h[:name] == 'key4' } + expect(key4_item).not_to be_nil + expect(key4_item[:value][:type]).to eq('string') + expect(key4_item[:value][:value]).to eq('value4') + + session_item = serialized.find { |h| h[:name] == 'session_id' } + expect(session_item).not_to be_nil + expect(session_item[:value][:value]).to eq('xyz123') end end end From bbd7bccbb8ad51a22edabd990bfd2b16c4bd31fe Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 11 Jan 2025 22:14:15 +0100 Subject: [PATCH 27/35] Add extra type support --- .../webdriver/bidi/network/intercepted_auth.rbs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs new file mode 100644 index 0000000000000..cd1eb6a3d56aa --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs @@ -0,0 +1,13 @@ +module Selenium + module WebDriver + class BiDi + class InterceptedAuth < InterceptedItem + def authenticate: (untyped username, untyped password) -> untyped + + def skip: () -> untyped + + def cancel: () -> untyped + end + end + end +end From eea4a65a84f41e684f766e1ca0b8f463310b02d5 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sat, 11 Jan 2025 22:34:26 +0100 Subject: [PATCH 28/35] remove unnecessary comment --- rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb | 1 - .../lib/selenium/webdriver/bidi/network/intercepted_request.rbs | 1 - 2 files changed, 2 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index a1716f2d7d3f5..ad679b4357d25 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -29,7 +29,6 @@ class InterceptedRequest < InterceptedItem def initialize(network, request) super - # We now rely on the modules above to initialize @headers and @cookies as Hashes @method = nil @url = nil @body = nil diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs index b38b4288a368d..57de5d189b297 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs @@ -2,7 +2,6 @@ module Selenium module WebDriver class BiDi class InterceptedRequest < InterceptedItem - # We now rely on the modules above to initialize @headers and @cookies as Hashes @method: untyped @url: untyped From acce73467ebf714d338cf5917e91258b6d667412 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Sun, 12 Jan 2025 09:43:57 +0100 Subject: [PATCH 29/35] Improve typing --- .../bidi/network/intercepted_request.rb | 1 - .../webdriver/bidi/network/cookies.rbs | 4 +-- .../webdriver/bidi/network/credentials.rbs | 12 ++++---- .../webdriver/bidi/network/headers.rbs | 2 +- .../bidi/network/intercepted_auth.rbs | 6 ++-- .../bidi/network/intercepted_item.rbs | 10 +++---- .../bidi/network/intercepted_request.rbs | 29 +++++++++---------- .../bidi/network/set_cookie_headers.rbs | 4 +-- .../lib/selenium/webdriver/common/network.rbs | 2 +- 9 files changed, 34 insertions(+), 36 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb index a1716f2d7d3f5..ad679b4357d25 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_request.rb @@ -29,7 +29,6 @@ class InterceptedRequest < InterceptedItem def initialize(network, request) super - # We now rely on the modules above to initialize @headers and @cookies as Hashes @method = nil @url = nil @body = nil diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs index 664b54de792b3..15745ff980b9b 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/cookies.rbs @@ -2,9 +2,9 @@ module Selenium module WebDriver class BiDi class Cookies - def initialize: (untyped cookies) -> void + def initialize: (Hash[Symbol, String] cookies) -> void - def serialize: () -> untyped + def serialize: () -> Hash[Symbol, String] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs index 5fd4e263f4107..340f9cf33c589 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/credentials.rbs @@ -2,17 +2,17 @@ module Selenium module WebDriver class BiDi class Credentials - @username: untyped + @username: String - @password: untyped + @password: String - attr_accessor username: untyped + attr_accessor username: String - attr_accessor password: untyped + attr_accessor password: String - def initialize: (?username: untyped?, ?password: untyped?) -> void + def initialize: (?username: String?, ?password: String?) -> void - def serialize: () -> (nil | { type: "password", username: untyped, password: untyped }) + def serialize: () -> Hash[Symbol, String]? end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs index f5a782235876b..d9fb5a1fb4f76 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/headers.rbs @@ -4,7 +4,7 @@ module Selenium class Headers def initialize: () -> void - def serialize: () -> untyped + def serialize: () -> Array[Hash[Symbol, String]] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs index cd1eb6a3d56aa..c7fb60df6a32e 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_auth.rbs @@ -2,11 +2,11 @@ module Selenium module WebDriver class BiDi class InterceptedAuth < InterceptedItem - def authenticate: (untyped username, untyped password) -> untyped + def authenticate: (String username, String password) -> Hash[nil, nil] - def skip: () -> untyped + def skip: () -> Hash[nil, nil] - def cancel: () -> untyped + def cancel: () -> Hash[nil, nil] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs index 7babcab9c1edd..ab73782de2d5f 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_item.rbs @@ -2,19 +2,19 @@ module Selenium module WebDriver class BiDi class InterceptedItem - @network: untyped + @network: Network @request: untyped - @id: untyped + @id: Integer - attr_reader network: untyped + attr_reader network: Network attr_reader request: untyped - def initialize: (untyped network, untyped request) -> void + def initialize: (Network network, Hash[untyped, untyped] request) -> void - def id: () -> untyped + def id: () -> Integer end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs index b38b4288a368d..04cecb59457dc 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_request.rbs @@ -2,34 +2,33 @@ module Selenium module WebDriver class BiDi class InterceptedRequest < InterceptedItem - # We now rely on the modules above to initialize @headers and @cookies as Hashes - @method: untyped + @method: String - @url: untyped + @url: String - @body: untyped + @body: Hash[untyped, untyped] - @headers: untyped + @headers: Hash[untyped, untyped] - @cookies: untyped + @cookies: Hash[untyped, untyped] - attr_accessor method: untyped + attr_accessor method: String - attr_accessor url: untyped + attr_accessor url: String - attr_reader body: untyped + attr_reader body: Hash[untyped, untyped] - def initialize: (untyped network, untyped request) -> void + def initialize: (Network network, Hash[untyped, untyped] request) -> void - def continue: () -> untyped + def continue: () -> Hash[nil, nil] - def fail: () -> untyped + def fail: () -> Hash[nil, nil] - def body=: (untyped value) -> untyped + def body=: (Hash[untyped, untyped] value) -> Hash[untyped, untyped] - def headers: () -> untyped + def headers: () -> Hash[untyped, untyped] - def cookies: () -> untyped + def cookies: () -> Hash[untyped, untyped] end end end diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs index d20e5295a644e..0a031351115f1 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/set_cookie_headers.rbs @@ -2,9 +2,9 @@ module Selenium module WebDriver class BiDi class SetCookieHeaders - def initialize: (untyped set_cookie_headers) -> void + def initialize: (Hash[Symbol, untyped] set_cookie_headers) -> void - def serialize: () -> (Array[untyped] | untyped) + def serialize: () -> Array[Hash[Symbol, untyped]] end end end diff --git a/rb/sig/lib/selenium/webdriver/common/network.rbs b/rb/sig/lib/selenium/webdriver/common/network.rbs index 6660cd390f6a5..193e7385439af 100644 --- a/rb/sig/lib/selenium/webdriver/common/network.rbs +++ b/rb/sig/lib/selenium/webdriver/common/network.rbs @@ -25,7 +25,7 @@ module Selenium private - def add_handler: (Symbol event_type, String phase, BiDi::InterceptedItem intercept_type, Array[String] filter, ?pattern_type: Symbol?) { (untyped) -> untyped } -> untyped + def add_handler: (Symbol event_type, String phase, BiDi::InterceptedRequest | BiDi::InterceptedAuth | BiDi::InterceptedResponse intercept_type, Array[String] filter, ?pattern_type: Symbol?) { (untyped) -> untyped } -> untyped end end end From 3557bfb0d528976cf80760d22a4de5bd933862a0 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Tue, 14 Jan 2025 18:53:39 +0100 Subject: [PATCH 30/35] add provide response support --- rb/lib/selenium/webdriver/bidi/network.rb | 12 ++++++++ .../bidi/network/intercepted_response.rb | 26 +++++++++++++++-- .../lib/selenium/webdriver/bidi/network.rbs | 2 ++ .../bidi/network/intercepted_response.rbs | 8 ++++++ .../selenium/webdriver/bidi/network_spec.rb | 28 +++++++++++++++++++ .../selenium/webdriver/network_spec.rb | 16 ++++++++++- 6 files changed, 89 insertions(+), 3 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network.rb b/rb/lib/selenium/webdriver/bidi/network.rb index f3074fb6173b7..5cebd8967f2e1 100644 --- a/rb/lib/selenium/webdriver/bidi/network.rb +++ b/rb/lib/selenium/webdriver/bidi/network.rb @@ -112,6 +112,18 @@ def continue_response(**args) ) end + def provide_response(**args) + @bidi.send_cmd( + 'network.provideResponse', + request: args[:id], + body: args[:body], + cookies: args[:cookies], + headers: args[:headers], + reasonPhrase: args[:reason], + statusCode: args[:status] + ) + end + def on(event, &) event = EVENTS[event] if event.is_a?(Symbol) @bidi.add_callback(event, &) diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 5cc2b484a45ca..e2e8c67d735e3 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -25,11 +25,14 @@ module Selenium module WebDriver class BiDi class InterceptedResponse < InterceptedItem - attr_accessor :reason + attr_accessor :reason, :status + attr_reader :body def initialize(network, request) super @reason = nil + @status = nil + @body = nil end def continue @@ -38,7 +41,19 @@ def continue cookies: set_cookie_headers.serialize, headers: headers.serialize, credentials: credentials.serialize, - reason: reason + reason: reason, + status: status + ) + end + + def provide_response + network.provide_response( + id: id, + cookies: set_cookie_headers.serialize, + headers: headers.serialize, + body: body, + reason: reason, + status: status ) end @@ -53,6 +68,13 @@ def headers def set_cookie_headers(set_cookie_headers = {}) @set_cookie_headers ||= SetCookieHeaders.new(set_cookie_headers) end + + def body=(value) + @body = { + type: 'string', + value: value.to_json + } + end end end # BiDi end # WebDriver diff --git a/rb/sig/lib/selenium/webdriver/bidi/network.rbs b/rb/sig/lib/selenium/webdriver/bidi/network.rbs index 71d2588c65750..e4fe4ec7721aa 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network.rbs @@ -22,6 +22,8 @@ module Selenium def fail_request: -> Hash[nil, nil] + def provide_response: -> Hash[nil, nil] + def remove_intercept: (String intercept) -> Hash[nil, nil] def continue_with_auth: (String request_id, String username, String password) -> Hash[nil, nil] diff --git a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs index 6c55f8c73494d..a7b7cff5c99ce 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/network/intercepted_response.rbs @@ -2,6 +2,7 @@ module Selenium module WebDriver class BiDi class InterceptedResponse < InterceptedItem + @body: untyped @reason: untyped @credentials: untyped @@ -10,16 +11,23 @@ module Selenium @set_cookie_headers: untyped + attr_reader body: untyped attr_accessor reason: untyped + attr_accessor status: Integer? + def initialize: (untyped network, untyped request) -> void + def body=: -> untyped + def continue: () -> untyped def credentials: (?username: untyped?, ?password: untyped?) -> untyped def headers: () -> untyped + def provide_response: -> untyped + def set_cookie_headers: (?untyped? set_cookie_headers) -> untyped end end diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index c02eee189450d..bd2ad5d3be3ec 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -144,6 +144,34 @@ class BiDi expect(driver.find_element(name: 'login')).to be_displayed end end + + it 'provides response' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver.bidi) + network.add_intercept(phases: [described_class::PHASES[:response_started]]) + network.on(:response_started) do |event| + request_id = event['request']['request'] + network.provide_response(id: request_id, + status: 200, + headers: [ + { + name: 'foo', + value: { + type: 'string', + value: 'bar' + } + } + ], + body: { + type: 'string', + value: 'Hello World!' + }) + end + + driver.navigate.to url_for('formPage.html') + expect(driver.page_source).to include('Hello World!') + end + end end end end diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index d86c670f700b4..b995abdd06d7e 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -150,7 +150,7 @@ module WebDriver request.headers['foo'] = 'bar' request.headers['baz'] = 'qux' request.cookies['foo'] = 'bar' - request.body = ({test: 'example'}) + request.body = ({ test: 'example' }) request.continue end driver.navigate.to url_for('formPage.html') @@ -274,6 +274,20 @@ module WebDriver end end + it 'adds a response handler that provides a response' do + reset_driver!(web_socket_url: true) do |driver| + network = described_class.new(driver) + network.add_response_handler do |response| + response.status = 200 + response.headers['foo'] = 'bar' + response.body = 'Hello World!' + response.provide_response + end + driver.navigate.to url_for('formPage.html') + expect(driver.page_source).to include('Hello World!') + end + end + it 'removes a response handler' do reset_driver!(web_socket_url: true) do |driver| network = described_class.new(driver) From 5d276c2a82cdadaf9738daad33a2aeb63ca52a40 Mon Sep 17 00:00:00 2001 From: Augustin Pequeno Date: Tue, 14 Jan 2025 18:56:30 +0100 Subject: [PATCH 31/35] Correct rubocop offenses --- .../selenium/webdriver/bidi/network_spec.rb | 32 ++++++++++--------- .../selenium/webdriver/network_spec.rb | 2 +- .../selenium/webdriver/bidi/headers_spec.rb | 4 +-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index bd2ad5d3be3ec..5c10082375dd0 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -151,21 +151,23 @@ class BiDi network.add_intercept(phases: [described_class::PHASES[:response_started]]) network.on(:response_started) do |event| request_id = event['request']['request'] - network.provide_response(id: request_id, - status: 200, - headers: [ - { - name: 'foo', - value: { - type: 'string', - value: 'bar' - } - } - ], - body: { - type: 'string', - value: 'Hello World!' - }) + network.provide_response( + id: request_id, + status: 200, + headers: [ + { + name: 'foo', + value: { + type: 'string', + value: 'bar' + } + } + ], + body: { + type: 'string', + value: 'Hello World!' + } + ) end driver.navigate.to url_for('formPage.html') diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index b995abdd06d7e..749eabb752a7b 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -150,7 +150,7 @@ module WebDriver request.headers['foo'] = 'bar' request.headers['baz'] = 'qux' request.cookies['foo'] = 'bar' - request.body = ({ test: 'example' }) + request.body = ({test: 'example'}) request.continue end driver.navigate.to url_for('formPage.html') diff --git a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb index d0eb22c558328..6873180b59610 100644 --- a/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb +++ b/rb/spec/unit/selenium/webdriver/bidi/headers_spec.rb @@ -36,11 +36,11 @@ class BiDi accept_item = serialized.find { |h| h[:name] == 'Accept' } expect(accept_item).not_to be_nil - expect(accept_item[:value]).to eq({ type: 'string', value: 'application/json' }) + expect(accept_item[:value]).to eq({type: 'string', value: 'application/json'}) ua_item = serialized.find { |h| h[:name] == 'User-Agent' } expect(ua_item).not_to be_nil - expect(ua_item[:value]).to eq({ type: 'string', value: 'MyAgent/1.0' }) + expect(ua_item[:value]).to eq({type: 'string', value: 'MyAgent/1.0'}) end end end From 816ba5127c780d337f6378cd7d39bcc6b79fcf38 Mon Sep 17 00:00:00 2001 From: aguspe Date: Sat, 25 Jan 2025 09:43:29 +0100 Subject: [PATCH 32/35] Remove set cookie headers --- .../webdriver/bidi/set_cookie_headers_spec.rb | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb diff --git a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb b/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb deleted file mode 100644 index 8aae3d59150f5..0000000000000 --- a/rb/spec/unit/selenium/webdriver/bidi/set_cookie_headers_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -# Licensed to the Software Freedom Conservancy (SFC) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The SFC licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -require File.expand_path('../spec_helper', __dir__) -require File.expand_path('../../../../../lib/selenium/webdriver/bidi/network/set_cookie_headers', __dir__) - -module Selenium - module WebDriver - class BiDi - describe SetCookieHeaders do - let(:set_cookie_headers) { described_class.new } - - it 'returns an array of serialized array of set-cookie header hashes' do - set_cookie_headers['key4'] = 'value4' - set_cookie_headers['session_id'] = 'xyz123' - - serialized = set_cookie_headers.serialize - expect(serialized).to be_an(Array) - expect(serialized.size).to eq(2) - - key4_item = serialized.find { |h| h[:name] == 'key4' } - expect(key4_item).not_to be_nil - expect(key4_item[:value][:type]).to eq('string') - expect(key4_item[:value][:value]).to eq('value4') - - session_item = serialized.find { |h| h[:name] == 'session_id' } - expect(session_item).not_to be_nil - expect(session_item[:value][:value]).to eq('xyz123') - end - end - end - end -end From 74a0545fdfb3a442d35a2ee748234bb37f2baaa9 Mon Sep 17 00:00:00 2001 From: aguspe Date: Sat, 25 Jan 2025 09:44:13 +0100 Subject: [PATCH 33/35] Remove set cookie headers --- .../bidi/network/set_cookie_headers.rb | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb diff --git a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb b/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb deleted file mode 100644 index 544cda43c5316..0000000000000 --- a/rb/lib/selenium/webdriver/bidi/network/set_cookie_headers.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -# Licensed to the Software Freedom Conservancy (SFC) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The SFC licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -module Selenium - module WebDriver - class BiDi - class SetCookieHeaders < Hash - def initialize(set_cookie_headers = {}) - super() - merge!(set_cookie_headers) - end - - def serialize - map do |name, data| - data = {value: data} unless data.is_a?(Hash) - - { - name: name.to_s, - value: { - type: 'string', - value: data[:value].to_s - }, - domain: data[:domain], - httpOnly: data[:httpOnly], - expiry: data[:expiry], - maxAge: data[:maxAge], - path: data[:path], - sameSite: data[:sameSite], - secure: data[:secure] - }.compact - end - end - end - end # BiDi - end # WebDriver -end # Selenium From 6a2255d89c9e5a372732c621211e80c339f8b024 Mon Sep 17 00:00:00 2001 From: aguspe Date: Sat, 25 Jan 2025 09:50:16 +0100 Subject: [PATCH 34/35] Fix failing tests --- .../webdriver/bidi/network/intercepted_response.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb index 900fe4f210bbd..08e4b9c84a715 100644 --- a/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb +++ b/rb/lib/selenium/webdriver/bidi/network/intercepted_response.rb @@ -49,8 +49,8 @@ def continue def provide_response network.provide_response( id: id, - cookies: set_cookie_headers.serialize, - headers: headers.serialize, + cookies: cookies.as_json, + headers: headers.as_json, body: body, reason: reason, status: status @@ -68,6 +68,13 @@ def headers def cookies(cookies = {}) @cookies ||= Cookies.new(cookies) end + + def body=(value) + @body = { + type: 'string', + value: value.to_json + } + end end end # BiDi end # WebDriver From 894883ce4baa0154d2a07d808b58f0b3f69493d4 Mon Sep 17 00:00:00 2001 From: aguspe Date: Wed, 5 Feb 2025 06:39:08 +0100 Subject: [PATCH 35/35] Add negative scenario --- rb/spec/integration/selenium/webdriver/bidi/network_spec.rb | 4 +++- rb/spec/integration/selenium/webdriver/network_spec.rb | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb index 5c10082375dd0..7c2b63f4770dc 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/network_spec.rb @@ -171,7 +171,9 @@ class BiDi end driver.navigate.to url_for('formPage.html') - expect(driver.page_source).to include('Hello World!') + source = driver.page_source + expect(source).not_to include('There should be a form here:') + expect(source).to include('Hello World!') end end end diff --git a/rb/spec/integration/selenium/webdriver/network_spec.rb b/rb/spec/integration/selenium/webdriver/network_spec.rb index e18fe90089c21..210e2d2e9d229 100644 --- a/rb/spec/integration/selenium/webdriver/network_spec.rb +++ b/rb/spec/integration/selenium/webdriver/network_spec.rb @@ -272,7 +272,9 @@ module WebDriver response.provide_response end driver.navigate.to url_for('formPage.html') - expect(driver.page_source).to include('Hello World!') + source = driver.page_source + expect(source).not_to include('There should be a form here:') + expect(source).to include('Hello World!') end end