Javascript Testing Comes to Drupal 8

With the arrival of Drupal 8.1.0 finally you can test javascript interactions on Drupal.org. This is culmination of years of work by many developers to improve the testing API and infrastructure. Without the improvements delivered by Drupal 8 it'd be hard to leverage Mink, PhantomJS and PHPUnit to run our tests, and without the new DrupalCI infrastructure we'd have nowhere to run the tests.

So that's fantastic - but how do you run them locally?

The tests are run on a headless browser called PhantomJS. The first step is to install PhantomJS on your computer.

Once you've got PhantomJS you need start it. I find easiest way is to open a terminal window and run it interactively since then you can see requests arriving and can ensure it is working. If you start it from the root of your Drupal 8 checkout, the following command will work:

/path/to/phantomjs --ssl-protocol=any --ignore-ssl-errors=true vendor/jcalderonzumba/gastonjs/src/Client/main.js 8510 1024 768

Replace /path/to/phantomjs with the path to where you installed it.

Now we need to open up a new terminal window now we can run some tests. To do this we are going to use the phpunit runner. As a prerequisite you need to have cloned or downloaded Drupal and downloaded any dependencies using composer.

Firstly we ensure that sites/simpletest exists and is writeable by the user that is running the webserver.

mkdir sites/simpletest
chown _www sites/simpletest 

For my setup this user is called _www, for other setups it might be www-data or same user you are logged in as.

Next we configure the required environmental variables. Copy core/phpunit.xml.dist to core/phpunit.xml and edit the file. You need to set SIMPLETEST_BASE_URL to the url where your Drupal 8 install can be reached locally.
<env name="SIMPLETEST_BASE_URL" value=""></env>
For me, this becomes:
<env name="SIMPLETEST_BASE_URL" value="http://drupal8alt.dev"></env>

You also need to set SIMPLETEST_DB to a database connection URL.
<env name="SIMPLETEST_DB" value=""></env>
To use SQLite, for example, this becomes:
<env name="SIMPLETEST_DB" value="sqlite://localhost/sites/default/files/.ht.sqlite"></env>

Once this is set up from the root of your Drupal install you should be able to run the test doing:

sudo -u _www ./vendor/bin/phpunit -c core core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php

Notice that I'm running the test with the same user that is running the webserver. This is important because the test will install Drupal and create files and then use phantomjs to access the installed site via the webserver.

You should see something like this:
A successful Drupal 8 JavaScript test run: OK (1 test, 13 assertions)

In the other terminal window which is running PhantomJS you will see some json showing the requests and browser actions occurring.

You can also run tests using core/scripts/run-tests.sh. In order to do this you will need to install Drupal and install the Simpletest module. For example:

sudo -u _www php ./core/scripts/run-tests.sh --url http://drupal8alt.dev/ --class 'Drupal\Tests\toolbar\FunctionalJavascript\ToolbarIntegrationTest'

Unfortunately if things go wrong it can be really hard to work out why if you using run-tests.sh.

What next?

So let's start writing tests for all of our complex javascript. This will make it easier to not break anything when we fix javascript bugs and it will make it easier to refactor or upgrade javascript dependencies and know we've broken nothing. To this end, I've started writing tests for Form API's #states.

Drupal now needs us to add test coverage of all the fantastic features we added in Drupal 8. Good places to start will be inline editing, CKEditor integration, the Views UI and our Ajax API.