diff --git a/.travis.yml b/.travis.yml
index d78abc3..e140e1f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -73,6 +73,12 @@ install:
   #- curl https://www.drupal.org/files/issues/2824932.patch | patch -p1
   #- cd $TRAVIS_BUILD_DIR/../drupal
   #########################################
+  #########################################
+  # to be removed once #2828848 is resolved
+  - cd modules/search_api
+  - curl https://www.drupal.org/files/issues/2828848_5_0.patch | patch -p1
+  - cd $TRAVIS_BUILD_DIR/../drupal
+  #########################################
 
 before_script:
   # Start the built-in php web server (mysql is already started) and
@@ -89,24 +95,9 @@ script:
   - cd $TRAVIS_BUILD_DIR/../drupal
   - export SIMPLETEST_DB=mysql://root:@localhost/drupal
   - export SIMPLETEST_BASE_URL=http://localhost:8888
-  - php core/scripts/run-tests.sh --verbose --color --non-html --concurrency 8 --php `which php` --url http://localhost:8888 --directory modules/search_api_solr --types Simpletest | tee /tmp/test.txt | grep passes; export TEST_EXIT=${PIPESTATUS[0]} ; echo $TEST_EXIT
-  # Check if we had fails in the run-tests.sh script
-  # Exit with the inverted value, because if there are no fails found, it will exit with 1 and for us that\
-  # is a good thing so invert it to 0. Travis has some issues with the exclamation mark in front so we have to fiddle a
-  # bit.
-  # Also make the grep case insensitive and fail on run-tests.sh regular fails as well on fatal errors.
-  - TEST_OUTPUT=$(! egrep -i "([0-9]+ fails)|(Fatal erro)|([0-9]+ exceptions)" /tmp/test.txt > /dev/null)$?
-  - cd $TRAVIS_BUILD_DIR/../drupal
   - ./vendor/bin/phpunit -c core --group search_api_solr --verbose --debug | tee ; export TEST_PHPUNIT=${PIPESTATUS[0]} ; echo $TEST_PHPUNIT
-  #- ./vendor/bin/phpunit --group search_api_solr -c "../modules/search_api_solr/phpunit.xml.travis" --verbose --debug --coverage-text | tee ; export TEST_PHPUNIT=${PIPESTATUS[0]} ; echo $TEST_PHPUNIT
-  # if the TEST_EXIT status is 0 AND the TEST_OUTPUT status is also 0 it means we succeeded, in all other cases we
-  # failed.
   # Re-enable when trying to get CodeSniffer doesn't return a 403 anymore.
   #- /home/travis/.composer/vendor/bin/phpcs --standard=/home/travis/.composer/vendor/drupal/coder/coder_sniffer/Drupal --extensions=php,inc,test,module,install --ignore=css/ $TRAVIS_BUILD_DIR/../drupal/modules/search_api
-  - php -i | grep 'php.ini'
   # Exit the build
-  - echo $TEST_EXIT
-  - echo $TEST_OUTPUT
   - echo $TEST_PHPUNIT
-  - if [ $TEST_EXIT -ne 0 ]; then cat /tmp/test.txt; fi
-  - if [ $TEST_EXIT -eq 0 ] && [ $TEST_OUTPUT -eq 0 ] && [ $TEST_PHPUNIT -eq 0 ]; then exit 0; else exit 1; fi
+  - if [ $TEST_PHPUNIT -eq 0 ]; then exit 0; else exit 1; fi
diff --git a/tests/src/Functional/FacetsTest.php b/tests/src/Functional/FacetsTest.php
index e5e6519..8f4f8d3 100644
--- a/tests/src/Functional/FacetsTest.php
+++ b/tests/src/Functional/FacetsTest.php
@@ -2,17 +2,19 @@
 
 namespace Drupal\Tests\search_api_solr\Functional;
 
+use Drupal\Component\Render\FormattableMarkup;
 use Drupal\facets\Tests\BlockTestTrait;
 use Drupal\facets\Tests\ExampleContentTrait;
 use Drupal\facets\Tests\TestHelperTrait;
+use Drupal\Tests\search_api\Functional\SearchApiBrowserTestBase;
 use Drupal\views\Entity\View;
 
 /**
- * Tests the overall functionality of the Search API framework and admin UI.
+ * Tests the facets functionality using the Solr backend.
  *
  * @group search_api_solr
  */
-class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTest {
+class FacetsTest extends SearchApiBrowserTestBase {
 
   use BlockTestTrait;
   use ExampleContentTrait {
@@ -21,27 +23,6 @@ class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTes
   use TestHelperTrait;
 
   /**
-   * The backend of the search server used for this test.
-   *
-   * @var string
-   */
-  protected $serverBackend = 'search_api_solr';
-
-  /**
-   * A search index ID.
-   *
-   * @var string
-   */
-  protected $indexId;
-
-  /**
-   * A storage instance for indexes.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $indexStorage;
-
-  /**
    * {@inheritdoc}
    */
   public static $modules = array(
@@ -54,61 +35,9 @@ class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTes
   );
 
   /**
-   * {@inheritdoc}
-   */
-  protected function tearDown() {
-    if ($this->indexId) {
-      $this->getIndex()->clear();
-      sleep(2);
-    }
-    parent::tearDown();
-  }
-
-  /**
-   * Tests various operations via the Search API's admin UI.
-   */
-  public function testFramework() {
-    $this->createServer();
-    $this->createServerDuplicate();
-    // @todo should work but doesn't.
-    //$this->checkServerAvailability();
-    $this->createIndex();
-    $this->createIndexDuplicate();
-    $this->editServer();
-    $this->editIndex();
-    $this->checkUserIndexCreation();
-    // This tests doesn't cover the backend. No need to run it on Solr again.
-    //$this->checkContentEntityTracking();
-
-    // @todo overwrite.
-    //$this->enableAllProcessors();
-    $this->checkFieldLabels();
-
-    // @todo overwrite.
-    //$this->addFieldsToIndex();
-    //$this->checkDataTypesTable();
-    //$this->removeFieldsFromIndex();
-    //$this->checkReferenceFieldsNonBaseFields();
-
-    // These tests don't cover the backend. No need to run them on Solr again.
-    //$this->configureFilter();
-    //$this->configureFilterPage();
-    //$this->checkProcessorChanges();
-    //$this->changeProcessorFieldBoost();
-
-    $this->setReadOnly();
-    // These tests don't cover the backend. No need to run them on Solr again.
-    //$this->disableEnableIndex();
-    $this->changeIndexDatasource();
-    $this->changeIndexServer();
-
-    $this->deleteServer();
-  }
-
-  /**
    * Tests basic facets integration.
    */
-  public function _testFacets() {
+  public function testFacets() {
     $view = View::load('search_api_test_view');
     $this->assertEquals('search_api_index_solr_search_index', $view->get('base_table'));
 
@@ -120,7 +49,6 @@ class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTes
       'administer blocks',
     ]);
     $this->drupalLogin($admin_user);
-    $this->indexId = 'solr_search_index';
 
     // Check that the test index is on the admin overview
     $this->drupalGet('admin/config/search/search-api');
@@ -128,10 +56,7 @@ class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTes
 
     $this->setUpExampleStructure();
     $this->insertExampleContent();
-
-    /** @var \Drupal\search_api\IndexInterface $index */
-    $index = $this->indexStorage->load($this->indexId);
-    $indexed_items = $this->indexItems($this->indexId);
+    $indexed_items = $this->indexItems('solr_search_index');
     $this->assertEquals(5, $indexed_items, 'Five items are indexed.');
 
     // Create a facet, enable 'show numbers'.
@@ -151,63 +76,63 @@ class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTes
   }
 
   /**
-   * {@inheritdoc}
+   * Indexes all (unindexed) items on the specified index.
    *
-   * This test doesn't really include any backend specific stuff and could be
-   * skipped.
+   * @return int
+   *   The number of successfully indexed items.
    */
-  public function testIntegerIndex() {
-    // Nothing to do here.
+  protected function indexItems($index_id) {
+    $index_status = $this->doindexItems($index_id);
+    sleep(2);
+    return $index_status;
   }
 
   /**
-   * {@inheritdoc}
+   * Follows a link by partial name.
+   *
+   * If the link is discovered and clicked, the test passes. Fail otherwise.
+   *
+   * @param string|\Drupal\Component\Render\MarkupInterface $label
+   *   Text between the anchor tags, uses starts-with().
+   * @param int $index
+   *   Link position counting from zero.
+   *
+   * @return string|bool
+   *   Page contents on success, or FALSE on failure.
+   *
+   * @see ::clickLink()
    */
-  protected function configureBackendAndSave(array $edit) {
-    $this->submitForm($edit, 'Save');
-    $this->assertSession()->pageTextContains('Please configure the selected backend.');
-
-    $edit += [
-      'backend_config[connector]' => 'standard',
-    ];
-    $this->submitForm($edit, 'Save');
-    $this->assertSession()->pageTextContains('Please configure the selected Solr connector.');
-
-    $edit += [
-      'backend_config[connector_config][host]' => 'localhost',
-      'backend_config[connector_config][port]' => '8983',
-      'backend_config[connector_config][path]' => '/',
-      'backend_config[connector_config][core]' => '',
-    ];
-    $this->submitForm($edit, 'Save');
-
-    $this->assertSession()->pageTextContains('The server was successfully saved.');
-    $this->assertSession()->addressEquals('admin/config/search/search-api/server/' . $this->serverId);
-    $this->assertSession()->pageTextContains('The Solr server could not be reached or is protected by your service provider.');
-
-    // Go back in and configure Solr.
-    $edit_path = 'admin/config/search/search-api/server/' . $this->serverId . '/edit';
-    $this->drupalGet($edit_path);
-    $edit = [
-      'backend_config[connector_config][host]' => 'localhost',
-      'backend_config[connector_config][port]' => '8983',
-      'backend_config[connector_config][path]' => '/solr',
-      'backend_config[connector_config][core]' => 'd8',
-    ];
-    $this->submitForm($edit, 'Save');
-    $this->assertSession()->pageTextContains('The Solr server could be reached.');
- }
+  protected function clickLinkPartialName($label, $index = 0) {
+    return $this->clickLinkHelper($label, $index, '//a[starts-with(normalize-space(), :label)]');
+  }
 
   /**
-   * Indexes all (unindexed) items on the specified index.
+   * Provides a helper for ::clickLink() and ::clickLinkPartialName().
    *
-   * @return int
-   *   The number of successfully indexed items.
+   * @param string|\Drupal\Component\Render\MarkupInterface $label
+   *   Text between the anchor tags, uses starts-with().
+   * @param int $index
+   *   Link position counting from zero.
+   * @param string $pattern
+   *   A pattern to use for the XPath.
+   *
+   * @return bool|string
+   *   Page contents on success, or FALSE on failure.
    */
-  protected function indexItems() {
-    $index_status = parent::indexItems();
-    sleep(2);
-    return $index_status;
+  protected function clickLinkHelper($label, $index, $pattern) {
+    // Cast MarkupInterface objects to string.
+    $label = (string) $label;
+    $url_before = $this->getUrl();
+    $urls = $this->xpath($pattern, array(':label' => $label));
+    if (isset($urls[$index])) {
+      /** @var \Behat\Mink\Element\NodeElement $url */
+      $url = $urls[$index];
+      $url_target = $this->getAbsoluteUrl($url->getAttribute('href'));
+      $this->assertTrue(TRUE, new FormattableMarkup('Clicked link %label (@url_target) from @url_before', array('%label' => $label, '@url_target' => $url_target, '@url_before' => $url_before)));
+      return $this->drupalGet($url_target);
+    }
+    $this->assertTrue(FALSE, new FormattableMarkup('Link %label does not exist on @url_before', array('%label' => $label, '@url_before' => $url_before)));
+    return FALSE;
   }
 
 }
diff --git a/tests/src/Functional/IntegrationTest.php b/tests/src/Functional/IntegrationTest.php
index 1869b6b..4edbae8 100644
--- a/tests/src/Functional/IntegrationTest.php
+++ b/tests/src/Functional/IntegrationTest.php
@@ -1,34 +1,17 @@
 <?php
 
-namespace Drupal\search_api_solr\Tests;
+namespace Drupal\Tests\search_api_solr\Functional;
 
-use Drupal\Component\Utility\Html;
 use Drupal\facets\Tests\BlockTestTrait;
 use Drupal\facets\Tests\ExampleContentTrait;
 use Drupal\facets\Tests\TestHelperTrait;
-use Drupal\search_api\Entity\Index;
-use Drupal\search_api\Tests\WebTestBase;
-use Drupal\views\Entity\View;
 
 /**
  * Tests the overall functionality of the Search API framework and admin UI.
  *
  * @group search_api_solr
  */
-class IntegrationTest extends WebTestBase {
-
-  use BlockTestTrait;
-  use ExampleContentTrait {
-    indexItems as doIndexItems;
-  }
-  use TestHelperTrait;
-
-  /**
-   * The ID of the search server used for this test.
-   *
-   * @var string
-   */
-  protected $serverId;
+class IntegrationTest extends \Drupal\Tests\search_api\Functional\IntegrationTest {
 
   /**
    * The backend of the search server used for this test.
@@ -38,51 +21,21 @@ class IntegrationTest extends WebTestBase {
   protected $serverBackend = 'search_api_solr';
 
   /**
-   * A search index ID.
-   *
-   * @var string
-   */
-  protected $indexId;
-
-  /**
-   * A storage instance for indexes.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $indexStorage;
-
-  /**
    * {@inheritdoc}
    */
   public static $modules = array(
-    'block',
-    'field_ui',
-    'node',
-    'views',
-    'search_api',
     'search_api_solr',
     'search_api_solr_test',
-    'search_api_solr_test_facets',
-    'facets',
   );
 
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
-    parent::setUp();
-
-    $this->indexStorage = \Drupal::entityTypeManager()->getStorage('search_api_index');
-
-    $this->drupalLogin($this->adminUser);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   protected function tearDown() {
-    $this->getIndex()->clear();
-    sleep(2);
+    if ($this->indexId) {
+      $this->getIndex()->clear();
+      sleep(2);
+    }
     parent::tearDown();
   }
 
@@ -91,94 +44,65 @@ class IntegrationTest extends WebTestBase {
    */
   public function testFramework() {
     $this->createServer();
+    $this->createServerDuplicate();
+    // @todo should work but doesn't.
+    //$this->checkServerAvailability();
     $this->createIndex();
-    $this->checkContentEntityTracking();
+    $this->createIndexDuplicate();
+    $this->editServer();
+    $this->editIndex();
+    $this->checkUserIndexCreation();
+    // This tests doesn't cover the backend. No need to run it on Solr again.
+    //$this->checkContentEntityTracking();
+
+    // @todo overwrite.
+    //$this->enableAllProcessors();
+    $this->checkFieldLabels();
+
+    // @todo overwrite.
+    //$this->addFieldsToIndex();
+    //$this->checkDataTypesTable();
+    //$this->removeFieldsFromIndex();
+    //$this->checkReferenceFieldsNonBaseFields();
+
+    // These tests don't cover the backend. No need to run them on Solr again.
+    //$this->configureFilter();
+    //$this->configureFilterPage();
+    //$this->checkProcessorChanges();
+    //$this->changeProcessorFieldBoost();
+
+    $this->setReadOnly();
+    // @todo review.
+    //$this->disableEnableIndex();
+    $this->changeIndexDatasource();
     $this->changeIndexServer();
+
+    // @todo review.
+    //$this->deleteServer();
   }
 
   /**
-   * Tests basic facets integration.
+   * {@inheritdoc}
+   *
+   * This test doesn't really include any backend specific stuff and could be
+   * skipped.
    */
-  public function testFacets() {
-    $view = View::load('search_api_test_view');
-    $this->assertEqual($view->get('base_table'), 'search_api_index_solr_search_index');
-
-    // Create the users used for the tests.
-    $admin_user = $this->drupalCreateUser([
-      'administer search_api',
-      'administer facets',
-      'access administration pages',
-      'administer blocks',
-    ]);
-    $this->drupalLogin($admin_user);
-    $this->indexId = 'solr_search_index';
-
-    // Check that the test index is on the admin overview
-    $this->drupalGet('admin/config/search/search-api');
-    $this->assertText('Test index');
-
-    $this->setUpExampleStructure();
-    $this->insertExampleContent();
-
-    /** @var \Drupal\search_api\IndexInterface $index */
-    $index = $this->indexStorage->load($this->indexId);
-    $indexed_items = $this->indexItems($this->indexId);
-    $this->assertEqual($indexed_items, 5, 'Five items are indexed.');
-
-    // Create a facet, enable 'show numbers'.
-    $this->createFacet('Owl', 'owl');
-    $edit = ['widget' => 'links', 'widget_config[show_numbers]' => '1'];
-    $this->drupalPostForm('admin/config/search/facets/owl/edit', $edit, $this->t('Save'));
-
-    // Verify that the facet results are correct.
-    $this->drupalGet('search-api-test-fulltext');
-    $this->assertResponse(200);
-    $this->assertFacetLabel('item (3)');
-    $this->assertFacetLabel('article (2)');
-    $this->assertText('Displaying 5 search results');
-    $this->clickLinkPartialName('item');
-    $this->assertResponse(200);
-    $this->assertText('Displaying 3 search results');
+  public function testIntegerIndex() {
+    // Nothing to do here.
   }
 
   /**
-   * Tests creating a search server via the UI.
+   * {@inheritdoc}
    */
-  protected function createServer($server_id = '_test_server') {
-    $this->serverId = $server_id;
-    $server_name = 'Search API &{}<>! Server';
-    $server_description = 'A >server< used for testing &.';
-    $edit_path = 'admin/config/search/search-api/add-server';
-
-    $this->drupalGet($edit_path);
-    $this->assertResponse(200, 'Server add page exists');
-
-    $edit = [
-      'status' => 1,
-      'description' => 'A server used for testing.',
-      'backend' => $this->serverBackend,
-    ];
-
-    $this->drupalPostForm($edit_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Server name'))));
-
-    $edit += [
-      'name' => $server_name,
-    ];
-    $this->drupalPostForm($edit_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Machine-readable name'))));
-
-    $edit += [
-      'id' => $this->serverId,
-    ];
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertText($this->t('Please configure the selected backend.'));
+  protected function configureBackendAndSave(array $edit) {
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Please configure the selected backend.');
 
     $edit += [
       'backend_config[connector]' => 'standard',
     ];
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertText($this->t('Please configure the selected Solr connector.'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Please configure the selected Solr connector.');
 
     $edit += [
       'backend_config[connector_config][host]' => 'localhost',
@@ -186,14 +110,13 @@ class IntegrationTest extends WebTestBase {
       'backend_config[connector_config][path]' => '/',
       'backend_config[connector_config][core]' => '',
     ];
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
+    $this->submitForm($edit, 'Save');
 
-    $this->assertUrl('admin/config/search/search-api/server/' . $this->serverId);
-    $this->assertText($this->t('The server was successfully saved.'));
-    $this->assertHtmlEscaped($server_name);
-    $this->assertText($this->t('The Solr server could not be reached or is protected by your service provider.'));
+    $this->assertSession()->pageTextContains('The server was successfully saved.');
+    $this->assertSession()->addressEquals('admin/config/search/search-api/server/' . $this->serverId);
+    $this->assertSession()->pageTextContains('The Solr server could not be reached or is protected by your service provider.');
 
-    // Go back in and configure solr.
+    // Go back in and configure Solr.
     $edit_path = 'admin/config/search/search-api/server/' . $this->serverId . '/edit';
     $this->drupalGet($edit_path);
     $edit = [
@@ -202,300 +125,18 @@ class IntegrationTest extends WebTestBase {
       'backend_config[connector_config][path]' => '/solr',
       'backend_config[connector_config][core]' => 'd8',
     ];
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertText($this->t('The Solr server could be reached.'));
-
-    $this->drupalGet('admin/config/search/search-api');
-    $this->assertHtmlEscaped($server_name);
-  }
-
-  /**
-   * Tests creating a search index via the UI.
-   */
-  protected function createIndex() {
-    $settings_path = 'admin/config/search/search-api/add-index';
-    $this->indexId = 'test_index';
-    $index_description = 'An >index< used for &! tęsting.';
-    $index_name = 'Search >API< test &!^* index';
-
-    $this->drupalGet($settings_path);
-    $this->assertResponse(200);
-    $edit = [
-      'status' => 1,
-      'description' => $index_description,
-    ];
-
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Index name'))));
-    $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Machine-readable name'))));
-    $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Data sources'))));
-
-    $edit += [
-      'name' => $index_name,
-      'id' => $this->indexId,
-      'server' => $this->serverId,
-      'datasources[entity:node]' => TRUE,
-    ];
-
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertResponse(200);
-    $this->assertText($this->t('Please configure the used datasources.'));
-
-    $this->drupalPostForm(NULL, array(), $this->t('Save'));
-    $this->assertResponse(200);
-    $this->assertText($this->t('The index was successfully saved.'));
-    $this->assertHtmlEscaped($index_name);
-
-    $this->drupalGet($this->getIndexPath('edit'));
-    $this->assertHtmlEscaped($index_name);
-
-    $this->indexStorage->resetCache(array($this->indexId));
-    /** @var $index \Drupal\search_api\IndexInterface */
-    $index = $this->indexStorage->load($this->indexId);
-
-    $this->assertEqual($index->label(), $edit['name'], 'Name correctly inserted.');
-    $this->assertEqual($index->id(), $edit['id'], 'Index ID correctly inserted.');
-    $this->assertTrue($index->status(), 'Index status correctly inserted.');
-    $this->assertEqual($index->getDescription(), $edit['description'], 'Index ID correctly inserted.');
-    $this->assertEqual($index->getServerId(), $edit['server'], 'Index server ID correctly inserted.');
-    $this->assertEqual($index->getDatasourceIds(), ['entity:node'], 'Index datasource id correctly inserted.');
-  }
-
-  /**
-   * Tests whether the tracking information is properly maintained.
-   *
-   * Will especially test the bundle option of the content entity datasource.
-   */
-  protected function checkContentEntityTracking() {
-    // Initially there should be no tracked items, because there are no nodes.
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 0, 'No items are tracked yet.');
-
-    // Add two articles and a page.
-    $article1 = $this->drupalCreateNode(array('type' => 'article'));
-    $this->drupalCreateNode(array('type' => 'article'));
-    $this->drupalCreateNode(array('type' => 'page'));
-
-    // Those 3 new nodes should be added to the tracking table immediately.
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 3, 'Three items are tracked.');
-
-    $node_count = \Drupal::entityQuery('node')->count()->execute();
-    $this->assertEqual($node_count, $tracked_items);
-
-    // Test disabling the index.
-    $settings_path = $this->getIndexPath('edit');
-    $this->drupalGet($settings_path);
-    $edit = array(
-      'status' => FALSE,
-      'datasource_configs[entity:node][bundles][default]' => 0,
-      'datasource_configs[entity:node][bundles][selected][article]' => FALSE,
-      'datasource_configs[entity:node][bundles][selected][page]' => FALSE,
-    );
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 0, 'No items are tracked.');
-
-    // Test re-enabling the index.
-    $this->drupalGet($settings_path);
-
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 0,
-      'datasource_configs[entity:node][bundles][selected][article]' => TRUE,
-      'datasource_configs[entity:node][bundles][selected][page]' => TRUE,
-    );
-    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 3, 'Three items are tracked.');
-
-    // Uncheck "default" and don't select any bundles. This should remove all
-    // items from the tracking table.
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 0,
-      'datasource_configs[entity:node][bundles][selected][article]' => FALSE,
-      'datasource_configs[entity:node][bundles][selected][page]' => FALSE,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 0, 'No items are tracked.');
-
-    // Leave "default" unchecked and select the "article" bundle. This should
-    // re-add the two articles to the tracking table.
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 0,
-      'datasource_configs[entity:node][bundles][selected][article]' => TRUE,
-      'datasource_configs[entity:node][bundles][selected][page]' => FALSE,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 2, 'Two items are tracked.');
-
-    // Leave "default" unchecked and select only the "page" bundle. This should
-    // result in only the page being present in the tracking table.
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 0,
-      'datasource_configs[entity:node][bundles][selected][article]' => FALSE,
-      'datasource_configs[entity:node][bundles][selected][page]' => TRUE,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 1, 'One item is tracked.');
-
-    // Check "default" again and select the "article" bundle. This shouldn't
-    // change the tracking table, which should still only contain the page.
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 1,
-      'datasource_configs[entity:node][bundles][selected][article]' => TRUE,
-      'datasource_configs[entity:node][bundles][selected][page]' => FALSE,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 1, 'One item is tracked.');
-
-    // Leave "default" checked but now select only the "page" bundle. This
-    // should result in only the articles being tracked.
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 1,
-      'datasource_configs[entity:node][bundles][selected][article]' => FALSE,
-      'datasource_configs[entity:node][bundles][selected][page]' => TRUE,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-    $this->assertText($this->t('The index was successfully saved.'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 2, 'Two items are tracked.');
-
-    // Delete an article. That should remove it from the item table.
-    $article1->delete();
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 1, 'One item is tracked.');
-
-    // Go back to the default setting to continue the test.
-    $edit = array(
-      'status' => TRUE,
-      'datasource_configs[entity:node][bundles][default]' => 1,
-      'datasource_configs[entity:node][bundles][selected][article]' => FALSE,
-      'datasource_configs[entity:node][bundles][selected][page]' => FALSE,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-
-    $tracked_items = $this->countTrackedItems();
-    $this->assertEqual($tracked_items, 2, 'Two items are tracked.');
-    $node_count = \Drupal::entityQuery('node')->count()->execute();
-    $this->assertEqual($node_count, $tracked_items, 'All nodes are correctly tracked by the index.');
-  }
-
-  /**
-   * Counts the number of tracked items in the test index.
-   *
-   * @return int
-   *   The number of tracked items in the test index.
-   */
-  protected function countTrackedItems() {
-    return $this->getIndex()->getTrackerInstance()->getTotalItemsCount();
-  }
-
-  /**
-   * Counts the number of unindexed items in the test index.
-   *
-   * @return int
-   *   The number of unindexed items in the test index.
-   */
-  protected function countRemainingItems() {
-    return $this->getIndex()->getTrackerInstance()->getRemainingItemsCount();
-  }
-
-  /**
-   * Changes the index's server and checks if it reacts correctly.
-   *
-   * The expected behavior is that, when an index's server is changed, all of
-   * the index's items should be removed from the previous server and marked as
-   * "unindexed" in the tracker.
-   */
-  protected function changeIndexServer() {
-    $this->indexStorage->resetCache(array($this->indexId));
-    /** @var $index \Drupal\search_api\IndexInterface */
-    $index = $this->indexStorage->load($this->indexId);
-
-    $node_count = \Drupal::entityQuery('node')->count()->execute();
-    $this->assertEqual($node_count, $this->countTrackedItems(), 'All nodes are correctly tracked by the index.');
-
-    // Index all remaining items on the index.
-    $this->indexItems($this->indexId);
-
-    $remaining_items = $this->countRemainingItems();
-    $this->assertEqual($remaining_items, 0, 'All items have been successfully indexed.');
-
-    // Create a second search server.
-    $this->createServer('test_server_2');
-
-    // Change the index's server to the new one.
-    $settings_path = $this->getIndexPath('edit');
-    $edit = array(
-      'server' => $this->serverId,
-    );
-    $this->drupalPostForm($settings_path, $edit, $this->t('Save'));
-
-    // After saving the new index, we should have called reindex.
-    $remaining_items = $this->countRemainingItems();
-    $this->assertEqual($remaining_items, $node_count, 'All items still need to be indexed.');
-  }
-
-  /**
-   * Retrieves test index.
-   *
-   * @return \Drupal\search_api\IndexInterface
-   *   The test index.
-   */
-  protected function getIndex() {
-    return Index::load($this->indexId);
-  }
-
-  /**
-   * Ensures that all occurrences of the string are properly escaped.
-   *
-   * This makes sure that the string is only mentioned in an escaped version and
-   * is never double escaped.
-   *
-   * @param string $string
-   *   The raw string to check for.
-   */
-  protected function assertHtmlEscaped($string) {
-    $this->assertRaw(Html::escape($string));
-    $this->assertNoRaw(Html::escape(Html::escape($string)));
-    $this->assertNoRaw($string);
-  }
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('The Solr server could be reached.');
+ }
 
   /**
    * Indexes all (unindexed) items on the specified index.
    *
-   * @param string $index_id
-   *   The ID of the index on which items should be indexed.
-   *
    * @return int
    *   The number of successfully indexed items.
    */
-  protected function indexItems($index_id) {
-    $index_status = $this->doIndexItems($index_id);
+  protected function indexItems() {
+    $index_status = parent::indexItems();
     sleep(2);
     return $index_status;
   }
diff --git a/tests/src/Functional/ViewsTest.php b/tests/src/Functional/ViewsTest.php
index 23badeb..81594a1 100644
--- a/tests/src/Functional/ViewsTest.php
+++ b/tests/src/Functional/ViewsTest.php
@@ -1,17 +1,17 @@
 <?php
 
-namespace Drupal\search_api_solr\Tests;
+namespace Drupal\Tests\search_api_solr\Functional;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\search_api\Entity\Index;
-use Drupal\simpletest\WebTestBase as SimpletestWebTestBase;
+use Drupal\Tests\search_api\Functional\SearchApiBrowserTestBase;
 
 /**
  * Tests the Views integration of the Search API.
  *
  * @group search_api_solr
  */
-class ViewsTest extends \Drupal\search_api\Tests\ViewsTest {
+class ViewsTest extends \Drupal\Tests\search_api\Functional\ViewsTest {
 
   /**
    * Modules to enable for this test.
@@ -25,7 +25,7 @@ class ViewsTest extends \Drupal\search_api\Tests\ViewsTest {
    */
   public function setUp() {
     // Skip parent::setUp().
-    SimpletestWebTestBase::setUp();
+    SearchApiBrowserTestBase::setUp();
 
     // Add a second language.
     ConfigurableLanguage::createFromLangcode('nl')->save();
