diff --git a/CHANGELOG.md b/CHANGELOG.md index 61a32f1..de3f20a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## master +- Allow to match failure reasons with RSpec DSL. ([@inkstak]) + ## 0.7.2 (2024-11-21) - Fix missing details in deny! message interpolation. ([@palkan][]) diff --git a/docs/testing.md b/docs/testing.md index 413a824..904993e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -104,6 +104,12 @@ describe PostPolicy do before { user.role = "manager" } end end + + # `failed` allowed to validates feailures reasons when they are provided + # (see Failure Reasons) + failed "when post is archived", reason: {post: [{archived?: {since: "2 days"}}]} + before { post.archived_at = 2.days.ago } + end end end ``` diff --git a/lib/action_policy/rspec/dsl.rb b/lib/action_policy/rspec/dsl.rb index 9d34cdb..e8962a3 100644 --- a/lib/action_policy/rspec/dsl.rb +++ b/lib/action_policy/rspec/dsl.rb @@ -87,8 +87,8 @@ def formatted_policy(policy) end case reason - when nil then next - when Hash then next if subject.reasons.details == reason + when nil then next + when Hash then next if subject.reasons.details == reason when Symbol then next if subject.reasons.details.values.flatten.include?(reason) when String then next if subject.reasons.full_messages.flatten.include?(reason) else @@ -97,7 +97,7 @@ def formatted_policy(policy) raise( RSpec::Expectations::ExpectationNotMetError, - "Expected to fail with #{reason.inspect} but but actually failed for another reason:\n#{subject.inspect}", + "Expected to fail with #{reason.inspect} but but actually failed for another reason:\n#{formatted_policy(policy)}}", the_caller ) end diff --git a/spec/action_policy/dsl_spec.rb b/spec/action_policy/dsl_spec.rb index 4378718..c414eea 100644 --- a/spec/action_policy/dsl_spec.rb +++ b/spec/action_policy/dsl_spec.rb @@ -28,6 +28,15 @@ def show? def manage? user.admin? && !record.admin? end + + def delete? + user.admin? && check?(:not_admin?) + end + + def not_admin? + details[:username] = record.name + !record.admin? + end end describe UserPolicy, type: :policy do @@ -74,4 +83,40 @@ def manage? end end end + + describe_rule :delete? do + let(:user) { admin } + let(:record) { User.new("admin") } + + failed "and reason matches", reason: {user: [{not_admin?: {username: "admin"}}]} + + context "test errors with reasons" do + after do |ex| + msg = ex.exception.message + # mark as not failed + ex.remove_instance_variable(:@exception) + + puts + puts msg + puts + + expect(msg).to include(<<~MESSAGE.strip) + Expected to fail with :unexpected but but actually failed for another reason: + [{:not_admin?=>{:username=>"admin"}}]}) + MESSAGE + + if ActionPolicy::PrettyPrint.available? + expect(msg).to include(<<~MESSAGE.strip) + ↳ user.admin? #=> #{ActionPolicy::PrettyPrint.colorize(true)} + AND + check?(:not_admin?) #=> #{ActionPolicy::PrettyPrint.colorize(false)} + MESSAGE + end + end + + failed reason: :unexpected do + let(:record) { User.new("admin") } + end + end + end end