Skip to content

Instantly share code, notes, and snippets.

@jaimerson
Created September 25, 2019 22:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaimerson/6a538d361276101c01add6c171c1bd1b to your computer and use it in GitHub Desktop.
Save jaimerson/6a538d361276101c01add6c171c1bd1b to your computer and use it in GitHub Desktop.
RSpec custom matchers
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rspec'
end
require 'rspec/autorun'
class Car
attr_reader :make, :model, :year, :doors
def initialize(make: 'Chevrolet', model: 'Impala', year: 1967, doors: 2)
@make = make
@model = model
@year = year
@doors = doors
end
end
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.include_chain_clauses_in_custom_matcher_descriptions = true
end
end
RSpec.describe Car do
specify do
expect(Car.new).to be_made_by('Chevrolet')
.and have_model('Impala')
.and have_been_made_in(1967)
.and have_two_doors
end
specify do
expect(Car.new(doors: 4)).to not_be_made_by('Nissan')
.and not_have_model('Skyline')
.and not_have_been_made_in(2010)
.and not_have_two_doors
end
specify do
car = Car.new(year: 1980)
expect(car).to have_been_made_after(1970)
.and_before(1990)
end
context 'when using information from the context' do
let(:today) do
require 'date'
Date.ordinal(2019, -1) # 31/12/2019
end
specify do
car = Car.new(year: 1960)
expect(car).to be_older_than(1980)
.and be_older_than(40).years
end
end
matcher :be_older_than do
match do |actual|
if @older_than_year
today - actual.year > expected
else
have_been_made_before(expected)
end
end
chain :years do
@older_than_year = true
end
end
matcher :have_been_made_before do
match do |actual|
actual.year < expected
end
end
matcher :have_been_made_after do
match do |actual|
made_after = actual.year > expected
if @before_year
made_after && actual.year < @before_year
else
made_after
end
end
match_when_negated do |actual|
if @before_year
fail ArgumentError, "You can't chain `and_before` when using negated version"
end
actual.year <= expected
end
chain :and_before do |before_year|
@before_year = before_year
end
description do
desc = "be manufactured after #{expected}"
desc << " and before #{@before_year}" if @before_year
end
failure_message do |actual|
message = "Expected #{actual} to have been made after #{expected}"
message << " and before #{@before_year}" if @before_year
message << " but it was made in #{actual.year}."
end
RSpec::Matchers.define_negated_matcher :not_have_been_made_after, :have_been_made_after
end
matcher :be_made_by do
match do |actual|
actual.make == expected
end
RSpec::Matchers.define_negated_matcher :not_be_made_by, :be_made_by
end
matcher :have_model do
match do |actual|
actual.model == expected
end
RSpec::Matchers.define_negated_matcher :not_have_model, :have_model
end
matcher :have_been_made_in do
match do |actual|
actual.year == expected
end
RSpec::Matchers.define_negated_matcher :not_have_been_made_in, :have_been_made_in
end
matcher :have_two_doors do
match do |actual|
actual.doors == 2
end
RSpec::Matchers.define_negated_matcher :not_have_two_doors, :have_two_doors
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment