The code you've used is fine, although I would structure it slightly differently as I don't like to use it
blocks the way you normally see them, I think it encourages testing of more than one aspect of a system at a time:
let(:body) { { :key => "abcdef" }.to_json }
before do
post '/channel/create', body, {'CONTENT_TYPE' => 'application/json'}
end
subject { last_response }
it { should be_ok }
I've used let because it's better than an instance variable in a before
block (kudos to you for not doing that). The post
is in a before
block because it's not really part of the spec, but a side effect that occurs prior to what you're speccing. The subject
is the response and that makes the it
a simple call.
Because checking the response is ok is needed so often I put it in a shared example:
shared_examples_for "Any route" do
subject { last_response }
it { should be_ok }
end
and then call it as such:
describe "Creating a new channel" do
let(:body) { { :key => "abcdef" }.to_json }
before do
post '/channel/create', body, {'CONTENT_TYPE' => 'application/json'}
end
it_should_behave_like "Any route"
# now spec some other, more complicated stuff…
subject { JSON.parse(last_response.body) }
it { should == "" }
and because the content type changes so often, I put that in a helper:
module Helpers
def env( *methods )
methods.each_with_object({}) do |meth, obj|
obj.merge! __send__(meth)
end
end
def accepts_html
{"HTTP_ACCEPT" => "text/html" }
end
def accepts_json
{"HTTP_ACCEPT" => "application/json" }
end
def via_xhr
{"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
end
It's easy to add this in where it's needed by including it via the RSpec config:
RSpec.configure do |config|
config.include Helpers, :type => :request
then:
describe "Creating a new channel", :type => :request do
let(:body) { { :key => "abcdef" }.to_json }
before do
post '/channel/create', body, env(:accepts_json)
end
Having said all that, personally, I wouldn't post using JSON. HTTP POST is simple to handle, and every form and javascript library does it easily and well. Respond with JSON by all means, but don't post JSON, HTTP is a lot easier.
Edit: after writing out the Helpers
bit above I realised it would be more helpful as a gem.