Unverified Commit 4babf62c authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3077785 by longwave: Refactor away DrupalMinkClient after Symfony 4.2+

parent d02bccbf
Loading
Loading
Loading
Loading
+0 −8
Changes for core/tests/Drupal/BuildTests/Framework/BuildTestBase.php: 0 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@
use Drupal\Component\FileSystem\FileSystem as DrupalFilesystem;
use Drupal\Tests\Traits\PHPUnit8Warnings;
use PHPUnit\Framework\TestCase;
use Symfony\Component\BrowserKit\Client as SymfonyClient;
use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Lock\Factory;
@@ -218,14 +217,7 @@ protected function getWorkingPath($working_dir = NULL) {
   * @return \Behat\Mink\Session
   */
  protected function initMink() {
    // If the Symfony BrowserKit client can followMetaRefresh(), we should use
    // the Goutte descendent instead of ours.
    if (method_exists(SymfonyClient::class, 'followMetaRefresh')) {
    $client = new Client();
    }
    else {
      $client = new DrupalMinkClient();
    }
    $client->followMetaRefresh(TRUE);
    $driver = new GoutteDriver($client);
    $session = new Session($driver);
+0 −74
Changes for core/tests/Drupal/BuildTests/Framework/DrupalMinkClient.php: 0 added lines, 74 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\BuildTests\Framework;

use Behat\Mink\Driver\Goutte\Client;
use Symfony\Component\BrowserKit\Client as SymfonyClient;

/**
 * Extend the Mink client for Drupal use-cases.
 *
 * This is adapted from https://github.com/symfony/symfony/pull/27118.
 *
 * @todo Update this client when Drupal starts using Symfony 4.2.0+.
 *       https://www.drupal.org/project/drupal/issues/3077785
 */
class DrupalMinkClient extends Client {

  /**
   * Whether to follow meta redirects or not.
   *
   * @var bool
   *
   * @see \Drupal\BuildTests\Framework\DrupalMinkClient::followMetaRefresh()
   */
  protected $followMetaRefresh;

  /**
   * Sets whether to automatically follow meta refresh redirects or not.
   *
   * @param bool $followMetaRefresh
   *   (optional) Whether to follow meta redirects. Defaults to TRUE.
   */
  public function followMetaRefresh(bool $followMetaRefresh = TRUE) {
    $this->followMetaRefresh = $followMetaRefresh;
  }

  /**
   * Glean the meta refresh URL from the current page content.
   *
   * @return string|null
   *   Either the redirect URL that was found, or NULL if none was found.
   */
  private function getMetaRefreshUrl() {
    $metaRefresh = $this->getCrawler()->filter('meta[http-equiv="Refresh"], meta[http-equiv="refresh"]');
    foreach ($metaRefresh->extract(['content']) as $content) {
      if (preg_match('/^\s*0\s*;\s*URL\s*=\s*(?|\'([^\']++)|"([^"]++)|([^\'"].*))/i', $content, $m)) {
        return str_replace("\t\r\n", '', rtrim($m[1]));
      }
    }
    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function request($method, $uri, array $parameters = [], array $files = [], array $server = [], $content = NULL, $changeHistory = TRUE) {
    $this->crawler = parent::request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
    // Check for meta refresh redirect and follow it.
    if ($this->followMetaRefresh && NULL !== $redirect = $this->getMetaRefreshUrl()) {
      $this->redirect = $redirect;
      // $this->redirects is private on the BrowserKit client, so we have to use
      // reflection to manage the redirects stack.
      $ref_redirects = new \ReflectionProperty(SymfonyClient::class, 'redirects');
      $ref_redirects->setAccessible(TRUE);
      $redirects = $ref_redirects->getValue($this);
      $redirects[serialize($this->history->current())] = TRUE;
      $ref_redirects->setValue($this, $redirects);

      $this->crawler = $this->followRedirect();
    }
    return $this->crawler;
  }

}
+0 −101
Changes for core/tests/Drupal/BuildTests/Framework/Tests/DrupalMinkClientTest.php: 0 added lines, 101 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\BuildTests\Framework\Tests;

use Drupal\BuildTests\Framework\DrupalMinkClient;
use PHPUnit\Framework\TestCase;
use Symfony\Component\BrowserKit\Response;

/**
 * Test \Drupal\BuildTests\Framework\DrupalMinkClient.
 *
 * This test is adapted from \Symfony\Component\BrowserKit\Tests\ClientTest.
 *
 * @coversDefaultClass \Drupal\BuildTests\Framework\DrupalMinkClient
 *
 * @group Build
 */
class DrupalMinkClientTest extends TestCase {

  /**
   * @dataProvider getTestsForMetaRefresh
   * @covers ::getMetaRefreshUrl
   */
  public function testFollowMetaRefresh(string $content, string $expectedEndingUrl, bool $followMetaRefresh = TRUE) {
    $client = new TestClient();
    $client->followMetaRefresh($followMetaRefresh);
    $client->setNextResponse(new Response($content));
    $client->request('GET', 'http://www.example.com/foo/foobar');
    $this->assertEquals($expectedEndingUrl, $client->getRequest()->getUri());
  }

  public function getTestsForMetaRefresh() {
    return [
      ['<html><head><meta http-equiv="Refresh" content="4" /><meta http-equiv="refresh" content="0; URL=http://www.example.com/redirected"/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><meta http-equiv="refresh" content="0;URL=http://www.example.com/redirected"/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><meta http-equiv="refresh" content="0;URL=\'http://www.example.com/redirected\'"/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><meta http-equiv="refresh" content=\'0;URL="http://www.example.com/redirected"\'/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><meta http-equiv="refresh" content="0; URL = http://www.example.com/redirected"/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><meta http-equiv="refresh" content="0;URL= http://www.example.com/redirected  "/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><meta http-equiv="refresh" content="0;url=http://www.example.com/redirected  "/></head></html>', 'http://www.example.com/redirected'],
      ['<html><head><noscript><meta http-equiv="refresh" content="0;URL=http://www.example.com/redirected"/></noscript></head></head></html>', 'http://www.example.com/redirected'],
      // Non-zero timeout should not result in a redirect.
      ['<html><head><meta http-equiv="refresh" content="4; URL=http://www.example.com/redirected"/></head></html>', 'http://www.example.com/foo/foobar'],
      ['<html><body></body></html>', 'http://www.example.com/foo/foobar'],
      // HTML 5 allows the meta tag to be placed in head or body.
      ['<html><body><meta http-equiv="refresh" content="0;url=http://www.example.com/redirected"/></body></html>', 'http://www.example.com/redirected'],
      // Valid meta refresh should not be followed if disabled.
      ['<html><head><meta http-equiv="refresh" content="0;URL=http://www.example.com/redirected"/></head></html>', 'http://www.example.com/foo/foobar', FALSE],
      'drupal-1' => ['<html><head><meta http-equiv="Refresh" content="0; URL=/update.php/start?id=2&op=do_nojs" /></body></html>', 'http://www.example.com/update.php/start?id=2&op=do_nojs'],
      'drupal-2' => ['<html><head><noscript><meta http-equiv="Refresh" content="0; URL=/update.php/start?id=2&op=do_nojs" /></noscript></body></html>', 'http://www.example.com/update.php/start?id=2&op=do_nojs'],
    ];
  }

  /**
   * @covers ::request
   */
  public function testBackForwardMetaRefresh() {
    $client = new TestClient();
    $client->followMetaRefresh();

    // First request.
    $client->request('GET', 'http://www.example.com/first-page');

    $content = '<html><head><meta http-equiv="Refresh" content="0; URL=/refreshed" /></body></html>';
    $client->setNextResponse(new Response($content, 200));
    $client->request('GET', 'http://www.example.com/refresh-from-here');

    $this->assertEquals('http://www.example.com/refreshed', $client->getRequest()->getUri());

    $client->back();
    $this->assertEquals('http://www.example.com/first-page', $client->getRequest()->getUri());

    $client->forward();
    $this->assertEquals('http://www.example.com/refreshed', $client->getRequest()->getUri());
  }

}

/**
 * Special client that can return a given response on the first doRequest().
 */
class TestClient extends DrupalMinkClient {

  protected $nextResponse = NULL;

  public function setNextResponse(Response $response) {
    $this->nextResponse = $response;
  }

  protected function doRequest($request) {
    if (NULL === $this->nextResponse) {
      return new Response();
    }

    $response = $this->nextResponse;
    $this->nextResponse = NULL;

    return $response;
  }

}