-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
#have_error
spec expectation (#1062)
* Add `#have_error` spec expectation * Add missing method return types * Fix lint errors As reported by *Ameba*: ``` src/avram/expectations/have_custom_error_expectation.cr:29:7 [Correctable] [C] Style/RedundantReturn: Redundant `return` detected > return <<-MSG ^ src/avram/expectations/have_error_expectation.cr:67:29 [W] Lint/ShadowingOuterLocalVar: Shadowing outer local variable `errors` > errors.join do |name, errors| ```
- Loading branch information
Showing
5 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
112 changes: 112 additions & 0 deletions
112
spec/avram/expectations/have_custom_error_expectation_spec.cr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
require "../../spec_helper" | ||
|
||
private class SaveEmailAddress < EmailAddress::SaveOperation | ||
end | ||
|
||
include Avram::Expectations | ||
|
||
describe Avram::Expectations::HaveCustomErrorExpectation do | ||
describe "#have_error" do | ||
context "in positive assertions" do | ||
it "passes if attribute is invalid" do | ||
operation = SaveEmailAddress.new | ||
operation.add_error(:providers, "is empty") | ||
|
||
operation.should have_error | ||
operation.should have_error("is empty") | ||
operation.should have_error(/\sempty/) | ||
|
||
operation.should have_error(:providers) | ||
operation.should have_error(:providers, "is empty") | ||
operation.should have_error(:providers, /\sempty/) | ||
end | ||
|
||
it "fails if attribute is valid" do | ||
operation = SaveEmailAddress.new | ||
|
||
expect_raises Spec::AssertionFailed, "have an error" do | ||
operation.should have_error(:providers) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error(:providers, "is empty") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error(:providers, /\sempty/) | ||
end | ||
end | ||
|
||
it "fails if attribute is invalid but without the given message" do | ||
operation = SaveEmailAddress.new | ||
operation.add_error(:providers, "is empty") | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error("wrong message") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error(/\smessage/) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error(:providers, "wrong message") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error(:providers, /\smessage/) | ||
end | ||
end | ||
end | ||
|
||
context "in negative assertions" do | ||
it "passes if attribute is valid" do | ||
operation = SaveEmailAddress.new | ||
|
||
operation.should_not have_error(:providers) | ||
operation.should_not have_error(:providers, "is empty") | ||
operation.should_not have_error(:providers, /\sempty/) | ||
end | ||
|
||
it "fails if attribute is invalid" do | ||
operation = SaveEmailAddress.new | ||
operation.add_error(:providers, "is empty") | ||
|
||
expect_raises Spec::AssertionFailed, "not have an error" do | ||
operation.should_not have_error | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.should_not have_error("is empty") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.should_not have_error(/\sempty/) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have an error" do | ||
operation.should_not have_error(:providers) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.should_not have_error(:providers, "is empty") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.should_not have_error(:providers, /\sempty/) | ||
end | ||
end | ||
|
||
it "passes if attribute is invalid but without the given message" do | ||
operation = SaveEmailAddress.new | ||
operation.add_error(:providers, "is required") | ||
|
||
operation.should_not have_error("wrong message") | ||
operation.should_not have_error(/\smessage/) | ||
|
||
operation.should_not have_error(:providers, "wrong message") | ||
operation.should_not have_error(:providers, /\smessage/) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
require "../../spec_helper" | ||
|
||
private class SaveEmailAddress < EmailAddress::SaveOperation | ||
end | ||
|
||
include Avram::Expectations | ||
|
||
describe Avram::Expectations::HaveErrorExpectation do | ||
describe "#have_error" do | ||
context "in positive assertions" do | ||
it "passes if attribute is invalid" do | ||
operation = SaveEmailAddress.new | ||
operation.address.add_error("is required") | ||
|
||
operation.should have_error | ||
operation.should have_error("is required") | ||
operation.should have_error(/\srequired/) | ||
|
||
operation.address.should have_error | ||
operation.address.should have_error("is required") | ||
operation.address.should have_error(/\srequired/) | ||
end | ||
|
||
it "fails if attribute is valid" do | ||
operation = SaveEmailAddress.new | ||
|
||
expect_raises Spec::AssertionFailed, "have an error" do | ||
operation.should have_error | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error" do | ||
operation.should have_error("is required") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error" do | ||
operation.should have_error(/\srequired/) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have an error" do | ||
operation.address.should have_error | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.address.should have_error("is required") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.address.should have_error(/\srequired/) | ||
end | ||
end | ||
|
||
it "fails if attribute is invalid but without the given message" do | ||
operation = SaveEmailAddress.new | ||
operation.address.add_error("is required") | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error("wrong message") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.should have_error(/\smessage/) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.address.should have_error("wrong message") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "have the error " do | ||
operation.address.should have_error(/\smessage/) | ||
end | ||
end | ||
end | ||
|
||
context "in negative assertions" do | ||
it "passes if attribute is valid" do | ||
operation = SaveEmailAddress.new | ||
|
||
operation.should_not have_error | ||
operation.should_not have_error("is required") | ||
operation.should_not have_error(/\srequired/) | ||
|
||
operation.address.should_not have_error | ||
operation.address.should_not have_error("is required") | ||
operation.address.should_not have_error(/\srequired/) | ||
end | ||
|
||
it "fails if attribute is invalid" do | ||
operation = SaveEmailAddress.new | ||
operation.address.add_error("is required") | ||
|
||
expect_raises Spec::AssertionFailed, "not have an error" do | ||
operation.should_not have_error | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.should_not have_error("is required") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.should_not have_error(/\srequired/) | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have an error" do | ||
operation.address.should_not have_error | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.address.should_not have_error("is required") | ||
end | ||
|
||
expect_raises Spec::AssertionFailed, "not have the error " do | ||
operation.address.should_not have_error(/\srequired/) | ||
end | ||
end | ||
|
||
it "passes if attribute is invalid but without the given message" do | ||
operation = SaveEmailAddress.new | ||
operation.address.add_error("is required") | ||
|
||
operation.should_not have_error("wrong message") | ||
operation.should_not have_error(/\smessage/) | ||
|
||
operation.address.should_not have_error("wrong message") | ||
operation.address.should_not have_error(/\smessage/) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
module Avram::Expectations | ||
# Tests that an operation or attribute has an error | ||
# | ||
# ``` | ||
# CreateReceipt.create(params) do |operation, receipt| | ||
# receipt.should be_nil | ||
# | ||
# operation.should have_error | ||
# operation.should have_error("is required") | ||
# operation.should have_error(/\srequired/) | ||
# | ||
# operation.user_id.should have_error | ||
# operation.user_id.should have_error("is required") | ||
# operation.user_id.should have_error(/\srequired/) | ||
# end | ||
# ``` | ||
def have_error(message = nil) | ||
HaveErrorExpectation.new(message) | ||
end | ||
|
||
# Tests that an operation has a custom error | ||
# | ||
# ``` | ||
# CreateUser.create(params) do |operation, user| | ||
# user.should be_nil | ||
# | ||
# operation.should have_error(:roles) | ||
# operation.should have_error(:roles, "is empty") | ||
# operation.should have_error(:roles, /\sempty/) | ||
# end | ||
# ``` | ||
def have_error(name : Symbol, message = nil) | ||
HaveCustomErrorExpectation.new(name, message) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
module Avram::Expectations | ||
struct HaveCustomErrorExpectation | ||
def initialize(@name : Symbol, @message : Regex? = nil) | ||
end | ||
|
||
def self.new(name, message : String) | ||
new(name, /#{message}/) | ||
end | ||
|
||
def match(operation : OperationErrors) : Bool | ||
return false unless errors = operation.custom_errors[@name]? | ||
@message.try { |message| return errors.any?(&.=~ message) } | ||
!errors.empty? | ||
end | ||
|
||
def failure_message(operation : OperationErrors) : String | ||
@message.try do |message| | ||
return "Expected :#{@name} to have the error '#{message.source}'" | ||
end | ||
|
||
"Expected :#{@name} to have an error" | ||
end | ||
|
||
def negative_failure_message(operation : OperationErrors) : String | ||
@message.try do |message| | ||
return "Expected :#{@name} to not have the error '#{message.source}'" | ||
end | ||
|
||
<<-MSG | ||
Expected :#{@name} to not have an error, got errors: | ||
#{HaveErrorExpectation.list(operation.custom_errors[@name])} | ||
MSG | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
module Avram::Expectations | ||
struct HaveErrorExpectation | ||
def initialize(@message : Regex? = nil) | ||
end | ||
|
||
def self.new(message : String) | ||
new(/#{message}/) | ||
end | ||
|
||
def match(attribute : Attribute) : Bool | ||
@message.try do |message| | ||
return attribute.errors.any?(&.=~ message) | ||
end | ||
|
||
!attribute.errors.empty? | ||
end | ||
|
||
def match(operation : OperationErrors) : Bool | ||
@message.try do |message| | ||
return operation.errors.flat_map { |_, errors| errors }.any? do |error| | ||
error =~ message | ||
end | ||
end | ||
|
||
!operation.errors.empty? | ||
end | ||
|
||
def failure_message(attribute : Attribute) : String | ||
@message.try do |message| | ||
return "Expected :#{attribute.name} to have the error '#{message.source}'" | ||
end | ||
|
||
"Expected :#{attribute.name} to have an error" | ||
end | ||
|
||
def failure_message(operation : OperationErrors) : String | ||
@message.try do |message| | ||
return "Expected operation to have the error '#{message.source}'" | ||
end | ||
|
||
"Expected operation to have an error" | ||
end | ||
|
||
def negative_failure_message(attribute : Attribute) : String | ||
@message.try do |message| | ||
return "Expected :#{attribute.name} to not have the error '#{message.source}'" | ||
end | ||
|
||
<<-MSG | ||
Expected :#{attribute.name} to not have an error, got errors: | ||
#{self.class.list(attribute.errors)} | ||
MSG | ||
end | ||
|
||
def negative_failure_message(operation : OperationErrors) : String | ||
@message.try do |message| | ||
return "Expected operation to not have the error '#{message.source}'" | ||
end | ||
|
||
<<-MSG | ||
Expected operation to not have an error, got errors: | ||
#{self.class.list(operation.errors)} | ||
MSG | ||
end | ||
|
||
protected def self.list(errors : Hash) | ||
errors.join do |name, _errors| | ||
list _errors.map { |error| "#{name}: #{error}" } | ||
end | ||
end | ||
|
||
protected def self.list(errors : Array) | ||
errors.join do |error| | ||
<<-ERROR | ||
- #{error} | ||
ERROR | ||
end | ||
end | ||
end | ||
end |