From 535fe05be8686fdafd8b22f2ed5c4192bd565d50 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Wed, 19 Nov 2014 16:13:59 -0700 Subject: [PATCH] Consolidate set_session and set_flash APIs * Refactor so they both use SetSessionOrFlashMatcher internally * Remove `set_session['key']` in favor of `set_session('key')` * `set_flash['key'].to(nil)` no longer works if set_flash has never been set --- NEWS.md | 8 +- lib/shoulda/matchers/action_controller.rb | 2 + .../matchers/action_controller/flash_store.rb | 95 +++++ .../action_controller/session_store.rb | 34 ++ .../action_controller/set_flash_matcher.rb | 155 ++------ .../action_controller/set_session_matcher.rb | 137 ++----- .../set_session_or_flash_matcher.rb | 2 +- .../shared_examples/set_session_or_flash.rb | 355 ++++++++++++++++++ .../set_flash_matcher_spec.rb | 150 +------- .../set_session_matcher_spec.rb | 293 +-------------- 10 files changed, 580 insertions(+), 651 deletions(-) create mode 100644 lib/shoulda/matchers/action_controller/flash_store.rb create mode 100644 lib/shoulda/matchers/action_controller/session_store.rb create mode 100644 spec/support/unit/shared_examples/set_session_or_flash.rb diff --git a/NEWS.md b/NEWS.md index 8f3546231..e63327b12 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,7 +13,13 @@ * `ensure_inclusion_of`, `ensure_exclusion_of`, and `ensure_length_of` have been removed in favor of their `validate_*` counterparts. -* `set_the_flash` has been removed in favor of `set_flash`. +* `set_the_flash` and `set_session` have been changed to more closely align with + each other: + * `set_the_flash` has been removed in favor of `set_flash`. + * `set_session('foo')` is no longer valid syntax, please use + `set_session['foo']` instead. + * `set_session['key'].to(nil)` will no longer pass when the key in question + has not been set yet. # 2.8.0 diff --git a/lib/shoulda/matchers/action_controller.rb b/lib/shoulda/matchers/action_controller.rb index fc276c27d..23cf6cca3 100644 --- a/lib/shoulda/matchers/action_controller.rb +++ b/lib/shoulda/matchers/action_controller.rb @@ -11,6 +11,8 @@ require 'shoulda/matchers/action_controller/callback_matcher' require 'shoulda/matchers/action_controller/strong_parameters_matcher' require 'shoulda/matchers/action_controller/set_session_or_flash_matcher' +require 'shoulda/matchers/action_controller/flash_store' +require 'shoulda/matchers/action_controller/session_store' module Shoulda module Matchers diff --git a/lib/shoulda/matchers/action_controller/flash_store.rb b/lib/shoulda/matchers/action_controller/flash_store.rb new file mode 100644 index 000000000..155f30420 --- /dev/null +++ b/lib/shoulda/matchers/action_controller/flash_store.rb @@ -0,0 +1,95 @@ +module Shoulda + module Matchers + module ActionController + # @private + class FlashStore + def self.future + new + end + + def self.now + new.use_now! + end + + attr_accessor :controller + + def initialize + @use_now = false + end + + def name + if @use_now + 'flash.now' + else + 'flash' + end + end + + def has_key?(key) + values_to_check.include?(key) + end + + def has_value?(expected_value) + values_to_check.values.any? do |actual_value| + expected_value === actual_value + end + end + + def empty? + flash.empty? + end + + def use_now! + @use_now = true + self + end + + private + + def flash + @_flash ||= copy_of_flash_from_controller + end + + def copy_of_flash_from_controller + controller.flash.dup.tap do |flash| + copy_flashes(controller.flash, flash) + copy_discard_if_necessary(controller.flash, flash) + # sweep_flash_if_necessary(flash) + end + end + + def copy_flashes(original_flash, new_flash) + flashes = original_flash.instance_variable_get('@flashes').dup + new_flash.instance_variable_set('@flashes', flashes) + end + + def copy_discard_if_necessary(original_flash, new_flash) + discard = original_flash.instance_variable_get('@discard').dup + new_flash.instance_variable_set('@discard', discard) + end + + def sweep_flash_if_necessary(flash) + unless @use_now + flash.sweep + end + end + + def set_values + flash.instance_variable_get('@flashes') + end + + def keys_to_discard + flash.instance_variable_get('@discard') + end + + def values_to_check + if @use_now + set_values.slice(*keys_to_discard.to_a) + else + set_values.except(*keys_to_discard.to_a) + end + end + end + end + end +end diff --git a/lib/shoulda/matchers/action_controller/session_store.rb b/lib/shoulda/matchers/action_controller/session_store.rb new file mode 100644 index 000000000..a63d238b1 --- /dev/null +++ b/lib/shoulda/matchers/action_controller/session_store.rb @@ -0,0 +1,34 @@ +module Shoulda + module Matchers + module ActionController + # @private + class SessionStore + attr_accessor :controller + + def name + 'session' + end + + def has_key?(key) + session.key?(key) + end + + def has_value?(expected_value) + session.values.any? do |actual_value| + expected_value === actual_value + end + end + + def empty? + session.empty? + end + + private + + def session + controller.session + end + end + end + end +end diff --git a/lib/shoulda/matchers/action_controller/set_flash_matcher.rb b/lib/shoulda/matchers/action_controller/set_flash_matcher.rb index 47244f6ef..23b9f9f95 100644 --- a/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +++ b/lib/shoulda/matchers/action_controller/set_flash_matcher.rb @@ -1,3 +1,5 @@ +require 'forwardable' + module Shoulda module Matchers module ActionController @@ -146,151 +148,54 @@ module ActionController # @return [SetFlashMatcher] # def set_flash - SetFlashMatcher.new + SetFlashMatcher.new.in_context(self) end # @private class SetFlashMatcher + extend Forwardable + + def_delegators :underlying_matcher, + :description, + :matches?, + :failure_message, + :failure_message_when_negated + alias_method \ + :failure_message_for_should, + :failure_message + alias_method \ + :failure_message_for_should_not, + :failure_message_when_negated + def initialize - @options = {} - @value = nil + store = FlashStore.future + @underlying_matcher = SetSessionOrFlashMatcher.new(store) end - def to(value) - if !value.is_a?(String) && !value.is_a?(Regexp) - raise "cannot match against #{value.inspect}" - end - @value = value + def now + store = FlashStore.now + @underlying_matcher = SetSessionOrFlashMatcher.new(store) self end - def now - @options[:now] = true + def in_context(context) + underlying_matcher.in_context(context) self end def [](key) - @options[:key] = key + underlying_matcher[key] self end - def matches?(controller) - @controller = controller - sets_the_flash? && string_value_matches? && regexp_value_matches? - end - - def description - description = "set the #{expected_flash_invocation}" - description << " to #{@value.inspect}" unless @value.nil? - description - end - - def failure_message - "Expected #{expectation}" - end - alias failure_message_for_should failure_message - - def failure_message_when_negated - "Did not expect #{expectation}" - end - alias failure_message_for_should_not failure_message_when_negated - - private - - def sets_the_flash? - flash_values.any? - end - - def string_value_matches? - if @value.is_a?(String) - flash_values.any? {|value| value == @value } - else - true - end - end - - def regexp_value_matches? - if @value.is_a?(Regexp) - flash_values.any? {|value| value =~ @value } - else - true - end - end - - def flash_values - if @options.key?(:key) - flash_hash = HashWithIndifferentAccess.new(flash.to_hash) - [flash_hash[@options[:key]]] - else - flash.to_hash.values - end - end - - def flash - @flash ||= copy_of_flash_from_controller - end - - def copy_of_flash_from_controller - @controller.flash.dup.tap do |flash| - copy_flashes(@controller.flash, flash) - copy_discard_if_necessary(@controller.flash, flash) - sweep_flash_if_necessary(flash) - end - end - - def copy_flashes(original_flash, new_flash) - flashes = original_flash.instance_variable_get('@flashes').dup - new_flash.instance_variable_set('@flashes', flashes) - end - - def copy_discard_if_necessary(original_flash, new_flash) - discard_ivar = :@discard - if original_flash.instance_variable_defined?(discard_ivar) - discard = original_flash.instance_variable_get(discard_ivar).dup - new_flash.instance_variable_set(discard_ivar, discard) - end - end - - def sweep_flash_if_necessary(flash) - unless @options[:now] - flash.sweep - end - end - - def expectation - expectation = "the #{expected_flash_invocation} to be set" - expectation << " to #{@value.inspect}" unless @value.nil? - expectation << ", but #{flash_description}" - expectation - end - - def flash_description - if flash.blank? - 'no flash was set' - else - "was #{flash.inspect}" - end - end - - def expected_flash_invocation - "flash#{pretty_now}#{pretty_key}" + def to(expected_value = nil, &block) + underlying_matcher.to(expected_value, &block) + self end - def pretty_now - if @options[:now] - '.now' - else - '' - end - end + protected - def pretty_key - if @options[:key] - "[:#{@options[:key]}]" - else - '' - end - end + attr_reader :underlying_matcher end end end diff --git a/lib/shoulda/matchers/action_controller/set_session_matcher.rb b/lib/shoulda/matchers/action_controller/set_session_matcher.rb index c86bec3ba..67851e9c3 100644 --- a/lib/shoulda/matchers/action_controller/set_session_matcher.rb +++ b/lib/shoulda/matchers/action_controller/set_session_matcher.rb @@ -1,3 +1,5 @@ +require 'forwardable' + module Shoulda module Matchers module ActionController @@ -112,132 +114,49 @@ module ActionController # # @return [SetSessionMatcher] # - def set_session(key = nil) - SetSessionMatcher.new(key) + def set_session + SetSessionMatcher.new.in_context(self) end # @private class SetSessionMatcher - def initialize(key) - if key - Shoulda::Matchers.warn < 'any value') + expect(controller).to set_store + end + end + + context 'if the store is empty' do + it 'rejects' do + controller = controller_with_empty_store + expect(controller).not_to set_store + end + + it 'produces the correct failure message' do + controller = controller_with_empty_store + expected_message = % + + expect { expect(controller).to set_store }. + to fail_with_message(expected_message) + end + end + end + + context 'in the negative' do + context 'if the given key is present in the store' do + it 'produces the correct failure message' do + controller = controller_with_store('any key' => 'any value') + expected_message = % + assertion = proc do + expect(controller).not_to set_store + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + end + + context 'with #[]' do + it 'produces the right description' do + matcher = set_store['the key'] + expected_description = % + + expect(matcher.description).to eq expected_description + end + + context 'in the positive' do + context 'if the given key is present in the store' do + it 'accepts' do + controller = controller_with_store('the key' => 'any value') + expect(controller).to set_store['the key'] + end + end + + context 'if the given key is not present in the store' do + it 'rejects' do + controller = controller_with_empty_store + expect(controller).not_to set_store['the key'] + end + + it 'produces the correct failure message' do + controller = controller_with_empty_store + expected_message = % + assertion = proc do + expect(controller).to set_store['the key'] + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + + context 'in the negative' do + context 'if the given key is present in the store' do + it 'produces the correct failure message' do + controller = controller_with_store('the key' => 'any value') + expected_message = % + assertion = proc do + expect(controller).not_to set_store['the key'] + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + end + + context 'with #to' do + context 'given a static value' do + it 'produces the right description' do + matcher = set_store.to('the value') + expected_description = % + + expect(matcher.description).to eq expected_description + end + + context 'in the positive' do + context 'if the given value is present in the store' do + it 'accepts' do + controller = controller_with_store('any key' => 'the value') + expect(controller).to set_store.to('the value') + end + + it 'accepts given a value of nil' do + controller = controller_with_store('any key' => nil) + expect(controller).to set_store.to(nil) + end + + it 'accepts given a value of false' do + controller = controller_with_store('any key' => false) + expect(controller).to set_store.to(false) + end + end + + context 'if the given value is not present in the store' do + it 'rejects' do + controller = controller_with_empty_store + expect(controller).not_to set_store.to('the value') + end + + it 'rejects checking for nil' do + controller = controller_with_empty_store + expect(controller).not_to set_store.to(nil) + end + + it 'produces the correct failure message' do + controller = controller_with_empty_store + expected_message = % + assertion = proc do + expect(controller).to set_store.to('the value') + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + + context 'in the negative' do + context 'if the given value is present in the store' do + it 'produces the correct failure message' do + controller = controller_with_store('any key' => 'the value') + expected_message = % + assertion = proc do + expect(controller).not_to set_store.to('the value') + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + end + + context 'given a regexp' do + it 'produces the right description' do + matcher = set_store.to(/value/) + expected_description = % + + expect(matcher.description).to eq expected_description + end + + context 'in the positive' do + context 'if the given value is present in the store' do + it 'accepts' do + controller = controller_with_store('any key' => 'the value') + expect(controller).to set_store.to(/value/) + end + + it 'accepts given a value of nil' do + controller = controller_with_store('any key' => nil) + expect(controller).to set_store.to(nil) + end + + it 'accepts given a value of false' do + controller = controller_with_store('any key' => false) + expect(controller).to set_store.to(false) + end + end + + context 'if the given value is not present in the store' do + it 'rejects' do + controller = controller_with_empty_store + expect(controller).not_to set_store.to(/value/) + end + + it 'produces the correct failure message' do + controller = controller_with_empty_store + expected_message = % + assertion = proc do + expect(controller).to set_store.to(/value/) + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + + context 'in the negative' do + context 'if the given value is present in the store' do + it 'produces the correct failure message' do + controller = controller_with_store('any key' => 'the value') + expected_message = % + assertion = proc do + expect(controller).not_to set_store.to(/value/) + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + end + end + + context 'with #[] + #to' do + context 'given a static value' do + it 'produces the right description' do + expected_description = % + matcher = set_store['the key'].to('the value') + + expect(matcher.description).to eq expected_description + end + + context 'in the positive' do + context 'if the given value is present in the store' do + it 'accepts' do + controller = controller_with_store('the key' => 'the value') + expect(controller).to set_store['the key'].to('the value') + end + end + + context 'if the given value is not present in the store' do + it 'rejects' do + controller = controller_with_empty_store + expect(controller).not_to set_store['the key'].to('the value') + end + + it 'produces the correct failure message' do + controller = controller_with_empty_store + expected_message = % + assertion = proc do + expect(controller).to set_store['the key'].to('the value') + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + + context 'in the negative' do + context 'if the given value is present in the store' do + it 'produces the correct failure message' do + controller = controller_with_store('the key' => 'the value') + expected_message = % + assertion = proc do + expect(controller).not_to set_store['the key'].to('the value') + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + end + + context 'given a dynamic value' do + it 'produces the right description' do + context = double('context', method_in_context: 'the value') + matcher = set_store['the key']. + in_context(context). + to { method_in_context } + expected_description = % + + expect(matcher.description).to eq expected_description + end + + context 'in the positive' do + context 'if the value evaluated in the context is present in the store' do + it 'accepts' do + controller = controller_with_store('the key' => 'the value') + context = double('context', method_in_context: 'the value') + + expect(controller).to set_store['the key']. + in_context(context). + to { method_in_context } + end + end + + context 'if the value evaluated in the context is not present in the store' do + it 'rejects' do + controller = controller_with_empty_store + context = double('context', method_in_context: 'the value') + + expect(controller).not_to set_store['the key']. + in_context(context). + to { method_in_context } + end + + it 'produces the correct failure message' do + controller = controller_with_empty_store + context = double('context', method_in_context: 'the value') + expected_message = % + assertion = proc do + expect(controller).to set_store['the key']. + in_context(context). + to { method_in_context } + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + + context 'in the negative' do + context 'if the value evaluated in the context is present in the store' do + it 'produces the correct failure message' do + context = double('context', method_in_context: 'the value') + controller = controller_with_store('the key' => 'the value') + expected_message = % + assertion = proc do + expect(controller).not_to set_store['the key']. + in_context(context). + to { method_in_context } + end + + expect(&assertion).to fail_with_message(expected_message) + end + end + end + end + end + + def controller_with_empty_store + build_fake_response + end + + def controller_with_store(store_contents) + context = self + + build_fake_response do + store = context.store_within(self) + + store_contents.each do |key, value| + store[key] = value + end + end + end +end diff --git a/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb b/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb index f6b0e8a10..5b45e4711 100644 --- a/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb @@ -1,153 +1,43 @@ require 'unit_spec_helper' describe Shoulda::Matchers::ActionController::SetFlashMatcher, type: :controller do - it 'fails with unmatchable #to' do - expect { set_flash.to(1) }.to raise_error('cannot match against 1') - end - - context 'a controller that sets a flash message' do - it 'accepts setting any flash message' do - expect(controller_with_flash(notice: 'hi')).to set_flash - end - - it 'accepts setting the exact flash message' do - expect(controller_with_flash(notice: 'hi')).to set_flash.to('hi') + it_behaves_like 'set session or flash matcher' do + def store_name + 'flash' end - it 'accepts setting a matched flash message' do - expect(controller_with_flash(notice: 'hello')).to set_flash.to(/he/) + def set_store + set_flash end - it 'rejects setting a different flash message' do - expect(controller_with_flash(notice: 'hi')). - not_to set_flash.to('other') - end - - it 'rejects setting a different pattern' do - expect(controller_with_flash(notice: 'hi')). - not_to set_flash.to(/other/) + def store_within(controller) + controller.flash end end - context 'a controller that sets a flash.now message' do - it 'rejects setting any flash message' do - expect(controller_with_flash_now).not_to set_flash + it_behaves_like 'set session or flash matcher' do + def store_name + 'flash.now' end - it 'accepts setting any flash.now message' do - expect(controller_with_flash_now).to set_flash.now + def set_store + set_flash.now end - it 'accepts setting the exact flash.now message' do - expect(controller_with_flash_now(notice: 'hi')). - to set_flash.now.to('hi') - end - - it 'accepts setting a matched flash.now message' do - expect(controller_with_flash_now(notice: 'flasher')). - to set_flash.now.to(/lash/) - end - - it 'rejects setting a different flash.now message' do - expect(controller_with_flash_now(notice: 'hi')). - not_to set_flash.now.to('other') - end - - it 'rejects setting a different flash.now pattern' do - expect(controller_with_flash_now(notice: 'hi')). - not_to set_flash.now.to(/other/) + def store_within(controller) + controller.flash.now end end - context 'a controller that sets flash messages for multiple keys' do - it 'accepts flash message for either key' do - controller = controller_with_flash(notice: 'one', alert: 'two') - - expect(controller).to set_flash[:notice] - expect(controller).to set_flash[:alert] - end - - it 'rejects a flash message that is not one of the set keys' do - expect(controller_with_flash(notice: 'one', alert: 'two')). - not_to set_flash[:warning] - end - - it 'accepts exact flash message of notice' do - expect(controller_with_flash(notice: 'one', alert: 'two')). - to set_flash[:notice].to('one') - end - - it 'accepts setting a matched flash message of notice' do - expect(controller_with_flash(notice: 'one', alert: 'two')). - to set_flash[:notice].to(/on/) - end - - it 'rejects setting a different flash message of notice' do - expect(controller_with_flash(notice: 'one', alert: 'two')). - not_to set_flash[:notice].to('other') - end - - it 'rejects setting a different pattern' do - expect(controller_with_flash(notice: 'one', alert: 'two')). - not_to set_flash[:notice].to(/other/) - end - end - - context 'a controller that sets flash and flash.now' do - it 'accepts setting any flash.now message' do - controller = build_fake_response do - flash.now[:notice] = 'value' - flash[:success] = 'great job' - end - - expect(controller).to set_flash.now - expect(controller).to set_flash - end - - it 'accepts setting a matched flash.now message' do + context 'when the controller sets both flash and flash.now' do + it 'does not mix flash and flash.now' do controller = build_fake_response do - flash.now[:notice] = 'value' - flash[:success] = 'great job' - end - - expect(controller).to set_flash.now.to(/value/) - expect(controller).to set_flash.to(/great/) - end - - it 'rejects setting a different flash.now message' do - controller = build_fake_response do - flash.now[:notice] = 'value' - flash[:success] = 'great job' - end - - expect(controller).not_to set_flash.now.to('other') - expect(controller).not_to set_flash.to('other') - end - end - - context 'a controller that does not set a flash message' do - it 'rejects setting any flash message' do - expect(controller_with_no_flashes).not_to set_flash - end - end - - def controller_with_no_flashes - build_fake_response - end - - def controller_with_flash(flash_hash) - build_fake_response do - flash_hash.each do |key, value| - flash[key] = value + flash['key for flash'] = 'value for flash' + flash.now['key for flash.now'] = 'value for flash.now' end - end - end - def controller_with_flash_now(flash_hash = { notice: 'hi' }) - build_fake_response do - flash_hash.each do |key, value| - flash.now[key] = value - end + expect(controller).not_to set_flash['key for flash.now'] + expect(controller).not_to set_flash.now['key for flash'] end end end diff --git a/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb b/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb index 2bb4b5971..c95565028 100644 --- a/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb @@ -1,294 +1,17 @@ require 'unit_spec_helper' -describe Shoulda::Matchers::ActionController, '#set_session', type: :controller do - context 'passing an argument to the initializer' do - it 'is deprecated in favor of using #[]' do - expectation = proc { set_session(:foo) } - - expect(&expectation).to print_warning_including( - 'Passing a key to set_session is deprecated' - ) - end - - it 'still works regardless' do - silence_warnings do - expect(controller_with_session(var: 'hi')).to set_session(:var) - end - end - end - - context 'a controller that sets a session variable' do - context 'without any qualifiers' do - it 'accepts' do - expect(controller_with_session(var: 'hi')).to set_session - end - end - - context 'with #to' do - context 'given a static value' do - context 'when any key in session has the given value' do - it 'accepts' do - expect(controller_with_session(var: 'hi')). - to set_session.to('hi') - end - - it 'accepts given nil' do - silence_warnings do - expect(controller_with_session(var: nil)). - to set_session.to(nil) - end - end - - it 'accepts given false' do - expect(controller_with_session(var: false)). - to set_session.to(false) - end - end - - context 'when no key in session has the given value' do - it 'rejects' do - expect(controller_with_session(var: 'hi')). - not_to set_session.to('different') - end - end - end - - context 'given a dynamic value' do - context 'when any key in session has the given value' do - it 'accepts' do - context = double(expected: 'hi') - expect(controller_with_session(var: 'hi')). - to set_session.in_context(context).to { expected } - end - - it 'accepts given nil' do - silence_warnings do - context = double(expected: nil) - expect(controller_with_session(var: nil)). - to set_session.in_context(context).to { expected } - end - end - - it 'accepts given false' do - context = double(expected: false) - expect(controller_with_session(var: false)). - to set_session.in_context(context).to { expected } - end - end - - context 'when no key in session has the given value' do - it 'rejects' do - context = double(expected: 'different') - expect(controller_with_session(var: 'hi')). - not_to set_session.in_context(context).to { expected } - end - end - end - - context 'given a regexp' do - context 'when any value in session matches the regexp' do - it 'accepts' do - expect(controller_with_session(var: 'hello')). - to set_session.to(/ello/) - end - end - - context 'when no value in session matches the regexp' do - it 'rejects' do - expect(controller_with_session(var: 'hello')). - not_to set_session.to(/different/) - end - end - end - end - - context 'with #[]' do - context 'when the given key is present in session' do - it 'accepts' do - expect(controller_with_session(var: 'hi')).to set_session[:var] - end - - it 'accepts when expected key is a string' do - expect(controller_with_session(var: 'hi')).to set_session['var'] - end - end - - context 'when the given key is not present in session' do - it 'rejects' do - expect(controller_with_session(var: 'hi')).not_to set_session[:other] - end - end - end - - context 'with #[] + #to' do - context 'given a static value' do - context 'when the given key and value are present in session' do - it 'accepts' do - expect(controller_with_session(var: 'hi')). - to set_session[:var].to('hi') - end - - it 'accepts given nil' do - silence_warnings do - expect(controller_with_session(var: nil)). - to set_session[:var].to(nil) - end - end - - it 'accepts given false' do - expect(controller_with_session(var: false)). - to set_session[:var].to(false) - end - end - - context 'when the given key is present in session but not the given value' do - it 'rejects' do - expect(controller_with_session(var: 'hi')). - not_to set_session[:var].to('other') - end - - it 'rejects given nil' do - expect(controller_with_session(var: 'hi')). - not_to set_session[:var].to(nil) - end - end - - context 'when the given key is not present in session' do - it 'accepts given nil' do - silence_warnings do - expect(controller_with_session(var: 'hi')). - to set_session[:other].to(nil) - end - end - - it 'rejects given false' do - expect(controller_with_session(var: false)). - not_to set_session[:other].to(false) - end - end - end - - context 'given a dynamic value' do - context 'when the given key and value are present in session' do - it 'accepts' do - context = double(expected: 'value') - - expect(controller_with_session(var: 'value')). - to set_session[:var].in_context(context).to { expected } - end - - it 'accepts given nil' do - silence_warnings do - context = double(expected: nil) - - expect(controller_with_session(var: nil)). - to set_session[:var].in_context(context).to { expected } - end - end - - it 'accepts given false' do - context = double(expected: false) - - expect(controller_with_session(var: false)). - to set_session[:var].in_context(context).to { expected } - end - end - - context 'when the given key is present in session but not the given value' do - it 'rejects given nil' do - context = double(expected: nil) - - expect(controller_with_session(var: 'hi')). - not_to set_session[:var].in_context(context).to { expected } - end - - it 'rejects given false' do - context = double(expected: false) - - expect(controller_with_session(var: 'hi')). - not_to set_session[:var].in_context(context).to { expected } - end - end - - context 'when the given key is not present in session' do - it 'rejects' do - context = double(expected: 'other') - - expect(controller_with_session(var: 'unexpected')). - not_to set_session[:var].in_context(context).to { expected } - end - - it 'accepts given nil' do - silence_warnings do - context = double(expected: nil) - - expect(controller_with_session(var: 'hi')). - to set_session[:other].in_context(context).to { expected } - end - end - - it 'rejects given false' do - context = double(expected: false) - - expect(controller_with_session(var: false)). - not_to set_session[:other].in_context(context).to { expected } - end - end - end - end - end - - context 'a controller that does not set any session variables' do - context 'without any qualifiers' do - it 'rejects' do - expect(controller_without_session).not_to set_session - end - end - - context 'with #[]' do - it 'rejects' do - expect(controller_without_session). - not_to set_session['any key'] - end - end - - context 'with #to' do - it 'rejects' do - expect(controller_without_session). - not_to set_session.to('any value') - end +describe Shoulda::Matchers::ActionController::SetSessionMatcher, type: :controller do + it_behaves_like 'set session or flash matcher' do + def store_name + 'session' end - context 'with #[] + #to' do - it 'rejects' do - expect(controller_without_session). - not_to set_session['any key'].to('any value') - end - - it 'prints a warning when using .to(nil) to assert that a variable is unset' do - expectation = proc do - expect(controller_without_session).to set_session['any key'].to(nil) - end - - expected_warning = <