Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

undefined method `original_path_set' for nil:NilClass #860

Closed
chancancode opened this Issue · 33 comments
@chancancode

Hi there! We are testing our apps against Rails master in anticipation of the soon-to-be-released Rails 4.1 to find problems early, and fix them before other people run into these issues.

When I'm running my tests, I see this warning:

An error occurred in an after hook
  NoMethodError: undefined method `original_path_set' for nil:NilClass
  occurred at /Users/godfrey/.rvm/gems/ruby-2.0.0-p353/bundler/gems/rspec-rails-c566453e7f83/lib/rspec/rails/view_rendering.rb:121:in `block (2 levels) in <module:ViewRendering>'

Which is coming from here:

      included do
        before do
          unless render_views?
            @_empty_view_path_set_delegator = EmptyTemplatePathSetDecorator.new(controller.class.view_paths)
            controller.class.view_paths = ::ActionView::PathSet.new.push(@_empty_view_path_set_delegator)
            controller.extend(EmptyTemplates)
          end
        end

        after do
          unless render_views?
            controller.class.view_paths = @_empty_view_path_set_delegator.original_path_set
          end
        end
      end      

I tried setting a breakpoint in the before and after hook here, and for some reason, the before hook here is not being run, so when the after hook is ran, the instance variable is nil.

Here are the gem versions I'm using:

% bundle list | grep rspec
  * rspec-collection_matchers (0.0.2)
  * rspec-core (3.0.0.beta1)
  * rspec-expectations (3.0.0.beta1)
  * rspec-mocks (3.0.0.beta1)
  * rspec-rails (3.0.0.beta1 c566453)
  * rspec-support (3.0.0.beta1)

Happy to provide more info to help hunt down the root cause!

@JonRowe
Owner

Is the before hook not running or render_views? just changing values between the before and after ?

@chancancode

@JonRowe it seems like it's not being ran at all =/ very strange I know, I'm pretty sure I added the breakpoint before the unless block and it wasn't hit at all

@JonRowe
Owner

Can you check again, there's very little chance the before hook would be skipped but not the after hook. Could you also try specifying the type of the spec manually e.g. describe 'MyCoolController', type: :controller

@juno

Same here.
I found out this behavior occured rspec-rails-3.0.0.beta1 with capybara-2.1.0.
I updated capybara to 2.2.0, problem solved.

@JonRowe
Owner

o_O

@alindeman
Collaborator

I'm unable to reproduce this in a pristine Rails edge (4.1.0.beta) app, but it's very concerning to me that two folks are seeing it.

Is anyone able to get a Rails app up and running that is publicly viewable that demonstrates the issue? I'd seriously :heart: it if so, as I've not been able to.

@chancancode

Sorry for the hold up, just confirmed – yes, 1) before hook was skipped :boom: 2) upgrading capybara from 2.1.0 to 2.2.0 solved the issue.

But given the nature if the issue it might be worth investigating still. But I have got a few things on my plate atm, so I probably won't be able to create a dummy app anytime soon. =/

However, upgrading capybara also fixes another error ("undefined method example" or something like that), so it might be related to this / jnicklas/capybara#1125. Perhaps an error in the block you passed to config.before would halt the other before blocks?

@alindeman
Collaborator

upgrading capybara from 2.1.0 to 2.2.0 solved the issue.

Oh, that's a good clue. You'll need capybara 2.2.0 to use rspec-rails 3.0.0, right. I'm still trying to figure out the best way to make that obvious.

I can add some code to rspec-rails that'll make the error more clear.

@JonRowe
Owner

Don't we require Capybara?

@alindeman
Collaborator

Don't we require Capybara?

No, it's optional :/ One option is to require it, though, but it's not without significant downsides in terms of coupling. That said, we already are coupled to a degree. The history of rspec-rails and capybara is complex, and while we tried to do what seemed best and most convenient at the time, it can lead to situations like this.

@myronmarston
Owner

You'll need capybara 2.2.0 to use rspec-rails 3.0.0, right. I'm still trying to figure out the best way to make that obvious.

I would recommend doing something like I do in VCR:

https://github.com/vcr/vcr/blob/e1e8231cef87682ccc39d6893eff071bae2419e7/lib/vcr/library_hooks/webmock.rb#L5
https://github.com/vcr/vcr/blob/e1e8231cef87682ccc39d6893eff071bae2419e7/lib/vcr/util/version_checker.rb

Basically, after requiring a library VCR integrates with, VCR checks the version, and issues an error if it's lower than what VCR requires (since it definitely won't work) or issues a warning if it's higher than the latest minor version VCR has been tested against (as it might or might not work) or does nothing if the version is in the expected range.

This would give a clear error or warning if the version of capybara is outside the expected range, without making it an explicitly declared dependency that bundler resolves and installs.

Alternately, we could spin off a new gem (e.g. rspec-rails-capybara) that depends on rspec-rails and capybara and contains the capybara bits of rspec-rails, and that could have the explicit dependency declaration.

@alindeman
Collaborator

Basically, after requiring a library VCR integrates with, VCR checks the version, and issues an error if it's lower than what VCR requires (since it definitely won't work) or issues a warning if it's higher than the latest minor version VCR has been tested against (as it might or might not work) or does nothing if the version is in the expected range.

This would give a clear error or warning if the version of capybara is outside the expected range, without making it an explicitly declared dependency that bundler resolves and installs.

:+1: I like this approach. I might steal VersionChecker :)

@myronmarston
Owner

I might steal VersionChecker :)

Plunder away :).

@alindeman alindeman referenced this issue in rspec/rspec-support
Merged

Adds VersionChecker #25

@petervandenabeele

Seeing the same (before hook skipped, after hook called and failing because @_empty_view_path_set_delegator not set), in combination with a (very) old capybara version and when setting the @controller manually.

A naive workaround is to say render_views in the describe block.

The problem occurs with this code:

  describe 'NewFooController', type: :controller, environment: true do

    let(:described_class)  { NewFooController }

    describe 'GET index' do

      # render_views  THIS IS THE WORKAROUND

      before(:each) do
        @controller = described_class.new
      end

      it 'returns success code' do
        get('index')
        expect( response.status ).to eq 200
      end

The problem does NOT happen with this version
(for this version the before and after hook (unless render_views?) are both called):

  describe NewFooController, type: :controller, environment: true do

    #let(:described_class)  { NewFooController }

    describe 'GET index' do
      #render_views
      #
      #before(:each) do
      #  @controller = described_class.new
      #end

      it 'returns success code' do
        get('index')
        expect( response.status ).to eq 200
      end

Versions are latest master of today:

GIT
  remote: git://github.com/rspec/rspec-core.git
  revision: 6ac37cc966593885ce58afe04abb1e0e31447c11
  branch: master
  specs:
    rspec-core (3.0.0.beta1)
      rspec-support (= 3.0.0.beta1)

GIT
  remote: git://github.com/rspec/rspec-expectations.git
  revision: 9cf314ed907a149ab38d4c82af2b1273cb4fb486
  branch: master
  specs:
    rspec-expectations (3.0.0.beta1)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (= 3.0.0.beta1)

GIT
  remote: git://github.com/rspec/rspec-mocks.git
  revision: 7aaa623c5412e78448fe90b026c46fa0b47568e7
  branch: master
  specs:
    rspec-mocks (3.0.0.beta1)
      rspec-support (= 3.0.0.beta1)

GIT
  remote: git://github.com/rspec/rspec-rails.git
  revision: c0b2d5380979d77194a742f0c82389e9572929bc
  branch: master
  specs:
    rspec-rails (3.0.0.beta1)
      actionpack (>= 3.0)
      activemodel (>= 3.0)
      activesupport (>= 3.0)
      railties (>= 3.0)
      rspec-collection_matchers
      rspec-core (= 3.0.0.beta1)
      rspec-expectations (= 3.0.0.beta1)
      rspec-mocks (= 3.0.0.beta1)

GIT
  remote: git://github.com/rspec/rspec-support.git
  revision: c76d20840ca78ecd64db92b4aebd99bfd6433240
  branch: master
  specs:
    rspec-support (3.0.0.beta1)
@petervandenabeele

I now upgraded to

capybara (2.2.1)

and I still see the issue. The (ugly) work-around that I implemented eventually is
forcing render_views? to true in an after block (because the tests without
the environment tag needed to run without dependency on rspec-rails).

module Api
  describe 'NewFooController', environment: true do

    let(:described_class) { NewFooController }

    describe 'GET index' do

      before(:each) do
        @controller = described_class.new
      end

      after(:each) do
        # see https://github.com/rspec/rspec-rails/issues/860
        def render_views?
          true
        end
      end

      it 'returns success code' do
        get('index')
        expect( response.status ).to eq 200
      end
    end
  end
end
@alindeman alindeman referenced this issue from a commit
@alindeman alindeman Capybara 2.2.0 is required
Resolves #860
81d7ed1
@alindeman alindeman referenced this issue from a commit
@alindeman alindeman Capybara 2.2.0 is required
Resolves #860
97a850e
@alindeman alindeman closed this in 8254ddc
@ncri

I still have the same issue with rspec-rails 3.0.0.beta2 with capybara 2.2.0

@JonRowe
Owner

Can you elaborate? Produce a reproducable example? It would help us identify this issue :)

@ncri

Well, the issue only appears on the codeship continuous deployment service. I haven't even been able to reproduce it locally...

@ncri

I contacted them. And here is a screenshot of the error message, which appears for all our tests. It's the same th op had:

bildschirmfoto 2014-03-10 um 10 45 19

@JonRowe
Owner

Ping @alindeman

@ncri

I suspect the error is related to another issue in a global config.before callback we have in our test suit. After the update from rails 4 to rails 4.1 a database table we try to access is not existing in that before callback for some reason.

So this has nothing to do with rspec, it seems. It looks like a load order issue. I'm looking into it now.

@ncri

Okay, we identified the issue, its unrelated to rspec.

@myabc myabc referenced this issue from a commit in opf/openproject
@myabc myabc Attempt to work-around an AccountController CI failure
     NoMethodError:
       undefined method `original_path_set' for nil:NilClass

