dchelimsky/rspec — Issue #55: Custom matchers keep state between specs
Author: artemave
Created: 2012-02-27 13:48:53+00:00
State: open

I've come across this counter intuitive behavior in RSpec (2.8.0) custom matchers functionality and I wonder whether it is a bug or feature or me being confused. Here is the code:

```ruby
# matcher code
RSpec::Matchers.define :exist do
chain :with_start_time do |time|
@start_time = time
end

chain :with_end_time do |time|
@end_time = time
end

match do |subject|
result = true
result &&= subject.start_time == @start_time if @start_time
result &&= subject.end_time == @end_time if @end_time
result
end

failure_message_for_should do |subject|
"Failure!\n".tap do |msg|
if @start_time != subject.start_time
msg << "Expected start_time to be #@start_time but was #{subject.start_time}\n"
end
if @end_time != subject.end_time
msg << "Expected end_time to be #@end_time but was #{subject.end_time}\n"
end
end
end
end

#spec code
require 'ostruct'

describe 'RSpec custom matcher keeping state between tests' do
let(:time) { Time.now }

it 'passes the first spec' do
o = OpenStruct.new(start_time: time)
o.should exist.with_start_time(time)
end

it 'fails the second because matcher kept @start_time from the first test' do
o = OpenStruct.new(end_time: time)
o.should exist.with_end_time(time)
end
end
```

This fails (demonstrating the issue):

```
avetia01:~/projects/custom_matcher_bug% rspec test_spec.rb
.F

Failures:

1) RSpec custom matcher keeping state between tests fails the second because matcher kept @start_time from the first test
Failure/Error: o.should exist.with_end_time(time)
Failure!
Expected start_time to be 2012-02-27 12:20:25 +0000 but was
# ./test_spec.rb:41:in `block (2 levels) in '

Finished in 0.00116 seconds

2 examples, 1 failure
```

So the unexpected bit is that the same matcher instance seems to be used across multiple specs. Which, in this particular case leads, to `@start_time` being initialized with the value from the first spec, causing incorrect failure of the second spec.