Phx_test - Quickly create and configure Phoenix test apps for library developers

phx_test

Inspired by this topic by @caleb-bb, I’ve been working on a little experiment called phx_test. The question was “how do I write tests for my LiveView development tool, without turning my libary into a Phoenix project?”. I don’t know where this project will go in the future, so I’d love your thoughts and feedback.

Problem

In order to build packages for Phoenix applications, it may be necessary to load a running Phoenix project in development and tests. However, when you ship your library you want to be sure that neither the Phoenix test app nor any of its dependencies are leaked into your distribution.

Solution

It is possible to embed a Phoenix project into a subdirectory of your project as a dev and test dependency, with full access to its modules and dependencies in your tests and dev environment. You can even start the server directly from your root project directory with mix phx.server or iex -S mix phx.server, just as you would in a normal Phoenix project.

The path to making this work is not too complex, but it’s not obviously apparent either. Setting this up can save you from starting a separate Phoenix project and importing your libary just so you can perform tests. Now you can manage both your core project and the Phoenix app you use for testing in one repo.

mix phx_test.new

When you add phx_test as a dev/test dependency to your project, you get the mix phx_test.new task to set this up with one command. When you run this task with no arguments you will get a Phoenix project named phx_test_app installed in the priv/ subdirectory, and some additional code injected into mix.exs, config/config.exs, and test/test_helper.exs to hook everything up. Notably you will have the following dev/test dependencies added to your project’s mix.exs:

{:phx_test_app, path: "./priv/phx_test_app", only: [:test, :dev]},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:floki, ">= 0.30.0", only: :test}

You can customize the test app’s name and location with options: mix phx_test.new bar --sub-directory foo will create a Phoenix app called Bar in the foo/bar directory. The app name and all other options besides --sub-directory are passed directly to mix phx.new, so you can do things like mix phx_test.new bar --no-ecto --no-mailer --no-dashboard --no-gettext --sub-directory foo. The only option that does not work with mix phx_test.new is --umbrella, but I don’t think that’s going to hold anyone back from running some tests :slight_smile:

Feedback!

̶R̶i̶g̶h̶t̶ ̶n̶o̶w̶ ̶t̶h̶i̶s̶ ̶i̶s̶ ̶j̶u̶s̶t̶ ̶a̶v̶a̶i̶l̶a̶b̶l̶e̶ ̶o̶n̶ ̶[̶g̶i̶t̶h̶u̶b̶]̶(̶h̶t̶t̶p̶s̶:̶/̶/̶g̶i̶t̶h̶u̶b̶.̶c̶o̶m̶/̶m̶s̶i̶m̶o̶n̶b̶o̶r̶g̶/̶p̶h̶x̶_̶t̶e̶s̶t̶)̶,̶ ̶a̶n̶d̶ ̶i̶s̶ ̶n̶o̶t̶ ̶p̶u̶b̶l̶i̶s̶h̶e̶d̶ ̶t̶o̶ ̶h̶e̶x̶.̶ ̶Y̶o̶u̶ ̶c̶a̶n̶ ̶a̶d̶d̶ ̶i̶t̶ ̶t̶o̶ ̶y̶o̶u̶r̶ ̶d̶e̶p̶s̶ ̶w̶i̶t̶h̶ ̶̶{̶:̶p̶h̶x̶_̶t̶e̶s̶t̶,̶ ̶g̶i̶t̶:̶ ̶"̶h̶t̶t̶p̶s̶:̶/̶/̶g̶i̶t̶h̶u̶b̶.̶c̶o̶m̶/̶m̶s̶i̶m̶o̶n̶b̶o̶r̶g̶/̶p̶h̶x̶_̶t̶e̶s̶t̶"̶,̶ ̶o̶n̶l̶y̶:̶ ̶[̶:̶d̶e̶v̶,̶ ̶:̶t̶e̶s̶t̶]̶}̶̶.̶ This is available on hex, and you can addit to your project with {:phx_test, "~> 0.1.0", only: [:dev, :test]}. So far this has been sort of an experiment for my own learning and enjoyment, and I may put it down if there’s not much interest from the Elixir community, so I’m curious:

  • Is doing something like this even a good idea?
  • Does it seem useful enough in the real world to keep developing it?
  • Is there anything like this already?
  • Are there any gotchas I’m not aware of?
  • Can you think of anything that would make this better if I continue working on it?

Thanks for reading!

8 Likes

Oops I slipped and hit my head on the keyboard and when I woke up v.0.1.0 had been published to hex.

Hey @msimonborg this is a really interesting project, and was wondering if there’s any way I could maybe contribute to it. I’ve run into this problem again and again, and have yet to find an easy/organic way around having to set up new phoenix instances and inject tests into them in order to make sure my library works (until I came across this).

1 Like

Cool idea! I found myself wanting something like this recently while developing a LV library (not released yet, but hopefully soon).

My solution has been in fact to turn my library repo into a phoenix app and exclude the phoenix app from the hex package and the docs. It should work, but using something like phx_test seems more elegant and less hacky.

Going to try using this to test a new library I’m writing that’s meant to be used in live views. Will report back any issue I run into. This 100% solves a need, and I hope you continue working on it!

Just reporting back. The setup was mostly flawless though I do get warnings during testing of missing modules. Basically, if you’re developing a library then your test phoenix application will have code using your library, but you library’s modules won’t be exist when your test phoenix application is compiled resulting in warnings about missing modules. Of course, at runtime the library modules exists and everything works as expected. So, nothing really bad, just annoying to see compile time warnings I can’t fix. Otherwise, it was a great development experience.

Going to use this for all my phoenix related libraries going forward! Can’t wait to see it expanded with stuff like generating multiple phoenix applications and/or different application scaffolds. E.g. maybe with commanded, or with a few simple live views, controllers, etc. Great work!

Also, I’ve been using this alias to make testing a little less painful:

      test: [
        "cmd command cd my_sub_dir/my_app && mix test --color",
        "test"
      ]

Not only does this ensure my test app’s db is setup, it also runs my test app’s tests which is nice. No use running my tests which depend on my test app, if my test app isn’t functioning properly to begin with.