In Rails, how do you functional test a Javascript

2019-03-09 20:59发布

问题:

If your controller action looks like this:

respond_to do |format|
  format.html { raise 'Unsupported' }
  format.js # index.js.erb
end

and your functional test looks like this:

test "javascript response..." do
  get :index
end

it will execute the HTML branch of the respond_to block.

If you try this:

test "javascript response..." do
  get 'index.js'
end

it executes the view (index.js.erb) withOUT running the controller action!

回答1:

Pass in a :format with your normal params to trigger a response in that format.

get :index, :format => 'js'

No need to mess with your request headers.



回答2:

with rspec:

it "should render js" do
  xhr :get, 'index'
  response.content_type.should == Mime::JS
end

and in your controller action:

respond_to do |format|
  format.js
end


回答3:

Set the accepted content type to the type you want:

@request.accept = "text/javascript"

Combine this with your get :index test and it will make the appropriate call to the controller.



回答4:

Use this before request:

@request.env['HTTP_ACCEPT'] = 'text/javascript'


回答5:

These three seem to be equivalent:

  1. get :index, :format => 'js'
  2. @request.env['HTTP_ACCEPT'] = 'text/javascript'
  3. @request.accept = "text/javascript"

They cause the controller to use a js template (e.g. index.js.erb)

Whereas simulating an XHR request (e.g. to get a HTML snippet) you can use this: @request.env['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest"

This means request.xhr? will return true.

Note that, when simulating XHR, I had to specify the expected format or I got an error:

get :index, format: "html"

Tested on Rails 3.0.3.

I got the latter from the Rails source, here: https://github.com/rails/rails/blob/6c8982fa137421eebdc55560d5ebd52703b65c65/actionpack/lib/action_dispatch/http/request.rb#L160



回答6:

RSpec 3.7 and Rails 5.x solution:

A few of these answers were a little outdated in my case so I decided to provide an answer for those running Rails 5 and RSpec 3.7:

it "should render js" do
  get :index, xhr: true

  expect(response.content_type).to eq('text/javascript')
end

Very similar to Steve's answer with a few adjustments. The first being xhr is passed as a boolean key/pair. Second is I now use expect due to should receiving deprecation warnings if used. Comparing the content_type of the response to be equal to text/javascript worked for me.



回答7:

Use code like this for parameters and user id, etc., notice that format option is in the same hash of other parameters like id and nested_attributes.

put :update, {id: record.id, nested_attributes: {id: 1, name: "John"}, format: :js}, user.id


回答8:

Many of the above answers are outdated.

The correct way to do it in RSpec 3+ is post some_path, xhr: true.

Deprecation warning straight from RSpec itself, when attempting to use xhr :post, "some_path":

DEPRECATION WARNING: `xhr` and `xml_http_request` are deprecated and will be removed in Rails 5.1.
Switch to e.g. `post comments_path, params: { comment: { body: 'Honey bunny' } }, xhr: true`.

Also, xhr :post, "some_path" results in some funky errors that doesn't happen with post some_path, xhr: true.