diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index f151b85..42bc7ef 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -619,9 +619,9 @@ function drupal_valid_test_ua($new_prefix = NULL) {
   // string.
   $http_user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL;
   $user_agent = isset($_COOKIE['SIMPLETEST_USER_AGENT']) ? $_COOKIE['SIMPLETEST_USER_AGENT'] : $http_user_agent;
-  if (isset($user_agent) && preg_match("/^(simpletest\d+);(.+);(.+);(.+)$/", $user_agent, $matches)) {
+  if (isset($user_agent) && preg_match("/^(simpletest\d+):(.+):(.+):(.+)$/", $user_agent, $matches)) {
     list(, $prefix, $time, $salt, $hmac) = $matches;
-    $check_string =  $prefix . ';' . $time . ';' . $salt;
+    $check_string =  $prefix . ':' . $time . ':' . $salt;
     // Read the hash salt prepared by drupal_generate_test_ua().
     // This function is called before settings.php is read and Drupal's error
     // handlers are set up. While Drupal's error handling may be properly
@@ -678,8 +678,8 @@ function drupal_generate_test_ua($prefix) {
   }
   // Generate a moderately secure HMAC based on the database credentials.
   $salt = uniqid('', TRUE);
-  $check_string = $prefix . ';' . time() . ';' . $salt;
-  return $check_string . ';' . Crypt::hmacBase64($check_string, $key);
+  $check_string = $prefix . ':' . time() . ':' . $salt;
+  return $check_string . ':' . Crypt::hmacBase64($check_string, $key);
 }
 
 /**
diff --git a/core/modules/simpletest/src/BrowserTestBase.php b/core/modules/simpletest/src/BrowserTestBase.php
index b5da13c..7e5b96b 100644
--- a/core/modules/simpletest/src/BrowserTestBase.php
+++ b/core/modules/simpletest/src/BrowserTestBase.php
@@ -29,6 +29,7 @@
 use Drupal\user\Entity\User;
 use Drupal\user\UserInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Zumba\Mink\Driver\PhantomJSDriver;
 
 /**
  * Provides a test case for functional Drupal tests.
@@ -227,6 +228,13 @@
   protected $preserveGlobalState = FALSE;
 
   /**
+   * The base URL.
+   *
+   * @var string
+   */
+   protected $baseUrl;
+
+  /**
    * Initializes Mink sessions.
    */
   protected function initMink() {
@@ -236,6 +244,14 @@ protected function initMink() {
     $this->mink->registerSession('default', $session);
     $this->mink->setDefaultSessionName('default');
     $this->registerSessions();
+
+    // Fire up the first request to the front page in order to be able to  set
+    // a cookie later.
+    // @fixme This is done to circumvent:
+    // WebDriver\Exception\UnableToSetCookie: {"errorMessage":"Unable to set Cookie: no URL has been loaded yet","request":{"headers":{"Accept":"application/json;charset=UTF-8","Content-Length":"164","Content-Type":"application/json;charset=UTF-8","Host":"127.0.0.1:8910"},"httpVersion":"1.1","method":"POST","post":"{\"cookie\":{\"name\":\"SIMPLETEST_USER_AGENT\",\"value\":\"simpletest472558;1441488302;55eb5dae78eeb7.36607058;IxhRvB7dhbDAMurfBshqgUwEOpAPPKybnJMv0JgaG8Q\",\"secure\":false}}","url":"/cookie","urlParsed":{"anchor":"","query":"","file":"cookie","directory":"/","path":"/cookie","relative":"/cookie","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/cookie","queryKey":{},"chunks":["cookie"]},"urlOriginal":"/session/91aef6b0-5414-11e5-9028-67c7fcbbdc3b/cookie"}}
+    $session = $this->getSession();
+    $session->visit($this->baseUrl);
+
     return $session;
   }
 
@@ -266,7 +282,7 @@ protected function getDefaultDriverInstance() {
 
     if (is_array($this->minkDefaultDriverArgs)) {
        // Use ReflectionClass to instantiate class with received params.
-      $reflector = new ReflectionClass($this->minkDefaultDriverClass);
+      $reflector = new \ReflectionClass($this->minkDefaultDriverClass);
       $driver = $reflector->newInstanceArgs($this->minkDefaultDriverArgs);
     }
     else {
@@ -312,6 +328,8 @@ protected function setUp() {
     $path = isset($parsed_url['path']) ? rtrim(rtrim($parsed_url['path']), '/') : '';
     $port = isset($parsed_url['port']) ? $parsed_url['port'] : 80;
 
+    $this->baseUrl = $base_url;
+
     // If the passed URL schema is 'https' then setup the $_SERVER variables
     // properly so that testing will run under HTTPS.
     if ($parsed_url['scheme'] === 'https') {
diff --git a/core/modules/simpletest/src/TestDiscovery.php b/core/modules/simpletest/src/TestDiscovery.php
index d2c49d7..735c03d 100644
--- a/core/modules/simpletest/src/TestDiscovery.php
+++ b/core/modules/simpletest/src/TestDiscovery.php
@@ -80,9 +80,10 @@ public function registerTestNamespaces() {
     $existing = $this->classLoader->getPrefixesPsr4();
 
     // Add PHPUnit test namespaces of Drupal core.
-    $this->testNamespaces['Drupal\\Tests\\'] = [DRUPAL_ROOT . '/core/tests/Drupal/Tests'];
-    $this->testNamespaces['Drupal\\KernelTests\\'] = [DRUPAL_ROOT . '/core/tests/Drupal/KernelTests'];
-    $this->testNamespaces['Drupal\\FunctionalTests\\'] = [DRUPAL_ROOT . '/core/tests/Drupal/FunctionalTests'];
+    $this->testNamespaces['Drupal\\Tests\\'] = [$this->root . '/core/tests/Drupal/Tests'];
+    $this->testNamespaces['Drupal\\KernelTests\\'] = [$this->root . '/core/tests/Drupal/KernelTests'];
+    $this->testNamespaces['Drupal\\FunctionalTests\\'] = [$this->root . '/core/tests/Drupal/FunctionalTests'];
+    $this->testNamespaces['Drupal\\FunctionalJavascriptTests\\'] = [$this->root . '/core/tests/Drupal/FunctionalJavascriptTests'];
 
     $this->availableExtensions = array();
     foreach ($this->getExtensions() as $name => $extension) {
@@ -101,6 +102,7 @@ public function registerTestNamespaces() {
       $this->testNamespaces["Drupal\\Tests\\$name\\Unit\\"][] = "$base_path/tests/src/Unit";
       $this->testNamespaces["Drupal\\Tests\\$name\\Kernel\\"][] = "$base_path/tests/src/Kernel";
       $this->testNamespaces["Drupal\\Tests\\$name\\Functional\\"][] = "$base_path/tests/src/Functional";
+      $this->testNamespaces["Drupal\\Tests\\$name\\FunctionalJavascript\\"][] = "$base_path/tests/src/FunctionalJavascript";
     }
 
     foreach ($this->testNamespaces as $prefix => $paths) {
diff --git a/core/modules/simpletest/tests/src/FunctionalJavascript/BrowserWithJavascriptTest.php b/core/modules/simpletest/tests/src/FunctionalJavascript/BrowserWithJavascriptTest.php
new file mode 100644
index 0000000..81d8425
--- /dev/null
+++ b/core/modules/simpletest/tests/src/FunctionalJavascript/BrowserWithJavascriptTest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\Tests\simpletest\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+
+/**
+ * Tests a browser with javascript.
+ *
+ * @group javascript
+ */
+class BrowserWithJavascriptTest extends JavascriptTestBase {
+
+  public function testJavascript() {
+    $this->drupalGet('<front>');
+    $session = $this->getSession();
+
+    $session->resizeWindow(400, 300);
+    $session->wait(1000, 'false');
+    $javascript = <<<JS
+    (function(){
+        var w = window,
+        d = document,
+        e = d.documentElement,
+        g = d.getElementsByTagName('body')[0],
+        x = w.innerWidth || e.clientWidth || g.clientWidth,
+        y = w.innerHeight|| e.clientHeight|| g.clientHeight;
+        var size = {};
+        size["width"]=x;
+        size["height"]= y;
+        return size;
+    }());
+JS;
+    $pageSize = $session->evaluateScript($javascript);
+    $this->assertEquals(400, $pageSize["width"]);
+    $this->assertEquals(300, $pageSize["height"]);
+  }
+
+}
diff --git a/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php b/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php
new file mode 100644
index 0000000..8428643
--- /dev/null
+++ b/core/modules/toolbar/tests/src/FunctionalJavascript/ToolbarIntegrationTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Drupal\Tests\toolbar\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+
+/**
+ * Basic toolbar testing.
+ *
+ * @group toolbar
+ */
+class ToolbarIntegrationTest extends JavascriptTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['toolbar', 'node'];
+
+  public function testToolbarToggling() {
+    $admin_user = $this->drupalCreateUser([
+      'access toolbar',
+      'administer site configuration',
+      'access content overview'
+    ]);
+    $this->drupalLogin($admin_user);
+
+    $this->drupalGet('<front>');
+
+    // Test that it is possible to toggle the toolbar tray.
+    $this->assertTrue($this->getSession()->getDriver()->isVisible('.//a[@id="toolbar-link-system-admin_content"]'), 'Toolbar tray is open by default.');
+    $this->getSession()->getDriver()->click('.//a[@id="toolbar-item-administration"]');
+    $this->assertFalse($this->getSession()->getDriver()->isVisible('//a[@id="toolbar-link-system-admin_content"]'), 'Toolbar tray is closed after clicking the "Manage" button.');
+    $this->getSession()->getDriver()->click('.//a[@id="toolbar-item-administration"]');
+    $this->assertTrue($this->getSession()->getDriver()->isVisible('//a[@id="toolbar-link-system-admin_content"]'), 'Toolbar tray is visible again after clicking the "Manage" button a second time.');
+
+    // Test toggling the toolbar tray between horizontal and vertical.
+    $this->assertTrue($this->getSession()->getDriver()->isVisible('.//div[@id="toolbar-item-administration-tray" and contains(concat(" ", @class, " "), " toolbar-tray-horizontal ")]'), 'Toolbar tray is horizontally oriented by default.');
+    $this->assertEmpty($this->getSession()->getDriver()->find('.//div[@id="toolbar-item-administration-tray" and contains(concat(" ", @class, " "), " toolbar-tray-vertical ")]'), 'Toolbar tray not vertically oriented by default.');
+
+    $this->getSession()->getDriver()->click('.//div[@id="toolbar-item-administration-tray"]//button[contains(concat(" ", @class, " "), " toolbar-icon-toggle-vertical ")]');
+    $this->assertTrue($this->getSession()->getDriver()->wait(1000, 'jQuery("#toolbar-item-administration-tray").hasClass("toolbar-tray-vertical")'));
+    $this->assertTrue($this->getSession()->getDriver()->isVisible('.//div[@id="toolbar-item-administration-tray" and contains(concat(" ", @class, " "), " toolbar-tray-vertical ")]'), 'After toggling the orientation the toolbar tray is now displayed vertically.');
+
+    $this->getSession()->getDriver()->click('.//div[@id="toolbar-item-administration-tray"]//button[contains(concat(" ", @class, " "), " toolbar-icon-toggle-horizontal ")]');
+    $this->assertTrue($this->getSession()->getDriver()->wait(1000, 'jQuery("#toolbar-item-administration-tray").hasClass("toolbar-tray-horizontal")'));
+    $this->assertTrue($this->getSession()->getDriver()->isVisible('.//div[@id="toolbar-item-administration-tray" and contains(concat(" ", @class, " "), " toolbar-tray-horizontal ")]'), 'After toggling the orientation a second time the toolbar tray is displayed horizontally again.');
+  }
+
+}
diff --git a/core/phpunit.xml.dist b/core/phpunit.xml.dist
index 2620fe9..4b9150e 100644
--- a/core/phpunit.xml.dist
+++ b/core/phpunit.xml.dist
@@ -50,6 +50,17 @@
       <!-- Exclude Drush tests. -->
       <exclude>./drush/tests</exclude>
     </testsuite>
+    <testsuite name="functional-javascript">
+      <directory>./tests/Drupal/FunctionalJavascriptTests</directory>
+      <directory>./modules/*/tests/src/FunctionalJavascript</directory>
+      <directory>../modules/*/tests/src/FunctionalJavascript</directory>
+      <directory>../profiles/*/tests/src/FunctionalJavascript</directory>
+      <directory>../sites/*/modules/*/tests/src/FunctionalJavascript</directory>
+      <!-- Exclude Composer's vendor directory so we don't run tests there. -->
+      <exclude>./vendor</exclude>
+      <!-- Exclude Drush tests. -->
+      <exclude>./drush/tests</exclude>
+    </testsuite>
   </testsuites>
   <listeners>
     <listener class="\Drupal\Tests\Listeners\DrupalStandardsListener">
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JavascriptTestBase.php b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptTestBase.php
new file mode 100644
index 0000000..fd7df67
--- /dev/null
+++ b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptTestBase.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\FunctionalJavascriptTests;
+
+use Drupal\simpletest\BrowserTestBase;
+use Zumba\Mink\Driver\PhantomJSDriver;
+
+/**
+ * Runs a browser test using phantomJS.
+ *
+ * Use this test baseclass if you want to test expected behaviour of some
+ * JavaScript.
+ */
+abstract class JavascriptTestBase extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $minkDefaultDriverClass = PhantomjsDriver::class;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function initMink() {
+    // Setup some template cache using by the phantomjs mink driver.
+    $path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
+    $this->minkDefaultDriverArgs = [
+      'http://127.0.0.1:8510',
+      $path,
+    ];
+    if (!file_exists($path)) {
+      mkdir($path);
+    }
+    parent::initMink();
+  }
+
+}
diff --git a/core/tests/README.md b/core/tests/README.md
new file mode 100644
index 0000000..df091f3
--- /dev/null
+++ b/core/tests/README.md
@@ -0,0 +1,14 @@
+# Running tests
+
+## Function tests
+
+* Start phantomjs:
+```
+phantomjs --ssl-protocol=any --ignore-ssl-errors=true vendor/jcalderonzumba/gastonjs/src/Client/main.js 8510 1024 768 2>&1 >> /dev/null &
+```
+* Run the function tests:
+```
+export SIMPLETEST_DB='mysql://root@localhost/dev_d8'
+export SIMPLETEST_BASE_URL='http://d8.dev'
+vendor/bin/phpunit -c core core/modules/simpletest/tests/src/Functional/BrowserTestBaseTest.php
+```
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index f1f7862..12c4deb 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -104,6 +104,8 @@ function drupal_phpunit_populate_class_loader() {
   // Start with classes in known locations.
   $loader->add('Drupal\\Tests', __DIR__);
   $loader->add('Drupal\\KernelTests', __DIR__);
+  $loader->add('Drupal\\FunctionalTests', __DIR__);
+  $loader->add('Drupal\\FunctionalJavascriptTests', __DIR__);
 
   if (!isset($GLOBALS['namespaces'])) {
     // Scan for arbitrary extension namespaces from core and contrib.
