Standard approach to testing/developing Phoenix libraries?

Hi all!

I’m maintaining a library (package?) that includes mix tasks, and does a fair bit of code injection into your Phoenix project when it’s first set up.

Question:

What is the best way to go about testing a library that relies extensively on Mix tasks to inject code into its Phoenix app?

Is there anyone maintaining libraries that require dummy Phoenix apps, that maybe have figured out an easy way to go about this?

Notes:

  • I’ve tried embedding a dummy Phoenix project in a subdirectory of the library project (i.e. in something like priv/). The problem is that I have to declare my library as a dependency in the dummy Phoenix project to run the mix task, thus creating a circular dependency when running tests from the library project.
  • I’d like to be able to reset the dummy project when testing so I can check the mix task I’m using correctly injects all the relevant code (at the moment I’m cleaning up files using regex + read/write).
  • I need to be able to run the mix task from the library testing suite (I understand I can use Mix.Project.in_project/4 to do this, maybe.).
1 Like

Look at phoenix_live_dashboard code: phoenix_live_dashboard/test_helper.exs at master · phoenixframework/phoenix_live_dashboard · GitHub

It declares a router, endpoint and so on… straight from test_helpers.exs

1 Like

As well as from dev.exs for development: phoenix_live_dashboard/dev.exs at master · phoenixframework/phoenix_live_dashboard · GitHub

1 Like

I see - so they build a minimum-viable implementation of the end framework exclusively for tests, hadn’t considered that approach.

That said, the main pain-point here is that the mix task I’m running is highly dependent on the default file-structure of a phoenix project (to find the files into which to inject the code).

In an ideal world I’d be able to create a new phoenix project for the tests in a subdirectory, include my library as a dependency of this new project, run the mix task as if running it from the test phoenix project, and check that the results of running it were correct. I’m also dependent on the esbuild process for the end result, which complicates things a bit.

I’m thinking it’s probably best to just write a series of helpers that create this separately from the library’s mix project, and then call to it with Mix.Project.in_project/4. Unless of course there’s a way to resolve the circular dependency that happens when the phoenix test app contained in the library references the library itself as a dependency (therefore making modules crash because they’re built multiple times).

1 Like

Mix can do that. Iirc the boundary project uses that to test its compiler tracer integration.

1 Like

I’ve gotten pretty close to where I want to be with it, but I keep running into the fact that when calling into this “sub-project” (I’m using Mix.Project.in_project to call my library’s mix task from inside the sub-project), for some reason the Mix.Project.deps_paths of the sub-project are empty, despite Mix.Project.config returning the correct configuration. The best clue I have is that Mix.Dep.cache comes up empty, but there seems to be no way to actually build the cache, thus no way to rely on Mix.Project.deps_paths both for testing and for production (I need this because I’m copying files from my library into the phoenix project using the mix task). That said, it’s a minor gripe, and I can probably get around it - was just curious as to why the deps are somehow unavailable despite the sub-project being pushed onto the mix project stack.

1 Like