One of the best features of Jest (the JavaScript testing library) is its
watch mode, which can be activated by adding the --watch
flag to the call
of the jest
command. So if the jest
executable is in your current path, you can call it like that:
jest --watch
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. 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.
But the ls
command is only the easiest way to get a list of files entr
should watch. A more powerful alternative is
the 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 entr
should
start watching. If you e.g. want to run your entire test suite whenever a file is changed, which instantiates a Media
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
The -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.
Of course you can also combine this new knowledge with any of your previous knowledge of your shell. But keep in mind
that this is still not as powerful as Jest's watch feature. That is because Jest can analyze the JavaScript code, and
will even be able to tell which files are importing a changed file, and include that information when finding the tests
that are affected by this change.
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
whenever my 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
:
pacman -S entr
I am sure that other linux distributions also have an entr
package, so check it out and happy entring!
Top comments (0)