How to test file uploads?

I’m using Arc to handle file uploads. It works in browser, but I can’t seem to get the test to pass for a model with an image upload. To test showing the model, I create the model and the image to go with it at the top of the test.

  test "show neta", %{ conn: conn } do
    neta = insert_neta(image_fixture())

    conn = get conn, neta_path(conn, :show, neta)
    assert html_response(conn, 200) =~ ""
  end

Where inserting the neta is:

  def insert_neta(image, attrs \\ %{}) do
    default_attrs = %{
      name: "Jim bob",
      uuid: "b118d22a-9cec-55ed-9e74-db83b49d7c31",
      image: image
    }
    changes = Map.merge(default_attrs, attrs)
    IO.puts inspect(default_attrs)

    %MyApp.Neta{}
    |> MyApp.Neta.changeset(changes)
    |> Repo.insert!()
  end

  def image_fixture() do
    case Ecto.DateTime.load({{2017, 7, 5}, {11, 25, 00}}) do
      { :ok, now } ->
        #%{ file_name: "thumb.jpg", updated_at: now }
        %Plug.Upload{ content_type: "image/jpeg", filename: "thumb.jpg", path: "/Users/myusername/proj/myapp/test/fixtures/thumb.jpg" }
      _ ->
        raise "Date could not be loaded"
    end
  end

The changeset for the model is:

  def changeset(struct, params \\ %{}) do
    struct
    |> record_image_uuid
    |> cast_attachments(params, [:image])
    |> cast(params, [:name, :uuid])
    |> validate_required([:name, :image])
  end

I figured out that I needed to pass in a %Plug.Upload{filename: “thumb.jpg”, path: “/Users/myusername/proj/myapp/test/fixtures/thumb.jpg”} in the parameters, but while in the changeset, it reports that it’s invalid.

This only happens inside of test, and not in browser. I made sure the file exists in the path. I also tapped between each changeset, and it fails right after cast_attachments.

------ recorded_image_uuid
#Ecto.Changeset<action: nil, changes: %{uuid: "e7179bda-621c-11e7-8a0f-c82a144f4d41"}, errors: [], data: #MyApp.Neta<>, valid?: true>
------ casted_attachments to image
seeing errors in changeset....
#Ecto.Changeset<action: nil, changes: %{uuid: "e7179bda-621c-11e7-8a0f-c82a144f4d41"}, errors: [image: {"is invalid", [type: MyApp.ImageUploader.Type, validation: :cast]}], data: #MyApp.Neta<>, valid?: false>

I’m at a completely loss. All I know is the Plug.Upload in the image should be correct, but it’s invalid in tests, but I don’t know why.

Update: The error is:
[image: {"is invalid", [type: MyApp.ImageUploader.Type, validation: :cast]}]

Ruled out:

  • that it can’t connect to S3 when saving file
  • that it can’t find the file to upload on disk for the test
  • that validate_required is causing the problem.

If anyone can help, I’d really appreciate it. Thanks.

4 Likes

try with path: "test/fixtures/thumb.jpg" for starters…

try with path: “test/fixtures/thumb.jpg” for starters…

Nope, that didn’t work. I also tried:

  • ./test/fixtures/thumb.jpg (in case it needed to know it’s the current dir from root)
  • …/test/fixtures/thumb.jpg (in case it was relative to the test file)

Figured it out. Documenting for subsequent readers.

First, I didn’t know the IEx was available to me as a debugger, once I figured that out, that made it a lot easier. To use IEx as a debugger, check out https://stackoverflow.com/questions/28724372/debugging-and-debugging-tools-in-elixir#28725462

Second, the arc library is swallowing errors, so I couldn’t see why something was wrong. In order to inject IEx.pry or IO.puts to print out what’s going on, you can edit the files in deps, and then recompile. To recompile just mix deps.compile, but that’s only in dev/. I don’t know the mix command to recompile test, so I just deleted _build/test and ran the tests again. The key file in this instance is arc_ecto/lib/arc_ecto/type.ex in the cast.

In my particular instance, I set environment variables in .env, and have to run source .env. I just forgot to do it in a new terminal window. Hence, the environmental variables for the AWS secret key was nil, and that’s why arc was marking it an error. In the terminal window where I had the server running, I had already sourced .env, so it wasn’t a problem.

UGH.

9 Likes

Are you making an actual HTTP request to AWS in your tests? That seems a bit error-prone and slow. Or perhaps you were just saying that the arc library requires that you pass in/set a specific env var.

@iamwil - I had the same problem. Thanks for the reminder to source .env

Regarding @axelson’s comment - I totally agree. I started using FakeS3 and it was super easy to get up an running.

2 Likes

I was making an actual HTTP request at first, but have since switched to FakeS3.

The problem was the .env wasn’t run in that term, and hence the proper env variables weren’t set.

1 Like