If you frequently work in umbrella apps in Elixir, you know that there are a couple of small pain points in the testing process related to folder structure and file locations. I have been working in umbrella apps for the past year, and I deal with these regularly. In this article I will explain the changes coming in Elixir 1.9 that will finally relieve those pain points.
Recursive Tasks and Umbrellas
mix test is a recursive task in Elixir. This means that when you run the task in an umbrella app, Elixir iterates through each of the child apps and runs the task on that child app. Recursive tasks are super helpful because your child apps can have different behavior for a given task and the recursion will run each as it was configured. The tasks for each child are run from the base of the child app, not the root of the umbrella app, allowing tasks to behave the same when run recursively from the umbrella level as from the child level.
The issues with testing umbrella apps in Elixir prior to 1.9 arises when you want to pass a file path to
mix test to test only that one file. For example, you would specify
mix test test/foo/my_test.exs to test a file in the
foo child app, even though the file relative to the umbrella app is actually
apps/foo/test/foo/my_test.exs. This disconnect means that you cannot use tab-completion to specify the file you want to test, as
apps/foo/test/foo/my_test.exs doesn’t exist relative to the child app’s base. Furthermore you can’t use features like VSCode tasks to quickly test the current file, as VSCode will include
apps/foo in the path it injects into the task execution.
A second frustration with testing single files on umbrella apps is that the command is run on every child app even though only one app is going to have the specified file in it. This results in
Paths given to "mix test" did not match any directory/file warnings in the console for every child app other than the one the file exists in, pushing the information you want to see up and potentially out of sight in the console.
A third issue with regards to testing paths is that the path in the output of a failed test doesn’t include
apps/foo, so it is not clickable in enhanced consoles that support clicking files, such as the VSCode terminal.
One of the great things about working in Elixir is the fact that if you run into an issue with the language, you can either report it and get it resolved fast, or just dive in and fix it yourself and have it merged in no time. One of the many benefits of working at DockYard is the “DockYard Day.” Monday through Thursday are client days; Friday is a DockYard Day, where we can work on a project of our choosing including contributing to Open Source. After working without tab-completion and clickability for too long, I finally decided on a recent DockYard Day to dive in and see what it would take to resolve these issues.
After some investigation, I took a shot at improving
mix test to recognize paths that include
apps/app_name. José suggested some improvements to the approach, which added the side-effect of skipping the test run altogether for child apps that don’t contain that file, resolving the second issue mentioned above.
In the discussion on the PR, I mentioned that resolving the third issue, including the full relative path in test outputs, was on my to-do list. When I came back the next DockYard Day to implement the fix for this, I found that it had already been implemented by José, which was awesome.
I have been running the master branch of Elixir ever since, and it is refreshing to be able to use tab completion and click file paths in failed tests again for the first time in a year. A week or so after this all wrapped up, the first release candidate for Elixir 1.9 was announced, so it won’t be long before everyone can enjoy these improvements.
DockYard is a digital product agency offering custom software, mobile, and web application development consulting. We provide exceptional professional services in strategy, user experience, design, and full stack engineering using Ember.js and Elixir. With a nationwide staff, we’ve got consultants in key markets across the United States, including San Francisco, San Diego, Phoenix, Detroit, Pittsburgh, Baltimore, Hartford, and New York.