Running PHPUnit JavaScript tests

Last updated on
28 February 2025

This documentation needs review. See "Help improve this page" in the sidebar.

Requirements

  • Base install of Drupal 9 or higher.
  • Google Chrome or Chromium.
  • chromedriver (tested with 2.45 - you will typically need the version that matches the version of your installed Chrome browser).
  • PHP 7.1 or higher.

Configuration

See Running PHPUnit tests for how to set up your own phpunit.xml for testing. Specific callouts for FunctionalJavascript tests:

SIMPLETEST_BASE_URL domain must use http:// protocol and a complete URL, otherwise it will throw the exception "invalid cookie domain" or "unable to set cookies." Example:

<env name="SIMPLETEST_BASE_URL" value="http://drupal8.localhost"/>

Move the chromedriver to /usr/local/bin and you should be able to run chromedriver from any directory.

Start chromedriver using port 4444 and keep it running.

$ chromedriver --port=4444
ChromeDriver 2.45.615355 (d5698f682d8b2742017df6c81e0bd8e6a3063189) on port 4444
Only local connections are allowed.

In a server environment (or in WSL) where X Windows is not available, install xvfb and run xvfb-run chromedriver --port=4444

Running tests

You can now run tests on the command line using PHPUnit, for example:

./vendor/bin/phpunit -v -c ./core/phpunit.xml ./core/modules/system/tests/src/FunctionalJavascript/FrameworkTest.php

Note: this assumes you're running the tests from the root directory of a Drupal checkout, that your phpunit.xml file lives in the core subdirectory, and that your vendor directory is "next to" core. The specific paths might vary based on your workflow. See the Configure PHPUnit and Locate the PHPUnit binary sections of the Running PHPUnit tests page for details.

Do not use core/scripts/run-tests.sh for JavaScript tests. When ChromeDriver is not running, it will say tests passed when in fact they did not run.

Debugging Tests

If your test is having a strange problem, you can add a line like this just before the failure, which will basically stop the test in Chrome and let you play with the test site and look around:

$this->assertSession()->waitForElementVisible('css', '.test-wait', 100000000000000000000000000);

Running chromedriver in a container (Docker)

To run chromedriver in a docker-compose setup, the following will suffice in your docker-compose.yml:

  chrome:
    image: drupalci/webdriver-chromedriver:production
    ulimits:
      core:
        soft: -1
        hard: -1
    ports:
      - "4444:4444"
      - "9515:9515"
    entrypoint:
      - chromedriver
      - "--log-path=/tmp/chromedriver.log"
      - "--verbose"
      - "--allowed-ips="
      - "--allowed-origins=*"

You must adjust your /etc/hosts file to map chrome to 127.0.0.1.

Then configure your driver args in your phpunit.xml like so

<env name="MINK_DRIVER_ARGS_WEBDRIVER" value='["chrome", {"browserName":"chrome","goog:chromeOptions":{"args":["--disable-gpu","--headless", "--no-sandbox", "--disable-dev-shm-usage"]}}, "http://chrome:9515"]'/>

Overriding chromedriver args dynamically 

MINK_DRIVER_ARGS configuration is used for functional tests:
https://git.drupalcode.org/project/drupal/-/blob/10.1.x/core/tests/Drupa...

and MINK_DRIVER_ARGS_WEBDRIVER is used for functional JavaScript tests:
https://git.drupalcode.org/project/drupal/-/blob/10.1.x/core/tests/Drupa...

It is possible to dynamically override this property by inheriting getMinkDriverArgs() method ( if the test class extends from  WebDriverTestBase or BrowserTestBase ), see examples: 

protected function getMinkDriverArgs() {
return '["chrome", {"browserName":"chrome","chromeOptions":{"args":["--disable-gpu","--headless"]}}, "http://chrome:4444"]';
}

protected function getMinkDriverArgs() {
$args = json_decode(parent::getMinkDriverArgs(), TRUE);
$args[1]['chromeOptions']['args'][] = '--no-sandbox';
return json_encode($args, JSON_UNESCAPED_SLASHES);
}

This can become handy when we'd like to modify driver behavior per test class (for example: running tests against different browser types), 
or to change the driver args when running automated tests in DrupalCI, which defaults to: 

["chrome", {"browserName":"chrome","chromeOptions":{"args":["--disable-gpu","--headless"]}}, "http://chromedriver-jenkins-drupal8-contrib-patches-141986:9515"]

See example use case - testing reCAPTCHA iframes in DrupalCI: https://www.drupal.org/project/simple_recaptcha/issues/3309489#comment-1...

FunctionalJavascript tests using DDEV

See the DDEV Contrib README and example docker compose chromedriver service. See also ddev selenium standlone chrome

Inside .ddev folder, add docker-compose.chromedriver.yaml file (this file can be get by click on above link)
Then run command: ddev restart

You can now run javaScripts tests on the command line using PHPUnit, for example:

./vendor/bin/phpunit -v -c ./core/phpunit.xml ./core/modules/system/tests/src/FunctionalJavascript/FrameworkTest.php

If you prefer to run PHPUnit without using DDEV SSH, you can prepend ddev exec to the relative path of the PHPUnit binary.

Troubleshooting

If you get the exception "chrome headless WebDriver\Exception\InvalidCookieDomain: invalid cookie domain," this is because you have defined https:// protocol in your SIMPLETEST_BASE_URL setting. Use http:// protocol.

Help improve this page

Page status: Needs review

You can: