From d826d27a987aef45bc5c5edab8cfbad55ee088fc Mon Sep 17 00:00:00 2001 From: alpaca-tc Date: Mon, 28 Oct 2024 12:20:12 +0900 Subject: [PATCH] Add Capybara.touched_session_names method to retrieve used session names This method returns the names of all currently active sessions that have been used with `using_session`. Its primary purpose is to call `save_screenshot` for multiple sessions when a test fails. Previously, it was difficult to retrieve session names during tests. With this addition, developers can now easily obtain all session names and save screenshots for each active session, enhancing debugging capabilities in multi-session test scenarios. --- lib/capybara.rb | 19 ++++++++++++++++++- lib/capybara/session.rb | 11 +++++++++++ spec/dsl_spec.rb | 28 ++++++++++++++++++++++++++++ spec/session_spec.rb | 13 +++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/lib/capybara.rb b/lib/capybara.rb index 41c9b5f73..02472957f 100644 --- a/lib/capybara.rb +++ b/lib/capybara.rb @@ -314,7 +314,7 @@ def using_wait_time(seconds) # @return [Capybara::Session] The currently used session # def current_session - specified_session || session_pool["#{current_driver}:#{session_name}:#{app.object_id}"] + specified_session || session_pool[build_session_key(session_name)] end ## @@ -407,6 +407,19 @@ def HTML(html) # rubocop:disable Naming/MethodName end end + ## + # + # Returns a list of session names that have been actively used. + # + # @return [Array] A list of session names + # + def touched_session_names + session_pool.keys.filter_map do |key| + session_name = key.split(':')[1].to_sym + session_name if key == build_session_key(session_name) && session_pool[key].touched? + end + end + def session_options config.session_options end @@ -417,6 +430,10 @@ def config @config ||= Capybara::Config.new end + def build_session_key(session_name) + "#{current_driver}:#{session_name}:#{app.object_id}" + end + def session_pool @session_pool ||= Hash.new do |hash, name| hash[name] = Capybara::Session.new(current_driver, app) diff --git a/lib/capybara/session.rb b/lib/capybara/session.rb index 1451a91af..d72d3f61d 100644 --- a/lib/capybara/session.rb +++ b/lib/capybara/session.rb @@ -109,6 +109,17 @@ def driver end end + ## + # + # Returns true if the current session has been touched, indicating it has been actively used. + # This returns true after a `visit` action and false after `quit` or `reset!`. + # + # @return [Boolean] true if the session has been used, false otherwise + # + def touched? + @touched + end + ## # # Reset the session (i.e. remove cookies and navigate to blank page). diff --git a/spec/dsl_spec.rb b/spec/dsl_spec.rb index 02795b091..5ea506fed 100644 --- a/spec/dsl_spec.rb +++ b/spec/dsl_spec.rb @@ -257,6 +257,34 @@ class TestClass end end + describe '#touched_session_names' do + before do + Capybara.send(:session_pool).clear + end + + it 'returns available session names' do + Capybara.current_session.visit '/' + expect(Capybara.touched_session_names).to contain_exactly(:default) + + Capybara.using_session(:administrator) do + Capybara.current_session.visit '/' + end + expect(Capybara.touched_session_names).to contain_exactly(:default, :administrator) + end + + it "doesn't return unmatched app session names" do + old_app = Capybara.app + + Capybara.current_session.visit '/' + expect(Capybara.touched_session_names).to contain_exactly(:default) + + Capybara.app = Class.new(old_app) + expect(Capybara.touched_session_names).to be_empty + ensure + Capybara.app = old_app + end + end + describe '#session_name' do it 'should default to :default' do expect(Capybara.session_name).to eq(:default) diff --git a/spec/session_spec.rb b/spec/session_spec.rb index 0436d8b22..e97c7b944 100644 --- a/spec/session_spec.rb +++ b/spec/session_spec.rb @@ -17,6 +17,19 @@ end end + describe '#touched?' do + it 'returns state of modified session' do + session = described_class.new(:rack_test, TestApp) + expect(session.touched?).to eq(false) + + session.visit '/' + expect(session.touched?).to eq(true) + + session.reset! + expect(session.touched?).to eq(false) + end + end + context 'current_driver' do around do |example| orig_driver = Capybara.current_driver