New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Access to arbitrary options metadata within "before" block #42
Comments
Green light! I'd like to have it work through the running_example variable though, not just options, to keep the local namespace uncluttered. Either of these would work for me: RSpec.configure do |config| config.before :each do Capybara.current_driver = :culerity if running_example[:js] end end RSpec.configure do |config| config.before :each do Capybara.current_driver = :culerity if running_example.options[:js] end end Separate, but related, what do you think about renaming running_example to example? |
Yes, makes sense to avoid cluttering the local namespace. Looking at the options:
Option "2" reads nicest to me because it is close to the English "if the example option foo is set". I'll go with that for now. Will start playing and see if I can knock a patch together before the day is out. |
Great. Thanks! |
Ok, have something now. Seeing as you can't attach patches to Github tickets, have pushed a few commits to forks here: http://github.com/wincent/rspec-core/commits/core-ticket-42 And here: http://github.com/wincent/rspec-rails/commits/core-ticket-42 Specifically we're talking about these commits: http://github.com/wincent/rspec-core/commit/99f0428d53b98cee8a60250d1347224f3dbc5697 The actual changes to the codebase were trivial (20 minutes of coding), but I've had quite a bit of trouble and spent several hours trying to keep the specs and features passing. One of the problems is that it is quite fiddly if you make a change which requires simultaneous modifications across different repos. For example, the renaming of "running_example" to "example" in rspec-core requires changes in rspec-rails because the latter uses "running_example". So you make the change in both repos at once, but you get failures in rspec-rails because it is using the system version of rspec-core rather than the local one. The spec failures can be fixed by tweaking the Gemfile in the generated example Rails app so that it uses the local version of rspec-core instead of some other version that it might pull from elsewhere on the system. (That's what commit 0c5801a412bfd does.) In this way you can make the change in both rspec-core and rspec-rails at the same time, and all specs keep passing. The feature failures are another matter entirely. Cucumber insists on using some other version of rspec-core rather than the local one. I've spent hours trying to find out why, but I'm afraid I have to give up. That in turn means I am not so confident about commit 66c5df14c5f7e. In particular I am not sure about the change to lib/rspec/rails/adapters.rb. I changed the instance variable name from @running_example to @example in the "method_name" method, but I don't even know what that method does, and the specs/features pass irrespective of what the instance variable is called. So, take a look at the commits and perhaps you can see something that I can't that explains how to get Cucumber to use the right version of rspec-core. In any case, with these commits we can do stuff like:
There is one possible further modification that I was playing around with, but it is a bit more invasive so I haven't committed anything yet. The thing is that in a "before :all" block there is obviously no "running example" at that point, so if the user tries to do something like this they'll bomb out because "example" is nil at this point:
At that point we're executing within the scope of a RSpec::Core::ExampleGroup class, so if we ask for "example" we hit the "example" accessor and get nil back. Note:
The idea I was playing with was in that context, returning a different non-nil object (probably a Metadata subclass) that responds to "options", and would return the user-supplied metadata passed in at the describe-block level. ie:
So you could define your metadata at any level, and access it at any level. Not sure if this is opening up a can of worms, though, cause then we'd have to think about how this metadata should "trickle" down when nesting is involved, e.g:
|
There's a lot to review in that comment and I'm pressed for time this minute, but re: the name change - we'll want to deprecate running_example as there are other consumers of that method in the wild. So in rspec-core, something like: def example # code moved from running_example end def running_example RSpec.deprecate("running_example", "example") example end Then you don't have to worry about the other libs just yet and they can move independently. |
Ah, yes, good idea. I'd seen the "RSpec.deprecate" in a couple places in the codebase but didn't think to use it. |
Added the deprecation warning as suggested: http://github.com/wincent/rspec-core/commit/272c3762fa0af775f0c7d23afffa3196bb7ad81c |
Merged - thanks!!!!! |
This allows custom behavior in before blocks that can be triggered by passing in arbitrary metadata to the "it" method when setting up the example: it 'should be special', :special => true do ... end The custom behavior can be set-up, for example, using config.before: RSpec.configure do |config| config.before :each do special_setup if example.options[:special] end end Closes rspec#42.
Just for the record, since this issue is what I found using "rspec metadata before" search-engine query and since I couldn't find it documented anywhere. This behaviour can be achieved in a up-to-date rspec version the following way: before do |example|
example.metadata[:foo] # => true
end
it "should behave", :foo => true do
end |
I'm trying to use Steak and Capybara to run some scenarios using a JavaScript-capable backend (Culerity) and others using the standard rack_test backend.
In Cucumber this was done using tags, but with Steak and RSpec 1.3 I'm told you can do something like this:
This is enabled by this config:
Under RSpec 2 this trick won't work; it seems that "options" isn't available in the scope of these before/after config blocks. I've been able to dig out the options via some very ugly "instance_variable_get" inspection:
So this ticket is about getting access to the arbitrary metadata that can be passed in to "describe" and "it" blocks via the options hash.
Note that in the use case I'm talking about above, using the "filter_run" stuff won't give me what I want (that's for selecting a subset of the examples to run, but I want to run all of the examples, but switch Capybara drivers on the fly).
What do you think about providing access to the options via an accessor?
I've noticed that I can get at the options passed in to the RSpec::Core::Example subclass; ie:
But I can't seem to get at the stuff passed in to the RSpec::Core::ExampleGroup subclass; ie:
In practice I don't really care too much about access to that metadata, because I want to switch drivers on a per-scenario basis (ie. at the "it/scenario" level). But if you agree to making the metadata available at that level, I guess it makes sense to make the metadata at the "describe/feature" level available too.
What do you think?
If I can get a "green light" on the idea I'm happy to put a patch together.
Cheers,
Wincent
The text was updated successfully, but these errors were encountered: