1
votes

I'm new to Elixir and Phoenix and I'm trying to create a web service to compliment my web site. To start with, I just want to test my new data structure by importing some data from a json file. I thought I'd do this with a test. I've read through the basic guides (including the testing section), but I haven't been able to find anything on testing an api call.

From the code below, I get the following error when I run mix test:

** (ArgumentError) flash not fetched, call fetch_flash/2

This fails on the line that makes the call and returns the connection. I'm assuming that I'm using the wrong call/missing something? Is there documentation that I've missed, or can somebody point me to a good example?

Here's a snippet from my router.ex:

  scope "/", ContactsApp do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    resources "/contacts", ContactsController
  end

  # Other scopes may use custom stacks.
  scope "/api", ContactsApp do
    pipe_through :api

    get "/import", ContactsController, :import
  end

For the time being, all I've done is copy the ContactsController.Create method and called it ContactsController.Import. I also copied the "creates resource and redirects when data is valid" test and used :import instead of :create

Here's the full stack trace:

** (ArgumentError) flash not fetched, call fetch_flash/2
 stacktrace:
   (phoenix) lib/phoenix/controller.ex:997: Phoenix.Controller.get_flash/1
   (phoenix) lib/phoenix/controller.ex:982: Phoenix.Controller.put_flash/3
   (contacts_app) web/controllers/contacts_controller.ex:74: ContactsApp.LogController.stuff/2
   (contacts_app) web/controllers/contacts_controller.ex:1: ContactsApp.LogController.action/2
   (contacts_app) web/controllers/contacts_controller.ex:1: ContactsApp.LogController.phoenix_controller_pipeline/2
   (contacts_app) lib/phoenix/router.ex:261: ContactsApp.Router.dispatch/2
   (contacts_app) web/router.ex:1: ContactsApp.Router.do_call/2
   (contacts_app) lib/contacts_app/endpoint.ex:1: ContactsApp.Endpoint.phoenix_pipeline/1
   (contacts_app) lib/phoenix/endpoint/render_errors.ex:34: ContactsApp.Endpoint.call/2
   (phoenix) lib/phoenix/test/conn_test.ex:194: Phoenix.ConnTest.dispatch/5
   test/controllers/contacts_controller_test.exs:69
1
Are you calling get_flash somewhere in your code or test?Dogbert
Apparently conn = get conn, contacts_path(conn, :import), log: @valid_attrs doesMitkins
Have you tried the mix phoenix.gen.json command? It will generate tests for you. So you can see how it's done.sobolevn
Cool. That helped a lot. ThanksMitkins

1 Answers

1
votes

Thanks to @Dogbert and @sobolevn I was able to figure out what I did wrong. When code is generated by mix phoenix.gen.html, then the controller may have something like the following:

def create(conn, %{"contact" => contact_params}) do
  changeset = Contact.changeset(%Contact{}, contact_params)

  case Repo.insert(changeset) do
    {:ok, _contact} ->
      conn
      |> put_flash(:info, "Contact created successfully.")
      |> redirect(to: contact_path(conn, :index))
    {:error, changeset} ->
      render(conn, "new.html", changeset: changeset)
  end
end

When code is generated by mix phoenix.gen.json, then the controller contains slightly different code:

def create(conn, %{"fred" => fred_params}) do
  changeset = Fred.changeset(%Fred{}, fred_params)

  case Repo.insert(changeset) do
    {:ok, fred} ->
      conn
      |> put_status(:created)
      |> put_resp_header("location", fred_path(conn, :show, fred))
      |> render("show.json", fred: fred)
    {:error, changeset} ->
      conn
      |> put_status(:unprocessable_entity)
      |> render(ContactsApp.ChangesetView, "error.json", changeset: changeset)
  end
end

In the code I copy and pasted, there is a call to put_flash as @Dogbert suggests (which is meant to work with the :browser pipeline). Using the code generated using mix phoenix.gen.json fixes the problem.