Failure only occurs with a full plugin configuration.

See rspec/rspec-rails#860
c66b959
@plribeiro3000

I still have this issue. It happens with rails 4 only, and im not using capybara at all.

Travis build : https://travis-ci.org/zertico/zertico/builds/27157378

Hope this helps to identify the issue.

@JonRowe
Owner

Sorry, we don't have the time to debug your builds, every instance of this issue so far has been solved by upgrading Capybara, enabling render_views if you have a plugin dependant on it, or another 3rd party source. Hope that helps.

@cupakromer
Collaborator

@plribeiro3000 just a quick look shows two problems:

  1. You need to config your rails app: You must set config.secret_key_base in your app's config. is the final error message
  2. I suggest not defining a let(:controller), as that will interfere with the controller helper that rspec rails setups up for you. Use instead something more descriptive as you did for the users_controller (which is actually what controller would give you normally).
@plribeiro3000

@JonRowe My projects doesn't depend on capybara at all, render_views didnt help either.

@cupakromer

  • Is a rails configuration file and shouldn't be added to control version. I have a minimal rails version just to test the classes i have defined on top of it. So, i think i can ignore this error.
  • I didnt know about the controller helper. Tnx for the info!

Its interesting how the specs have broken only on rails 4.0. Can you guys at least give a look and point me out where should i look to find the bug in rspec-rails ?

@JonRowe
Owner

Its interesting how the specs have broken only on rails 4.0.

Most of rspec-rails is a thin wrapper on top of the Rails test helpers, it's not at all surprising.

I didnt know about the controller helper. Tnx for the info!

Overriding the controller helper will cause issues most of the time, try not to do it.

@cupakromer
Collaborator

@plribeiro3000 this is an issue with the changes in Rail 4 and how it is trying to load the environment. This isn't an RSpec issue. You'll need to look into the Rails code. I suggest starting by looking at a default Rails 4 app and see how the setup differs from the files you have.

@plribeiro3000

@cupakromer Thank you. I didnt know it it was an issue or not. I saw people mentioning in this issue that it was a bug, but didnt know where. I will look further at my app now that i know it inst a bug on rspec but the rails 4 loading. =)

@plribeiro3000

At the end it was exactly the warning. Rails 4.0 doesn't load the secrets.yml file automatically.
Problem solved. =)

@wtfiwtz

For me, this was caused today by not being able to delete foreign key constraints on a PostgreSQL database. It seems that even as the owner of the PG table, this is not always an available privilege. One workaround is to force the test database user to be a super-user:

http://stackoverflow.com/questions/10757431/postgres-upgrade-a-user-to-be-a-superuser#answer-10757486

Perhaps there is another privilege that is more targeted but this solved the problem at least.

@afinetooth

@wtfiwtz thanks for leaving your comment in this thread. It gave me the tip I needed to solve my own problem.

For anyone else receiving the original exception:

An error occurred in an after hook
    NoMethodError: undefined method `original_path_set' for nil:NilClass
    occurred at [...] in <module:ViewRendering>

What seems to be happening is that the before hook associated with the referred-to after hook in the exception, is failing to set a value for @_empty_view_path_set_delegator, which is the object later receiving original_path_set in the after hook. (See code below.)

The "why" of the issue can probably vary.

@wtfiwtz reports that his PostgreSQL user didn't have permissions to delete cascading associations in his database, probably related to test cleanup by, I'm assuming, database_cleaner.

For me, it was a typo in a line of my database_cleaner config:

config.before(:each) do
    DatabaseCleaner.strategy = :transaction
end

(I was passing in the variable, transaction, instead of the symbol, :transaction.)

The point is that, this instructed DatabaseCleaner to use a strategy it didn't understand, blowing up its before hook, which failed up the chain to the before hook in RSpec's ViewRendering module:

included do
    before do
      unless render_views?
        @_empty_view_path_set_delegator = EmptyTemplatePathSetDecorator.new(controller.class.view_paths)
        controller.class.view_paths = ::ActionView::PathSet.new.push(@_empty_view_path_set_delegator)
        controller.extend(EmptyTemplates)
      end
    end

    after do
      unless render_views?
        controller.class.view_paths = @_empty_view_path_set_delegator.original_path_set
      end
    end
end

Such that, in my case, the before hook above wasn't even running. Thus, it failed to set @_empty_view_path_set_delegator.

So, my advice: generalize the problem to this before hook failing and start looking for good reasons why. Configs in your test setup related to before blocks being excellent places to start!

@JonRowe
Owner

Can you open a separate PR for that issue? our before hook should probably run regardless, or we should cope with the lack of the variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.