From fbd45c3a89991ae14fdfa5d2f11b776f8b4f6f18 Mon Sep 17 00:00:00 2001 From: Tristan Dunn Date: Sun, 9 Jan 2011 17:47:28 -0500 Subject: [PATCH] Add support for temporarily switching between multiple named sessions. --- lib/capybara/dsl.rb | 37 ++++++++++++++++++++++++++++++++- spec/dsl_spec.rb | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/lib/capybara/dsl.rb b/lib/capybara/dsl.rb index 66a921b8..47c1b9e1 100644 --- a/lib/capybara/dsl.rb +++ b/lib/capybara/dsl.rb @@ -57,7 +57,7 @@ module Capybara # @return [Capybara::Session] The currently used session # def current_session - session_pool["#{current_driver}#{app.object_id}"] ||= Capybara::Session.new(current_driver, app) + session_pool[session_namespace] ||= Capybara::Session.new(current_driver, app) end ## @@ -70,8 +70,34 @@ module Capybara end alias_method :reset!, :reset_sessions! + ## + # + # Switch to a different session, referenced by name, execute the provided block and return to + # the default session. This is useful for testing interactions between two browser sessions. + # + def in_session(name, &block) + return unless block_given? + + namespace = "#{session_namespace}:#{name}" + previous_session = current_session + session_pool[namespace] ||= Capybara::Session.new(current_driver, app) + + self.current_session = session_pool[namespace] + yield + ensure + self.current_session = previous_session + end + private + def current_session=(session) + session_pool[session_namespace] = session + end + + def session_namespace + "#{current_driver}#{app.object_id}" + end + def session_pool @session_pool ||= {} end @@ -79,6 +105,15 @@ module Capybara extend(self) + ## + # + # Shortcut to working in a different session. This is useful when Capybara is included + # in a class or module. + # + def in_session(name, &block) + Capybara.in_session(name, &block) + end + ## # # Shortcut to accessing the current session. This is useful when Capybara is included in a diff --git a/spec/dsl_spec.rb b/spec/dsl_spec.rb index 58e4e260..8f0b930a 100644 --- a/spec/dsl_spec.rb +++ b/spec/dsl_spec.rb @@ -125,6 +125,47 @@ describe Capybara do end end + describe "#in_session" do + let!(:default_session) { Capybara.current_session } + + before do + @object_ids = { :default => default_session.object_id } + end + + it "should create unique sessions by name" do + Capybara.in_session(:bob) { @object_ids[:bob] = Capybara.current_session.object_id } + Capybara.in_session(:sue) { @object_ids[:sue] = Capybara.current_session.object_id } + + @object_ids.values.uniq.length.should == 3 + end + + it "should cache sessions by name" do + Capybara.in_session(:bob) { @object_ids[:bob] = Capybara.current_session.object_id } + Capybara.in_session(:sue) { @object_ids[:sue] = Capybara.current_session.object_id } + + Capybara.in_session(:bob) do + @object_ids[:bob].should == Capybara.current_session.object_id + end + Capybara.in_session(:sue) do + @object_ids[:sue].should == Capybara.current_session.object_id + end + end + + it "should reset the session to the default, even if an exception occurs" do + begin + Capybara.in_session(:raise) { raise } + rescue Exception + end + Capybara.current_session.should == default_session + end + + it "should yield the passed block" do + called = false + Capybara.in_session(:other) { called = true } + called.should == true + end + end + describe 'the DSL' do before do @session = Capybara @@ -152,6 +193,15 @@ describe Capybara do foo.page.click_link('ullamco') foo.page.body.should include('Another World') end + + it "should provide an 'in_session' shortcut" do + klass = Class.new do + include Capybara + end + Capybara.should_receive(:in_session).with(:name) + foo = klass.new + foo.in_session(:name) + end end end