fireproofsocks
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 Application — Elixir v1.20.2 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!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
NobbZ
You should compile the files in the docker, not on your system.
Another approach were to compile the raw JSON I to the module.
fireproofsocks
How? I thought I was doing that by specifying the
test/support/directory in myelixirc_paths.NobbZ
That just specifies that
*.exfiles intest/supportshould be compiled into*.beamfiles on disk.This does not cause any JSON to be compiled into the modules. They JSON is still loaded during runtime.
The approach I am proposing does the following:
This will only work though if the JSON file is not written to after compilation and if the names are knwon statically. On the other hand side, touching any of the files will cause the module in question to recompile as necessary.
If though the files are subject to change during the test as part of the testrun, you should not store them in the project folder at all, but somewhere in
/tmp, making sure they won’t interfere in subsequent testruns.fireproofsocks
Won’t that have the same problems because
__DIR__will get evaluated at compile time?NobbZ
Yes,
__DIR__will get evaluated at compiletime. But no file access will happen at runtime. The JSON will be parsed at compile time and put as an immediate value into the compiled module.So instead of having some path in your sources pointing to a JSON file containing
{}on the build but not existing on the run time host, you now have a module that not contains that path at all, but instead a function that returns the immediate value%{}when asked for that mutations name.fireproofsocks
Ah, that’s tricky. Thanks!
joshtaylor
Can you do:
?
fireproofsocks
That looks promising – it resolves to
/path/to/my_app/_build/test/lib/my_app/priv/, which in my case is empty.I see that
gettexthas some extra files that end up in there (its.pofiles)… but I don’t see how to get those included… and I can’t find docs as to how mix is supposed to handle this.From
gettext'smix.exs:kip
the
.pofiles are compiled into functions in the module thatuse Gettext, otp_app: ___so they don’t need to be in a release.The behaviour of the
privdir is controlled by thebuild_embedded: Mix.env() == :prod,line inmix.exs. In development theprivdir issymlinkedto the_builddirectory 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:
fireproofsocks
Interesting. So it looks like it would be possible to put some extra files into the
priv/directory (in my case.jsonfiles), but that feels a bit odd because they are only relevant to testing…