Automatic command execution on file changes with entr
watch mode, which can be activated by adding the
--watch flag to the call
jest command. So if the
jest executable is in your current path, you can call it like that:
And what this simple flag does is absolutely amazing. Instead of just executing all the tests and shut down, Jest will execute only the tests being affected by the currently not staged changes of your git repository. That means you don’t have to execute all the tests all the time, which will result in much less load on your machine. At the same time only the necessary tests run and finish much sooner, which will result in a much better developer experience. Additionally, Jest will watch all your files, and rerun your tests as soon as a file within your codebase changes.
A watch mode for PHPUnit
Actually I was so fascinated by this feature, that I wanted to have something similar for PHPUnit, my PHP testing framework of choice. Unfortunately I did not find any built-in solution, but I found another interesting generic-purpose tool called entr. Based on this I could build something I would call a poor man’s watch mode. Just recently I had to resolve a merge conflict in a PHP file; luckily the error was also caught by a unit test. Since the unit test failed, and I knew which file was causing the error, it was easily possible to rerun the unit test everytime the content of that PHP file changed.
ls path/to/source-file.php | entr phpunit --filter=path/to/test-file.php
ls in the above example will only return the path to
source-file.php and pass that value as input to the
entr command will add a file watch to this file, and execute the command it gets passed everytime
source-file.php changes its content. That’s already a poor man’s watch mode! And it was really useful in that case,
because I didn’t have to change to another terminal everytime I wanted to run the tests. I just had two terminals open,
and when I changed the content of
source-file.php in order to resolve the conflict in one terminal, the other
terminal automatically ran the tests without any manual instruction from my side.
ls command is only the easiest way to get a list of files
entr should watch. A more powerful alternative is
find command, that is also distributed with almost every linux installation. So we can use the following command
if we want to run the entire
phpunit testsuite when any file ending with
Test.php is updated:
find . -name "*Test.php" | entr phpunit
Mind that this might not make a lot of sense if you have a huge test suite, since waiting an hour after everytime you touch a PHP file would be a waste of time (so is waiting too long for your tests, so you might refactor that suite anyway).
You can even use other powerful tools like
ack to get the list of files
start watching. If you e.g. want to run your entire test suite whenever a file is changed, which instantiates a
object (again, not sure this is a very good use case, but I still want to show how it would work, so that you
understand it better) your command would look like this:
ack "new Media()" -l | entr phpunit
-l flag of the
ack command will only list the files containing this content, not the content itself. It is
necessary, because otherwise
entr get more than just a list of entries, and it wouldn’t be able to handle that.
Reuse that watch mode with other commands
Since we have found now a more generic solution to this problem (which comes with the just mentioned downsides) we
are able to also reuse that command in other situations. Something that I found very helpful is to automatically
create new HTML output when I am building one of my
markdown presentations. All
I have to do to make this work is to write a command like this, which will then run and create a new HTML output
slides.md file changes:
ls slides.md | entr make html
So while this approach is not as powerful as having a watch mode fully integrated in some other tools, I still like to have it in my toolbelt, since I can apply it to many different situations in which a watch mode might not be available.
If you are curious now and you want to play with
entr, you can easily install it in ArchLinux using
pacman -S entr
I am sure that other linux distributions also have an
entr package, so check it out and happy entring!