PHPUnit Javascript testing tutorial

Last updated on
18 February 2018

This documentation is incomplete. Add more information.

As part of 8.1.x we introduced a way to test Javascript code in an end-to-end testing way. This means the entire Drupal site (exactly like in WebTestBase / BrowserTestBase) is set up.

Component Diagram

PHPUnit Javascript testing Component Diagram

Image source: Drupadocs

Execute tests

In order to run it, you need to install Phantomjs, and then, from the root of your Drupal install, execute the following command to start phantomjs:

phantomjs --ssl-protocol=any --ignore-ssl-errors=true ./vendor/jcalderonzumba/gastonjs/src/Client/main.js 8510 1024 768 2>&1 >> /dev/null &

The following options can be added right after -ignore-ssl-errors=true.

Option Description
--cookies-file=/tmp/cookies.txt Enables settings cookies in PhantomJS
--debug=true Makes the phantomJS more verbose. Only useful if you don't add 2>&1 >> /dev/null & at the end.

The next step is to setup some environment variables. Therefore copy the file core/phpunit.xml.distto core/phpunit.xml and edit the lines that set the values for SIMPLETEST_DB and SIMPLETEST_BASE_URL. For example, if you are using an sqlite database and the base URL of your site is, this might be:

<env name="SIMPLETEST_DB" value="sqlite://localhost/sites/default/files/.ht.sqlite"></env>
<env name="SIMPLETEST_BASE_URL" value=""></env>

There are a number of ways to now run the tests:

  • you can execute tests using phpunit. (_www is the user of the webserver, needed for permission issues. On other systems this might be, for example, www-data.)
sudo -u _www ./vendor/bin/phpunit -c core core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php
  • run the test is using This is more like the Drupal test-bot runs the tests but is much less verbose. If your tests passes using phpunit but fails on, try running your test using the following method:
sudo -u _www php ./core/scripts/ --verbose --sqlite [Valid path, eg: /tmp/test.sqlite] --url [Valid URL, eg:] --class "[Class including namespace to test]"
  • If you use PHPStorm, you can also run the tests straight from PHPStorm. Follow the setup guide here.

Write tests

The main difference from other tests is that the Javascript function tests are executed in a real browser. Javascript behaviours are executed, meaning the tests will have the same experience AND requirements that you have in a normal browser.


In order to write your own tests, you add a FunctionalJavascript folder inside yourmodule/tests/src and create a FooTest.php file.
In there ensure to extend \Drupal\FunctionalJavascriptTests\JavascriptTestBase. The namespace for your test will be \Drupal\Tests\[MODULENAME]\FunctionalJavascript.


In there you can do ordinary HTTP requests using drupalGet, but also click on links / press buttons. When pressing a submit button (that is not ajaxified) the page will submit and load the resulting page. After the page is loaded the test will continue.

NOTE: The test continues on the load event. If AJAX behaviors are triggered on load (for example in behaviors) you should add a $this->assertSession()->assertWaitOnAjaxRequest() after the load or, better yet, if you are waiting for elements to appear, you can use a waitForX method, see Waiting.

Finding and using elements

After loading a page you can use various methods of finding elements on the page. The most common methods are for this are (there are other methods but these are the most used):

$page = $this->getSession()->getPage();

// Find the submit button labeled 'Save'
$button = $page->findButton('Save');

// Find the field with the name 'test'
$field = $page->findField('field_test[0][value]');

// Find links
$link = $page->findLink('Link text');

// Find using css
$element = $page->find('css', 'css selector');

Before using an element you should always check if it was found:


After this you can start changing / using the element. For example: You can now check the visibility of an element, see the following code examples:

$page = $this->getSession()->getPage();
$content = $page->findLink('Content');

Ajax form interactions are also supported. The following will run the Ajax behaviours if there are any attached:

$this->getSession()->getPage()->find('css', '#somebutton')->click();


When clicking a link/button with Ajax behaviour attached, you need to keep in mind that the underlying browser might need a while to deliver changes to the HTML. The preferred method for this is to wait until an expected piece of UI is available. There are various methods available for this:

  • ::waitForElement()
  • ::waitForElementVisible()
  • ::waitForButton()
  • ::waitForLink()
  • ::waitForField()
  • ::waitForId()

The methods work similar to the find...() methods in that they return an element when found.

There are edge cases where you have to directly wait for the Ajax request to finish. Use $this->assertSession()->assertWaitOnAjaxRequest() to wait for that.

As a last resort you can use a custom javascript snippet code that needs to pass:

$this->assertJsCondition('Javascript condition that should equal TRUE');

You should always avoid waiting for a specific number of (milli)seconds. This would cause random failures in tests as sometimes the test will run longer than you'd expect, or you will wait too long causing the test to take more time then necessary.

Debug tests


If you want to see a screenshot to work out what is going on you can do this! (introduced in 8.1.9)


Don't put the screenshot in a path inside the test environment like public://test.jpg as this will be cleaned up at the end of the test.

Read more about the context of these changes at #2807237: PHPUnit initiative.

Screenshots on Drupal CI

If you want to see a screenshot to work out what is going when the Drupal CI testbot runs your tests, you can also do this! To achieve this, you have to write the screenshot to a directory which will be in the build artifacts. The folder sites/default/files/simpletest is such a folder.

Example code:

$this->createScreenshot(\Drupal::root() . '/sites/default/files/simpletest/screen.png');

You can then inspect your screenshot by clicking your way to this file:

  • Click the test result on the issue
  • Click View results on dispatcher
  • Expand the following path under Build Artifacts: simpletest.js -> phpunit-xml


Sometimes you'll want to inspect the HTML of the page or a specific element. There is no official method for this yet but the following works:

$this->assertEquals('', $this->getSession()->getPage()->getHTML());

Your test will now fail with the HTML in the assert error message.