diff --git a/rb/lib/selenium/webdriver/bidi.rb b/rb/lib/selenium/webdriver/bidi.rb index a07acc1c8d95f..21a78b0361a4e 100644 --- a/rb/lib/selenium/webdriver/bidi.rb +++ b/rb/lib/selenium/webdriver/bidi.rb @@ -37,7 +37,7 @@ def callbacks end def session - Session.new(self) + @session ||= Session.new(self) end def send_cmd(method, **params) diff --git a/rb/lib/selenium/webdriver/common/driver.rb b/rb/lib/selenium/webdriver/common/driver.rb index 398337041b3ad..c24e8ec28ae66 100644 --- a/rb/lib/selenium/webdriver/common/driver.rb +++ b/rb/lib/selenium/webdriver/common/driver.rb @@ -71,6 +71,7 @@ def for(browser, opts = {}) def initialize(bridge: nil, listener: nil, **opts) @service_manager = nil @devtools = nil + @bidi = nil bridge ||= create_bridge(**opts) add_extensions(bridge.browser) @bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge @@ -174,6 +175,7 @@ def quit ensure @service_manager&.stop @devtools&.close + @bidi&.close end # @@ -181,7 +183,10 @@ def quit # def close - bridge.close + # If no top-level browsing contexts are open after calling close, + # it indicates that the WebDriver session is closed. + # If the WebDriver session is closed, the BiDi session also needs to be closed. + bridge.close.tap { |handles| @bidi&.close if handles&.empty? } end # diff --git a/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb b/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb index 8fa9a8405c5af..2ba0047183d4b 100644 --- a/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi/browsing_context_spec.rb @@ -22,7 +22,7 @@ module Selenium module WebDriver class BiDi - describe BrowsingContext, exclusive: {browser: %i[chrome firefox]} do + describe BrowsingContext, only: {browser: %i[chrome edge firefox]} do before { reset_driver!(web_socket_url: true) } after { quit_driver } @@ -32,50 +32,47 @@ class BiDi expect(browsing_context.id).to eq(id) end - it 'can create a window without a reference context' do + it 'can create a window' do browsing_context = described_class.new(driver: driver, type: :window) expect(browsing_context.id).not_to be_nil end - it 'can create a window with a reference context', except: {browser: :chrome} do + it 'can create a window with a reference context', except: {browser: %i[chrome edge]} do browsing_context = described_class.new(driver: driver, type: :window, reference_context: driver.window_handle) expect(browsing_context.id).not_to be_nil end - it 'can create a tab without a reference context' do + it 'can create a tab' do browsing_context = described_class.new(driver: driver, type: :tab) expect(browsing_context.id).not_to be_nil end - it 'can create a tab with a reference context', except: {browser: :chrome} do + it 'can create a tab with a reference context', except: {browser: %i[chrome edge]} do browsing_context = described_class.new(driver: driver, type: :tab, reference_context: driver.window_handle) expect(browsing_context.id).not_to be_nil end - it 'can navigate to a url without a readiness state', - except: {browser: :chrome, reason: 'navigation_id is not nil'} do + it 'can navigate to a url' do browsing_context = described_class.new(driver: driver, type: :tab) info = browsing_context.navigate url: url_for('/bidi/logEntryAdded.html') expect(browsing_context.id).not_to be_nil - expect(info.navigation_id).to be_nil expect(info.url).to include('/bidi/logEntryAdded.html') end - it 'can navigate to a url with readiness state', except: {browser: :chrome} do + it 'can navigate to a url with readiness state' do browsing_context = described_class.new(driver: driver, type: :tab) info = browsing_context.navigate url: url_for('/bidi/logEntryAdded.html'), readiness_state: :complete expect(browsing_context.id).not_to be_nil - expect(info.navigation_id).to be_nil expect(info.url).to include('/bidi/logEntryAdded.html') end - it 'can get tree with a child', except: {browser: :chrome} do + it 'can get tree with a child', except: {browser: %i[chrome edge]} do browsing_context_id = driver.window_handle parent_window = described_class.new(driver: driver, browsing_context_id: browsing_context_id) parent_window.navigate(url: url_for('iframes.html'), @@ -87,7 +84,7 @@ class BiDi expect(context_info.children[0]['url']).to include('formPage.html') end - it 'can get tree with depth', except: {browser: :chrome, reason: 'not yet implemented'} do + it 'can get tree with depth', except: {browser: %i[chrome edge], reason: 'not yet implemented'} do browsing_context_id = driver.window_handle parent_window = described_class.new(driver: driver, browsing_context_id: browsing_context_id) parent_window.navigate(url: url_for('iframes.html'), diff --git a/rb/spec/integration/selenium/webdriver/bidi_spec.rb b/rb/spec/integration/selenium/webdriver/bidi_spec.rb index ebc583ec2a8fd..497f066ad74df 100644 --- a/rb/spec/integration/selenium/webdriver/bidi_spec.rb +++ b/rb/spec/integration/selenium/webdriver/bidi_spec.rb @@ -23,7 +23,12 @@ module Selenium module WebDriver describe BiDi, only: {browser: %i[chrome edge firefox]} do before { reset_driver!(web_socket_url: true) } - after { quit_driver } + + after do + quit_driver + rescue Selenium::WebDriver::Error::InvalidSessionIdError + # do nothing + end it 'gets session status' do status = driver.bidi.session.status @@ -52,6 +57,32 @@ module WebDriver level: BiDi::LogInspector::LOG_LEVEL[:ERROR] ) end + + it 'does not close BiDi session if at least one window is opened' do + status = driver.bidi.session.status + expect(status.ready).to be false + expect(status.message).to be_a String + + driver.switch_to.new_window(:window) + driver.switch_to.new_window(:tab) + driver.switch_to.new_window(:tab) + + driver.close + + status_after_closing = driver.bidi.session.status + expect(status_after_closing.ready).to be false + expect(status_after_closing.message).to be_a String + end + + it 'closes BiDi session if last window is closed' do + status = driver.bidi.session.status + expect(status.ready).to be false + expect(status.message).to be_a String + + driver.close + + expect { driver.bidi.session.status }.to raise_error(IOError) + end end end end