The Crystal Programming Language Forum

Unit-testing HTTP handlers

I’m trying to build a simple JSON service that routes like Roda to HTTP::Handler-like instances:

class App
  include HTTP::Handler
  include Routing

  def call(context)
    route context do |r, response, session|
      r.root { HomePage.new.call context }

      r.on "api" { API.new.call context }

      # other routes...
    end
  end
end

Since it’s just passing off the context, I’m looking for a way to unit-test these individual routes, building up the HTTP::Server::Context myself and stubbing out other services. Unfortunately, when I parse the response in this spec:

describe "GET /people" do
  it "returns a list of people" do
    io = IO::Memory.new
    response = HTTP::Server::Response.new io
    context = HTTP::Server::Context.new(
      request: HTTP::Request.new("GET", "/people"),
      response: response,
    )
    response.flush

    ExampleWebService::App.new.call context

    io.rewind.to_s STDOUT
    response_body = JSON.parse(io.rewind)
    response_body.should eq({
      people: [
        { id: 123, name: "Jamie" },
      ],
    })
  end
end

The response IO is empty, so I get a JSON parsing error in the spec. This is the code:

module ExampleWebService
  class App
    include HTTP::Handler

    def call(context)
      {
        people: [
          Person.new(id: 123, name: "Jamie"),
        ],
      }.to_json context.response
    end
  end

It’s all hardcoded right now while I flesh out the pattern of unit-testing it, so there’s nothing really to go wrong. When I run it through an HTTP::Server, it works just fine, it just seems like the data isn’t making it to the IO instance inside the spec. I’m using response.flush, is there something else I need to be doing there?

I think you want to flush the response after executing the handler. Then you get

HTTP/1.1 200 OK
Transfer-Encoding: chunked

26
{"people":[{"id":123,"name":"Jamie"}]}

which still fails since there is other data.

3 Likes

OMG, you’re right. Man, I was staring at this until I was questioning whether I knew how computers worked. :stuck_out_tongue_closed_eyes:

I can handle it from there, I think. I just didn’t realize I put the flush in the wrong place. Thanks!

3 Likes