-
-
Notifications
You must be signed in to change notification settings - Fork 760
yield current running example to it/example and before/after hooks #666
Conversation
Interesting idea. I assume this is in response to #663? I like the fact that this creates fewer potential naming conflicts (especially since module SomeHelperMethods
def some_helper_method
if example.metadata[:blah]
do_something
end
end
end
RSpec.configure do |c|
c.include SomeHelperMethods
end In this highly contrived and totally generic example, the helper method is able to directly access the example metadata in a conditional. With your proposed change, this would no longer be possible -- all helper methods that need access to the example would have to accept (and be passed) an So I guess you could say I'm on the fence about this. BTW, if we do make this change, how many other method names are we "squatting" (for lack of a better term)? Are there likely to be other methods that could have similar conflicts? |
What if we hung module SomeHelperMethods
def some_helper_method
if RSpec.example.metadata[:blah]
do_something
end
end
end
RSpec.configure do |c|
c.include SomeHelperMethods
end That makes it available for the edge case. Another option would be to offer a config option: RSpec.configure do |c|
c.expose_current_running_example_as :rspec_example
end or some such. The only other instance methods on |
Doing this w/ |
What if we don't deprecate these methods for rspec-2.x, but "soft deprecate" them (i.e. a deprecation notice tells users how to turn it off - requires some infrastructure). BTW - this is something I've wanted for a long time. I actually did it in response to a reaction I had working on slides for a preso I'm doing next week. This happened a lot w/ The RSpec Book - I'm writing about something and think "wow, that's lame," and fix it :) Perhaps it was subconsciously on my mind due to #633 as well, but that's not what I was thinking of. In regard to #633, however, part of this commit points at the solution if we don't expose the block arg or deprecate |
I'm OK with that idea, although I think it should be I also realized there's a fairly trivial way for end-users to add an module ExampleHelper
extend RSpec::Core::SharedContext
attr_reader :example
before { |ex| @example = ex }
end
RSpec.configure do |c|
c.include ExampleHelper
end Given the simplicity of that, maybe we should just direct users who need this towards doing that? It feels like overkill to add a bunch of infrastructure for a fairly simple deprecation like this. Anyhow, one other thing I thought of...I think this is a potentially breaking change for anyone who uses lambdas for hooks or examples, e.g.: def before_hook_for_foo(some_arg)
lambda do
# do something
end
end
before &before_hook_for_foo(:bar) Lambda semantics dictate that it raises an error if the number of args don't match (in contrast, proc semantics -- which are used for blocks -- do not raise an error if the number of args don't match). With the new example arg passed to the lambda, it'll blow up, I think.
I think that's a good idea, regardless. |
I do use |
I personally like the block syntax & explicitly passing the example to the helper. Perhaps it's verbose because all helper methods will need it, but I like that the example is an explicit argument. It means the helper has a bit less knowledge of RSpec's internals. Granted you know it's in a module that's mixed into RSpec so the whole point is to extend it...but I figure anything we can do to have an explicit API is good. |
What @totallymike said... /cc @myronmarston |
I need to think about it some more, but I'd say the earliest we would make this change is 3.0. |
This has sat for a while but I still like it and would like to get it in RSpec 3. FWIW :). |
It needs to be rebased. Working on that now. |
I rebased this off master, force pushed, and added another commit. I'm pretty happy with it as/is but welcome feedback /cc @myronmarston @alindeman @JonRowe @soulcutter @samphippen |
# end | ||
# | ||
# example "does something" do |ex| | ||
# # ex is a wrapper for the current running example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought ex
was the current example object? In what sense is it a wrapper of the current example rather than than the current example itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're correct. I think at one point I had a wrapper in mind (a la example and group proxies for rspec-1 formatters), but ended up just with the example.
Looking good. There are probably some cukes that we should edit so as to use this new style as well. |
I'm more than prepared to go and lend a hand to things like capybara to help them gain RSpec 3.x support, I think in most cases the changes won't be that extreme, there are probably going to be more gems out there version locked to 2.x with a 2.99 should print deprecation warnings for this, and we are planning to have that around for a significant time to help people get ready for the change, so I don't feel it's necessary to leave things like this around deprecated... we can help people upgrade for the change, we can document things they can do and suggested solutions, I hardly think this will be cutting people off at the knees. I do however apologise for the language in my comment, it was more humour than perhaps it was taken. |
That's great.
I think it's the combination of 2.99 and 3.0.0.beta/rc that needs to be around for a while before 3.0.0 final goes out so lib maintainers and end-users alike can see the deprecation warnings and validate that their resulting changes work with the new version. We've talked about this before but haven't really defined what "a significant time" means. I think we need some means of validating that enough people (definition TBD) are successfully using 3.0 pre-releases with a sufficiently wide variety of 3rd party gems (definition TBD) in play. Surveys? A user-sourced compatibility chart? An opt-in stats report that rspec-3.0.0 pre-releases can send to a server so we can collect data like gem versions, which we can use to publish a compatibility chart? Other ideas? |
What if we did expose current_example = RSpec.respond_to?(:current_example) ? RSpec.current_example : example (the check could also be written in such a way that it'd only be performed once for performance reasons) ... and maintain compatibility? Or is there a compelling reason to not expose it like that? |
Thoughts? |
FWIW, I think the best way to encourage adoption of 3.x is to make the upgrade as simple and painless as possible, both for users and library authors, so there's no reason not to upgrade. That's why we're putting significant effort into 2.99, so that users have a very clear upgrade path, with explicit instructions about what's changing and how it affects them, rather than just a changelog they have to read to figure out how it applies to them.
I'm 👎 on this idea, but certainly could be convinced otherwise once we get more community feedback. One of the main wins of this PR was reducing the amount of namespace squatting we're doing, and if we leave it in place deprecated, we lose that benefit until RSpec 4...which is a long time to wait. I'd first like to see if we can't ease the transition in other ways.
👍 I like this. |
That's backwards to me. If a lib author is going to make a change, we want him/her to follow the path forward and use the yielded example object, not propagate the dependency on |
Thought, could we deprecate the direct calls to |
Except that's not what I intended :) I was saying that |
I'm a tad confused, sorry. Why would end users want I'm nervous right now because rspec-rails' test suite on ... and this makes me suspect there are many other libraries that are now broken against RSpec master and will need to release a new major version if we don't provide some easier way to support both RSpec 2 and 3. I agree that sometimes we need to break compatibility in a major version release, but I feel like we should be conservative about it and only do it when there's a really compelling reason and no great way to support a simple unifying API. My thought was that In my opinion, even if you think this change is positive, it's simultaneously small yet far-reaching: I think we should add, document, and maybe help (via pull requests) gems that integrate with RSpec to support both 2.x and 3.x. Thoughts? |
They wouldn't except to protect against lib authors who are slow to upgrade. Today there is some set of end users (possibly a set of 0, but I doubt it) who use Similarly there is some set of lib authors who use The problem case is the end user who uses lib xyz, and lib xyz does not get updated, even though we've submitted pull requests and bought the author a bottle of Octomore (which is not particularly inexpensive, but oh, so delicious!). That end user can not upgrade to RSpec 3 without: a) bagging lib xyz. Boo! Make sense? That solves the Capybara issue, btw, without imposing anything on Capybara in the short run. It just makes the end user do a little extra work until the Capybara issue is properly solved within Capybara. |
This sounds good in theory, but the part that confuses me (and may be confuses Andy) is this:
I don't see how an end user using |
Aha! And now I see the disconnect. Buried deep within this thread I proposed something like this: RSpec.configure do |c|
c.expose_current_running_example_as :example
end And I mistook
|
👍
I think |
I'd rather
than
(just my 2¢) |
They have completely different purposes. It's not an either/or.
|
I'm still really confused. This is not about Capybara using RSpec for its own test suite; instead, the problem is that Capybara integrates with RSpec ... adding methods and hooks to example groups for users to drive web browsers. When you bring in Capybara to your application or library with The issue is how we make those hooks compatible with both RSpec <= 2.14 and 3, without creating a rift in Capybara itself (where Capybara has to release a version that's only compatible with RSpec >= 2.14, 3). If I were a maintainer of Capybara, I'd be pretty annoyed if RSpec made me do this, since my integration with RSpec is somewhat incidental to my gem's purpose. I think |
@alindeman I don't think that the addition of if RSpec.respond_to?(:current_example)
# use RSpec.current_example
else
# use the local example method
end Right? |
Yep, right. But at least there's an option, even if it's a conditional. If we keep it as it is right now, there's nothing that doesn't feel very fragile and ugly (as far as I can tell anyway). I don't like this because there are a lot of gems that integrate optionally with RSpec (so you don't get rubygems backing up the version constraint) and because many gems integrate with RSpec as a convenience for users, even when that's not a core feature. Making a breaking change like this and giving no good option to support both versions feels like we're not being a very good citizen. |
I agree we don't have a better alternative at the moment. I read your concern about Capybara to mean that you thought there was a way that Capy wouldn't need any changes at all to properly support rspec-3.
Agree with all of that ^^ as well, so I think we're on the same page at this point re: |
Yes, these two things sound good to me :) I'm sorry for all the misunderstandings throughout this thread. I'll make a PR for |
As of RSpec 3, we can't call A0DE example in test. see discussion: rspec/rspec-core#666
As of RSpec 3, we can't call example in test. see discussion: rspec/rspec-core#666
This commit was imported from rspec/rspec-core@917b3a9.
Let's yield current running example to it/example and before/after hooks instead of exposing it via the implicit
example
getter.@myronmarston, @alindeman comments, please