Reputation: 7524
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
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
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