-
-
Save obie/1886393 to your computer and use it in GitHub Desktop.
| def be_guest_member_of(expected) | |
| Class.new do | |
| def initialize(expected) | |
| @expected = expected | |
| end | |
| def matches?(target) | |
| @target = target | |
| @target.memberships.where(role: "guest").map(&:network).include? @expected | |
| end | |
| def failure_message_for_should | |
| "expected #{@target.inspect} to be a guest member of #{@expected.inspect}" | |
| end | |
| def failure_message_for_should_not | |
| "expected #{@target.inspect} to not be a guest member of #{@expected.inspect}" | |
| end | |
| end.new(expected) | |
| end | |
| # usage example | |
| user1.should be_guest_member_of network2 | |
| user1.should_not be_guest_member_of network1 |
@obie every time you use the matcher, a new class is created and after that is instantiated.
You may want to do that:
module Matchers
extend RSpec::Matchers::DSL
matcher :have_disabled_field do |field|
match do |page|
page.find_field(field)[:disabled].should eq 'true'
end
failure_message_for_should do |page|
"expected #{page.text.inspect} to have disabled field #{field.inspect}"
end
failure_message_for_should_not do |page|
"expected #{page.text.inspect} not to have disabled field #{field.inspect}"
end
end
matcher :have_disabled_button do |field|
match do |page|
page.find_button(field)[:disabled].should eq 'true'
end
failure_message_for_should do |page|
"expected #{page.text.inspect} to have disabled button #{field.inspect}"
end
failure_message_for_should_not do |page|
"expected #{page.text.inspect} not to have disabled button #{field.inspect}"
end
end
matcher :have_notice do |notice|
match do |page|
page.should have_css(".notice", :text => notice)
end
failure_message_for_should do |page|
"expected #{page.text.inspect} to have notice #{notice.inspect}"
end
failure_message_for_should_not do |page|
"expected #{page.text.inspect} not to have notice #{notice.inspect}"
end
end
matcher :have_alert do |alert|
match do |page|
page.should have_css(".alert", :text => alert)
end
failure_message_for_should do |page|
"expected #{page.text.inspect} to have alert #{alert.inspect}"
end
failure_message_for_should_not do |page|
"expected #{page.text.inspect} not to have alert #{alert.inspect}"
end
end
end
RSpec.configure do |config|
config.include Matchers, :type => :request
endI didn't make a benchmark but is obviously that creating a new class every time you use the matcher will be slow :)
@supaspoida, methinks the more appropriate question here would be as to what is the specific benefit of that class being anonymous?
@dexterous No benefit, in fact probably harmful given the matcher DSL example provided by @sobrinho :)
@obie yeah; in fact, given that the class isn't built dynamically using the parameter to be_guest_member_of, simply pulling the class out of the function and naming it might boost, not just performance, but also clarity of intent by at least an order of magnitude.
RSpec::Matchers also has a .define that will take care of the config stuff for you. Throw it in spec/support like so:
RSpec::Matchers.define :be_guest_member_of do |expected|
match do |target|
target.memberships.where(role: "guest").map(&:network).include? expected
end
failure_message_for_should do |target|
"expected #{target.inspect} to be a guest member of #{expected.inspect}"
end
failure_message_for_should_not do |target|
"expected #{target.inspect} to not be a guest member of #{expected.inspect}"
end
endI would argue that this is the cleanest way to go, but make no claims regarding performance.
I do think in this case that reaching through so many associations like that is an indicator that the design should change to improve the tests though.
@sobrinho what do you mean?