isuPatches
isuPatches

Reputation: 7524

Undefined local variable or method `last_request' on Devise controllers with Cucumber

I have a basic user update test/endpoint:

 def update
    current_user.update_attributes!(user_params)
    respond_with current_user
  end

I'm using Cucumber. Here are some of my versions for reference:

 cucumber (2.4.0)
      builder (>= 2.1.2)
      cucumber-core (~> 1.5.0)
      cucumber-wire (~> 0.0.1)
      diff-lcs (>= 1.1.3)
      gherkin (~> 4.0)
      multi_json (>= 1.7.5, < 2.0)
      multi_test (>= 0.1.2)
    cucumber-core (1.5.0)
      gherkin (~> 4.0)
    cucumber-rails (1.4.5)
      capybara (>= 1.1.2, < 3)
      cucumber (>= 1.3.8, < 4)
      mime-types (>= 1.16, < 4)
      nokogiri (~> 1.5)
      railties (>= 3, < 5.1)
    cucumber-wire (0.0.1)

 rspec (3.5.0)
      rspec-core (~> 3.5.0)
      rspec-expectations (~> 3.5.0)
      rspec-mocks (~> 3.5.0)
    rspec-core (3.5.4)
      rspec-support (~> 3.5.0)
    rspec-expectations (3.5.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.5.0)
    rspec-mocks (3.5.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.5.0)
    rspec-rails (3.5.2)
      actionpack (>= 3.0)
      activesupport (>= 3.0)
      railties (>= 3.0)
      rspec-core (~> 3.5.0)
      rspec-expectations (~> 3.5.0)
      rspec-mocks (~> 3.5.0)
      rspec-support (~> 3.5.0)
    rspec-sidekiq (3.0.1)
      rspec-core (~> 3.0, >= 3.0.0)
      sidekiq (>= 2.4.0)
    rspec-support (3.5.0)

Here's what the test looks like:

  Scenario: A user edits just their profile data
    Given user with e-mail: "[email protected]"
    And I am logged in as: "[email protected]"
    When I update my first name to be: "TEST"
    And the response status should be: 204
    And my "first_name" is updated to be: "TEST"

Under the hood I have these methods for the update and status part:

 When /^I update my first name to be: "(.*?)"$/ do |name|
  put '/v1/users', v1_user: { first_name: name }
end

Then /^the response status should be: (\d+)$/ do |code|
  expect(status).to eq(code.to_i)
end

This helper is meant to help tests:

module ResponseHelper
  def json
    JSON.parse(last_response.body)
  end

  def status
    response.status
  end

  def successful
    response.success?
  end

  def failure
    !successful
  end

  def request
    last_request
  end

  def response
    last_response
  end
end

And it's included in the env.rb file:

World(Rack::Test::Methods)
World(ResponseHelper)

I'm not sure why, but as far as I can tell, something is weird can calling .last_request on any controller that inherits from a Devise controller. The only tests that are failing are devise controller ones (not request specs, but simple controller/crud actions). Here's the stacktrace:

Started POST "/v1/users" for 127.0.0.1 at 2017-05-03 05:29:15 -0500

NameError - undefined local variable or method `last_request' for #<V1::RegistrationsController:0x007fb4094861f0>
Did you mean?  stub_request:
  features/support/response_helper.rb:19:in `request'
  devise (4.2.1) app/controllers/devise_controller.rb:26:in `_prefixes'
  actionview (5.0.2) lib/action_view/view_paths.rb:42:in `lookup_context'
  actionview (5.0.2) lib/action_view/rendering.rb:29:in `process'
  actionpack (5.0.2) lib/action_controller/metal.rb:190:in `dispatch'
  actionpack (5.0.2) lib/action_controller/metal.rb:262:in `dispatch'
  actionpack (5.0.2) lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
  actionpack (5.0.2) lib/action_dispatch/routing/route_set.rb:32:in `serve'
  actionpack (5.0.2) lib/action_dispatch/routing/mapper.rb:16:in `block in <class:Constraints>'
  actionpack (5.0.2) lib/action_dispatch/routing/mapper.rb:46:in `serve'
  actionpack (5.0.2) lib/action_dispatch/journey/router.rb:39:in `block in serve'
  actionpack (5.0.2) lib/action_dispatch/journey/router.rb:26:in `serve'
  actionpack (5.0.2) lib/action_dispatch/routing/route_set.rb:725:in `call'
  rack-pjax (1.0.0) lib/rack/pjax.rb:12:in `call'
  omniauth (1.6.1) lib/omniauth/strategy.rb:189:in `call!'
  omniauth (1.6.1) lib/omniauth/strategy.rb:167:in `call'
  bullet (5.5.1) lib/bullet/rack.rb:12:in `call'
  remotipart (1.3.1) lib/remotipart/middleware.rb:32:in `call'
  aws-healthcheck (1.0.1) lib/healthcheck/middleware.rb:10:in `call'
  warden (1.2.7) lib/warden/manager.rb:36:in `block in call'
  warden (1.2.7) lib/warden/manager.rb:35:in `call'
  rack (2.0.1) lib/rack/etag.rb:25:in `call'
  rack (2.0.1) lib/rack/conditional_get.rb:38:in `call'
  rack (2.0.1) lib/rack/head.rb:12:in `call'
  rack (2.0.1) lib/rack/session/abstract/id.rb:222:in `context'
  rack (2.0.1) lib/rack/session/abstract/id.rb:216:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/cookies.rb:613:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/callbacks.rb:38:in `block in call'
  activesupport (5.0.2) lib/active_support/callbacks.rb:97:in `__run_callbacks__'
  activesupport (5.0.2) lib/active_support/callbacks.rb:750:in `_run_call_callbacks'
  activesupport (5.0.2) lib/active_support/callbacks.rb:90:in `run_callbacks'
  actionpack (5.0.2) lib/action_dispatch/middleware/callbacks.rb:36:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/debug_exceptions.rb:49:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
  cucumber-rails (1.4.5) lib/cucumber/rails/action_controller.rb:10:in `call'
  railties (5.0.2) lib/rails/rack/logger.rb:36:in `call_app'
  railties (5.0.2) lib/rails/rack/logger.rb:24:in `block in call'
  activesupport (5.0.2) lib/active_support/tagged_logging.rb:69:in `block in tagged'
  activesupport (5.0.2) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (5.0.2) lib/active_support/tagged_logging.rb:69:in `tagged'
  railties (5.0.2) lib/rails/rack/logger.rb:24:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/request_id.rb:24:in `call'
  rack (2.0.1) lib/rack/method_override.rb:22:in `call'
  rack (2.0.1) lib/rack/runtime.rb:22:in `call'
  activesupport (5.0.2) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/executor.rb:12:in `call'
  actionpack (5.0.2) lib/action_dispatch/middleware/static.rb:136:in `call'
  rack (2.0.1) lib/rack/sendfile.rb:111:in `call'
  railties (5.0.2) lib/rails/engine.rb:522:in `call'
  rack-test (0.6.3) lib/rack/mock_session.rb:30:in `request'
  rack-test (0.6.3) lib/rack/test.rb:244:in `process_request'
  rack-test (0.6.3) lib/rack/test.rb:67:in `post'
  /Users/Patches/.rbenv/versions/2.3.4/lib/ruby/2.3.0/forwardable.rb:204:in `post'
  features/step_definitions/user_steps.rb:121:in `block in <top (required)>'
  cucumber (2.4.0) lib/cucumber/core_ext/instance_exec.rb:25:in `block in cucumber_instance_exec'
  cucumber (2.4.0) lib/cucumber/core_ext/instance_exec.rb:42:in `cucumber_run_with_backtrace_filtering'
  cucumber (2.4.0) lib/cucumber/core_ext/instance_exec.rb:13:in `cucumber_instance_exec'
  cucumber (2.4.0) lib/cucumber/rb_support/rb_step_definition.rb:102:in `invoke'
  cucumber (2.4.0) lib/cucumber/step_match.rb:27:in `invoke'
  cucumber (2.4.0) lib/cucumber/step_match.rb:20:in `block in activate'
  cucumber-core (1.5.0) lib/cucumber/core/test/action.rb:23:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/step.rb:31:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:104:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:51:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:26:in `test_step'
  cucumber-core (1.5.0) lib/cucumber/core/test/step.rb:16:in `describe_to'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:26:in `block (3 levels) in describe_to'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:25:in `block (2 levels) in describe_to'
  cucumber (2.4.0) lib/cucumber/filters/prepare_world.rb:22:in `block in test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/around_hook.rb:16:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:104:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:51:in `execute'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:33:in `around_hook'
  cucumber-core (1.5.0) lib/cucumber/core/test/around_hook.rb:11:in `describe_to'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:106:in `block (2 levels) in compose_around_hooks'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:107:in `compose_around_hooks'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:24:in `block in describe_to'
  cucumber-core (1.5.0) lib/cucumber/core/test/runner.rb:18:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/prepare_world.rb:11:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/apply_around_hooks.rb:8:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/apply_after_hooks.rb:5:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/apply_before_hooks.rb:5:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/apply_after_step_hooks.rb:8:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/activate_steps.rb:11:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber (2.4.0) lib/cucumber/filters/quit.rb:11:in `test_case'
  cucumber-core (1.5.0) lib/cucumber/core/test/case.rb:23:in `describe_to'
  cucumber-core (1.5.0) lib/cucumber/core/test/filters/locations_filter.rb:17:in `block in done'
  cucumber-core (1.5.0) lib/cucumber/core/test/filters/locations_filter.rb:16:in `done'
  cucumber-core (1.5.0) lib/cucumber/core/filter.rb:61:in `done'
  cucumber-core (1.5.0) lib/cucumber/core/test/filters/tag_filter.rb:18:in `done'
  cucumber-core (1.5.0) lib/cucumber/core/compiler.rb:23:in `done'
  cucumber-core (1.5.0) lib/cucumber/core/gherkin/parser.rb:35:in `done'
  cucumber-core (1.5.0) lib/cucumber/core.rb:29:in `parse'
  cucumber-core (1.5.0) lib/cucumber/core.rb:18:in `compile'
  cucumber (2.4.0) lib/cucumber/runtime.rb:67:in `run!'
  cucumber (2.4.0) lib/cucumber/cli/main.rb:32:in `execute!'
  cucumber (2.4.0) bin/cucumber:8:in `<top (required)>'
  /Users/Patches/.rbenv/versions/2.3.4/bin/cucumber:22:in `<top (required)>'
  bundler (1.14.6) lib/bundler/cli/exec.rb:74:in `kernel_load'
  bundler (1.14.6) lib/bundler/cli/exec.rb:27:in `run'
  bundler (1.14.6) lib/bundler/cli.rb:335:in `exec'
  bundler (1.14.6) lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
  bundler (1.14.6) lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
  bundler (1.14.6) lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
  bundler (1.14.6) lib/bundler/cli.rb:20:in `dispatch'
  bundler (1.14.6) lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
  bundler (1.14.6) lib/bundler/cli.rb:11:in `start'
  bundler (1.14.6) exe/bundle:32:in `block in <top (required)>'
  bundler (1.14.6) lib/bundler/friendly_errors.rb:121:in `with_friendly_errors'
  bundler (1.14.6) exe/bundle:24:in `<top (required)>'
  /Users/Patches/.rbenv/versions/2.3.4/bin/bundle:22:in `<main>'

Upvotes: 0

Views: 286

Answers (2)

isuPatches
isuPatches

Reputation: 7524

So this actually turned out to be a bad stacktrace...the real issue was I was missing a require statement before World(ResponseHelper) and it also seems there was a conflicting file in the non-test portion of the app. Changing the class / file name and adding a require line fixed my last_response issue with Rack::Test::Helpers.

Still no idea why it broke the way it did though, it's very interesting that only Devise controllers seemed to be affected and this was functional elsewhere.

Upvotes: 1

diabolist
diabolist

Reputation: 4099

Capybara doesn't (as far as I know) support getting request and response codes. Its designed to work at a higher level of abstraction. So for this sort of test you should not be testing the response code but instead examining the content of the response.

If you want to test response codes you should write a unit test. If you rewrite the test using rspec or mini test you will get access to the methods you want.

Upvotes: 0

Related Questions