I am spoiled by the many test watchers from the javascript world that do all the file change watching and polling on your behalf, to rerun the tests the moment you save a particular file. This feature usually comes out of the box, especially with the more complex tools like Jest or Cypress.
Trying to do the same thing with PHPUnit, the standard PHP testing framework used by Laravel too, I found automatic test running on file change not included as a first-class citizen. I have found multiple packages that could be installed by composer, buy all of them did not appeal to me.
I am a script kiddie
Yes, StackOverflow copy-paste to the rescue. Again. The dead-simple solution written in Bash could be found in this answer and looks like this:
#!/bin/bash
while true; do
FILE=$(inotifywait --exclude=".*.*sw*" --exclude="4913" ./ --format "%w%f" -e close_write) &&
clear &&
phpunit --color $FILE
done
Kudos for the user
Tango Bravo for
providing it. The author also claims the script is vim compatible, due to
the magic number 4913
which I do not understand unfortunately. As a
proper script-kiddie, not understanding every part of the script did not
prevent me putting the script into the Laravel project directory, made it
executable and run it.
Not part of the playground: inotifywait
Yeah, expecting something to run on the first time might be foolish:
./watch.sh: line 3: inotifywait: command not found
If you follow my posts for long enough, where long enough means something around three months worth of my blogging career, which is hilariously short time, you probably know how to determine which package provides the file. I did exactly that:
$ pkgfile inotifywait
extra/bash-completion
community/inotify-tools
A tough choice for a zsh
user
sudo pacman -S inotify-tools
The script now runs without command not found
complains.
Sail to the distant shores
The first optimization that I did with the running watch script was to change the test command. With the Laravel 8, the Laravel Sail is available. I had it running already, so why not use it?
#!/bin/bash
while true; do
FILE=$(inotifywait --exclude=".*.*sw*" --exclude="4913" ./ --format "%w%f" -e close_write) &&
clear &&
- phpunit --color $FILE
+ ./vendor/bin/sail artisan test
done
Still, editing any project file deeper in the directory structure did not trigger the test run. We need to go recursive for that:
#!/bin/bash
while true; do
FILE=$(inotifywait --recursive --exclude=".*.*sw*" --exclude="4913" ./ --format "%w%f" -e close_write) &&
clear &&
./vendor/bin/sail artisan test
done
This works reasonably well, but it can get a little bit better still.
Focus please
One problem with the above is that a mere git status
triggers the test
run as the command probably writes some file into the .git/
directory (I
did not test, but it is the most likely reason). Luckily, we just need a
monitor a few key directories, namely app/
, tests/
, routes/
and
possibly resources/
. They can be specified easily:
#!/bin/bash
while true; do
FILE=$(inotifywait --recursive --exclude=".*.*sw*" --exclude="4913" ./app ./tests ./routes ./resources/ --format "%w%f" -e close_write) &&
clear &&
./vendor/bin/sail artisan test
done
I keep this script running on the side monitor. Currently it works well enough. Happy testing!