fireproofsocks

fireproofsocks

Referencing files from tests -- __DIR__ is evaluated at compile time, so paths can break

This is a problem I’ve come across now and then… in an app, I have a few directories containing .json files (e.g. for example requests or responses). I put these files into directories inside of test/support/ and then in my mix.exs I reference the test/support/ directory as follows:

    def project do
    [
      # ...
      elixirc_paths: elixirc_paths(Mix.env()),
      # ...
    ]
  end

  # Specifies which paths to compile per environment.
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

The problem revolves around the __DIR__ variable because it is resolved at compile time. I can include files in my setup fixtures doing something like this:

 # example setup inside `test/support/conn_case.ex`
  defp append_mutation(%{mutation: mutation} = context) do
    data =
      "#{__DIR__}/mutations/#{mutation}.json"  # <-- resolves to /full/path/to/test/support/mutations/something.json
      |> File.read!()
      |> Jason.decode!()

    %{context | mutation: data}
  end

When I run tests locally, the path gets converted to paths that make sense on my local machine, so tests pass. However, if I then try to run tests in a containerized environment (e.g. via docker-compose), the paths are not the same, so tests fail.

One option is to do mix compile --force before running the tests, but that’s slow – I have to recompile everything every time I switch environments.

I seem to remember something about the https://hexdocs.pm/elixir/Application.html#app_dir/1 working in certain cases here… but I don’t see how it’s working its magic. Even with my mix.exs set to compile my test/support/ folder, none of my supporting .json files end up in the _build/ folder, so I don’t think I can reference them there.

Can someone educate me on a better way to dealing with this?

Thanks!

Marked As Solved

kip

kip

ex_cldr Core Team

I would be very unusually to put test files in priv, yes. For accessing support files in tests I typically just rely on the fact that tests are being run when the working directory is the root of the project. Therefore just "test/support/mutations/#{mutation}.json"

Also Liked

kip

kip

ex_cldr Core Team

Yes, thats my normal strategy. It breaks if you have tests that change working directory - and there are some functions in Mix that do that if you are messing around with dependencies (which is not something I’d recommend and wouldn’t normally be an issue).

joshtaylor

joshtaylor

Can you do:

Path.join([:code.priv_dir(:my_otp_app), "#{mutation}.json"])

?
https://erlang.org/doc/man/code.html#priv_dir-1

kip

kip

ex_cldr Core Team

the .po files are compiled into functions in the module that use Gettext, otp_app: ___ so they don’t need to be in a release.

The behaviour of the priv dir is controlled by the build_embedded: Mix.env() == :prod, line in mix.exs. In development the priv dir is symlinked to the _build directory and in production it is copied. So I would expect your /path/to/my_app/_build/test/lib/my_app/priv/ is a symlink on your dev machine?

For example, for one of my libs:

$ ls -al _build/test/lib/ex_cldr/priv
lrwxr-xr-x  1 kip  staff  16  8 Jan 06:09 _build/test/lib/ex_cldr/priv -> ../../../../priv
NobbZ

NobbZ

So, as they are only relevant to testing, and during testing usually your full sources are available from where you run mix, why not just use relative path from CWD?

Where Next?

Popular in Questions Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Kagamiiiii
Student &amp; New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement