rspec/rspec-rails

`assigns` and `assert_template` have been removed and extracted to a gem in Rails 5.

JonRowe opened this issue · 18 comments

Moving discussion from rspec/rspec-core#1993

Are there any plans to continue support for it? Both methods have been extracted into https://github.com/rails/rails-controller-testing.

Personally my vote would be no, @cupakromer ?

I need to think it over a bit. @JonRowe could you expand on your thoughts more? I'd like to understand your reasoning and view on the future of controller tests.

Sure, my reasoning is that rspec-rails is mostly a thin wrapper around rails test helpers and those particular matchers would be difficult to replicate without digging into the controller which I feel would be brittle.

However I'm now realising they've been pulled out to another gem, so for now I'd be ok with just continuing to make the matchers available by using that gem...

I share my issue: rails/rails-controller-testing#5 .
Is this comment correct?:
"So far, RSpec is known to be broken because RSpec implements assign."

So is going to be a problem. Yes, current RSpec does not support Rails 5, but that is changing very soon.

However, with assigns being in an external gem now, we would need to make rspec-rails include it as a dependency. But I don't see how we can do that and still support Rails 3.0 - 4.1 given that external gem locks into Rails >= 4.2.

I share my issue: rails/rails-controller-testing#5 .
Is this comment correct?:
"So far, RSpec is known to be broken because RSpec implements assign."

Nope not true. I just realized rails-controller-testing includes the modules into ActionController::TestProcess but RSpec includes ActionController::TestProcess::Behaviour directly.

So is going to be a problem. Yes, current RSpec does not support Rails 5, but that is changing very soon.

However, with assigns being in an external gem now, we would need to make rspec-rails include it as a dependency. But I don't see how we can do that and still support Rails 3.0 - 4.1 given that external gem locks into Rails >= 4.2.

Actually the dependency is going to be Rails >= 5.0 but since it hasn't been released yet we placed it at Rails >= 4.2. In a way, the gem isn't going to be useful until Rails 5.0 rolls out.

Nope not true. I just realized rails-controller-testing includes the modules into ActionController::TestProcess but RSpec includes ActionController::TestProcess::Behaviour directly.

Thanks 😸 I'll look into this.

Actually the dependency is going to be Rails >= 5.0 but since it hasn't been released yet we placed it at Rails >= 4.2.

This is good to know, though that is still a problem. rspec-rails cannot default to including the gem in the gemspec since it still supports other Rails versions. That leaves us with two main choices: implement those methods ourselves or shim stubs for them defaulting to throwing errors if the rspec-controller-testing gem is not available

Nope not true. I just realized rails-controller-testing includes the modules into ActionController::TestProcess but RSpec includes ActionController::TestProcess::Behaviour directly.
Thanks I'll look into this.

Let me know how I can help since I extracted the two methods into rails-controller-testing. 😄

That leaves us with two main choices: implement those methods ourselves or shim stubs for them defaulting to throwing errors if the rspec-controller-testing gem is not available

There's another possiility: move the rspec-rails stuff that integrates with these features into a separate gem that depends directly on rails-controller-testing.

There's another possiility: move the rspec-rails stuff that integrates with these features into a separate gem that depends directly on rails-controller-testing.

I need to dig more to really understand the full impact. They are most heavily used by controller specs. Those two matchers combined with views not being rendered by default, is really what made controller specs isolated. However, reviewing things, this may have an impact on request specs, which seem to allow use of the template matching and view specs. The view specs allow you to stub out partials, layouts, and other things; as well as the ability to "assign" an ivar for the view to use.

This could be much more invasive than I had originally anticipated.

On a related note for controller specs, I'm a little surprised Rails left the flash hash around as that is largely a view construct as well; albeit a named hash instead of "magical" instance variables which appear.

On a related note for controller specs, I'm a little surprised Rails left the flash hash around as that is largely a view construct as well; albeit a named hash instead of "magical" instance variables which appear.

Usually used in the next requests views but always set by a controller though...

I'd like to see this work as a first class behaviour. I think we should soft depend on rails-controller-testing and provide an integration if it's present. I'm happy to work on this.

I'd be ok with conditionally supporting this, and requiring rails-controller-testing as a soft dependency for Rails 5

I've just fixed this with fc5fe38

Hello,
I am a little bit confused...
As of today, 2019, what is the recommended approach on this?
Should we use the "rails-controller-testing" gem?
Should we use "render_template" and "redirect_to"?
If we do not use the above two then what about request specs? Those two are the fundamedal matchers of request specs....
Thank you very much in advance...

👋

rspec-rails exists to enable the usage of Rails testing patterns with RSpec. Rails recommends that you write system specs for "end to end" testing and request specs when you do not. Controller specs are thus not recommended.

The rails-controller-testing gem is intended as a stop gap for those that still have controller tests / specs and want them to keep working, it is not recommended for new setups but it is your choice of course.

The render_template matcher is not included by default (you'd need the rails-controller-testing gem) but you should be able to assert on the actual response (contents, status codes and wether its a redirect) etc.

Dear @JonRowe,

Thank you very much for your kind time and help :)

I am a little bit confused because in https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec (the official site for rspec) it states:

RSpec provides two matchers that delegate to Rails assertions:

render_template # delegates to assert_template
redirect_to # delegates to assert_redirected_to

This page is about Request spec, so if the two main matchers of request specs are not supposed to be used, why the general direction is to use request specs?

Probably I am missing something here...

PS: Please excuse me if I missing something obvious, I just started to learn TDD and RSpec... :)

the two main matchers of request specs

They are the two matchers mentioned, one still works redirect_to, without the gem, the other requires the gem due to the decisions made by the Rails team. You should not be asserting a template was rendered, you should be asserting on the behaviour and contents of the output.

why the general direction is to use request specs?

The Rails team have driven the decision to push request specs over controller specs. The underlying functionality comes from Rails. The reason is that controller specs were a partial integration of various Rails functionality and didn't behave as production did. Request specs are the total Rails stack going from the top right down to the response being rendered and are thus a more complete integration test.

It's virtually impossible to unit test parts of Rails due to its high level of coupling between its internal components.