Initial Drupal 11 with DDEV setup
This commit is contained in:
		@ -0,0 +1,126 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
 | 
			
		||||
// cspell:ignore ȅchȏ foobarbaz meΦω
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests incoming path case insensitivity.
 | 
			
		||||
 *
 | 
			
		||||
 * @group routing
 | 
			
		||||
 */
 | 
			
		||||
class CaseInsensitivePathTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['system', 'views', 'node', 'system_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    \Drupal::state()->set('system_test.module_hidden', FALSE);
 | 
			
		||||
    $this->createContentType(['type' => 'page']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests mixed case paths.
 | 
			
		||||
   */
 | 
			
		||||
  public function testMixedCasePaths(): void {
 | 
			
		||||
    // Tests paths defined by routes from standard modules as anonymous.
 | 
			
		||||
    $this->drupalGet('user/login');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/Log in/');
 | 
			
		||||
    $this->drupalGet('User/Login');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/Log in/');
 | 
			
		||||
 | 
			
		||||
    // Tests paths defined by routes from the Views module.
 | 
			
		||||
    $admin = $this->drupalCreateUser([
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer nodes',
 | 
			
		||||
      'access content overview',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($admin);
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('admin/content');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/Content/');
 | 
			
		||||
    $this->drupalGet('Admin/Content');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/Content/');
 | 
			
		||||
 | 
			
		||||
    // Tests paths with query arguments.
 | 
			
		||||
 | 
			
		||||
    // Make sure our node title doesn't exist.
 | 
			
		||||
    $this->drupalGet('admin/content');
 | 
			
		||||
    $this->assertSession()->linkNotExists('FooBarBaz');
 | 
			
		||||
    $this->assertSession()->linkNotExists('foobarbaz');
 | 
			
		||||
 | 
			
		||||
    // Create a node, and make sure it shows up on admin/content.
 | 
			
		||||
    $node = $this->createNode([
 | 
			
		||||
      'title' => 'FooBarBaz',
 | 
			
		||||
      'type' => 'page',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('admin/content', [
 | 
			
		||||
      'query' => [
 | 
			
		||||
        'title' => 'FooBarBaz',
 | 
			
		||||
      ],
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    $this->assertSession()->linkExists('FooBarBaz');
 | 
			
		||||
    $this->assertSession()->linkByHrefExists($node->toUrl()->toString());
 | 
			
		||||
 | 
			
		||||
    // Make sure the path is case-insensitive, and query case is preserved.
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('Admin/Content', [
 | 
			
		||||
      'query' => [
 | 
			
		||||
        'title' => 'FooBarBaz',
 | 
			
		||||
      ],
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    $this->assertSession()->linkExists('FooBarBaz');
 | 
			
		||||
    $this->assertSession()->linkByHrefExists($node->toUrl()->toString());
 | 
			
		||||
    $this->assertSession()->fieldValueEquals('edit-title', 'FooBarBaz');
 | 
			
		||||
    // Check that we can access the node with a mixed case path.
 | 
			
		||||
    $this->drupalGet('NOdE/' . $node->id());
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/FooBarBaz/');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests paths with slugs.
 | 
			
		||||
   */
 | 
			
		||||
  public function testPathsWithArguments(): void {
 | 
			
		||||
    $this->drupalGet('system-test/echo/foobarbaz');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/foobarbaz/');
 | 
			
		||||
    $this->assertSession()->pageTextNotMatches('/FooBarBaz/');
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('system-test/echo/FooBarBaz');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/FooBarBaz/');
 | 
			
		||||
    $this->assertSession()->pageTextNotMatches('/foobarbaz/');
 | 
			
		||||
 | 
			
		||||
    // Test utf-8 characters in the route path.
 | 
			
		||||
    $this->drupalGet('/system-test/Ȅchȏ/meΦω/ABc123');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/ABc123/');
 | 
			
		||||
    $this->drupalGet('/system-test/ȅchȎ/MEΦΩ/ABc123');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
    $this->assertSession()->pageTextMatches('/ABc123/');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @group routing
 | 
			
		||||
 */
 | 
			
		||||
class DefaultFormatTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['system', 'default_format_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  public function testFoo(): void {
 | 
			
		||||
    $this->drupalGet('/default_format_test/human');
 | 
			
		||||
    $this->assertSame('format:html', $this->getSession()->getPage()->getContent());
 | 
			
		||||
    $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
 | 
			
		||||
    $this->drupalGet('/default_format_test/human');
 | 
			
		||||
    $this->assertSame('format:html', $this->getSession()->getPage()->getContent());
 | 
			
		||||
    $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('/default_format_test/machine');
 | 
			
		||||
    $this->assertSame('format:json', $this->getSession()->getPage()->getContent());
 | 
			
		||||
    $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
 | 
			
		||||
    $this->drupalGet('/default_format_test/machine');
 | 
			
		||||
    $this->assertSame('format:json', $this->getSession()->getPage()->getContent());
 | 
			
		||||
    $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function testMultipleRoutesWithSameSingleFormat(): void {
 | 
			
		||||
    $this->drupalGet('/default_format_test/machine');
 | 
			
		||||
    $this->assertSame('format:json', $this->getSession()->getPage()->getContent());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @group routing
 | 
			
		||||
 */
 | 
			
		||||
class LazyRouteProviderInstallTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['lazy_route_provider_install_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that the lazy route provider is used during a module install.
 | 
			
		||||
   */
 | 
			
		||||
  public function testInstallation(): void {
 | 
			
		||||
    $this->container->get('module_installer')->install(['router_test']);
 | 
			
		||||
    // Note that on DrupalCI the test site is installed in a sub directory so
 | 
			
		||||
    // we cannot use ::assertEquals().
 | 
			
		||||
    $this->assertStringEndsWith('/admin', \Drupal::state()->get('Drupal\lazy_route_provider_install_test\PluginManager'));
 | 
			
		||||
    $this->assertStringEndsWith('/router_test/test1', \Drupal::state()->get('router_test_install'));
 | 
			
		||||
    // If there is an exception thrown in rebuilding a route then the state
 | 
			
		||||
    // 'lazy_route_provider_install_test_menu_links_discovered_alter' will be
 | 
			
		||||
    // set.
 | 
			
		||||
    // @see lazy_route_provider_install_test_menu_links_discovered_alter().
 | 
			
		||||
    $this->assertEquals('success', \Drupal::state()->get('lazy_route_provider_install_test_menu_links_discovered_alter', NULL));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,63 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Url;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests URL generation and routing for route paths with encoded characters.
 | 
			
		||||
 *
 | 
			
		||||
 * @group path
 | 
			
		||||
 * @group routing
 | 
			
		||||
 */
 | 
			
		||||
class PathEncodedTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['system', 'path_encoded_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  public function testGetEncoded(): void {
 | 
			
		||||
    $route_paths = [
 | 
			
		||||
      'path_encoded_test.colon' => '/hi/llama:party',
 | 
			
		||||
      'path_encoded_test.at_sign' => '/blog/@Dries',
 | 
			
		||||
      'path_encoded_test.parentheses' => '/cat(box)',
 | 
			
		||||
    ];
 | 
			
		||||
    foreach ($route_paths as $route_name => $path) {
 | 
			
		||||
      $this->drupalGet(Url::fromRoute($route_name));
 | 
			
		||||
      $this->assertSession()->pageTextContains('PathEncodedTestController works');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function testAliasToEncoded(): void {
 | 
			
		||||
    $route_paths = [
 | 
			
		||||
      'path_encoded_test.colon' => '/hi/llama:party',
 | 
			
		||||
      'path_encoded_test.at_sign' => '/blog/@Dries',
 | 
			
		||||
      'path_encoded_test.parentheses' => '/cat(box)',
 | 
			
		||||
    ];
 | 
			
		||||
    $aliases = [];
 | 
			
		||||
    foreach ($route_paths as $route_name => $path) {
 | 
			
		||||
      $aliases[$route_name] = $this->randomMachineName();
 | 
			
		||||
      $this->createPathAlias($path, '/' . $aliases[$route_name]);
 | 
			
		||||
    }
 | 
			
		||||
    foreach ($route_paths as $route_name => $path) {
 | 
			
		||||
      // The alias may be only a suffix of the generated path when the test is
 | 
			
		||||
      // run with Drupal installed in a subdirectory.
 | 
			
		||||
      $this->assertMatchesRegularExpression('@/' . rawurlencode($aliases[$route_name]) . '$@', Url::fromRoute($route_name)->toString());
 | 
			
		||||
      $this->drupalGet(Url::fromRoute($route_name));
 | 
			
		||||
      $this->assertSession()->pageTextContains('PathEncodedTestController works');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,200 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\field\Entity\FieldConfig;
 | 
			
		||||
use Drupal\field\Entity\FieldStorageConfig;
 | 
			
		||||
use Drupal\language\Entity\ConfigurableLanguage;
 | 
			
		||||
use Drupal\link\LinkItemInterface;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\content_translation\Traits\ContentTranslationTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests that route lookup is cached by the current language.
 | 
			
		||||
 *
 | 
			
		||||
 * @group routing
 | 
			
		||||
 */
 | 
			
		||||
class RouteCachingLanguageTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use ContentTranslationTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'path',
 | 
			
		||||
    'node',
 | 
			
		||||
    'content_translation',
 | 
			
		||||
    'link',
 | 
			
		||||
    'block',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * A user with permissions to administer content types.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\user\UserInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $webUser;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->createContentType(['type' => 'page']);
 | 
			
		||||
 | 
			
		||||
    $this->drupalPlaceBlock('local_tasks_block');
 | 
			
		||||
    $this->drupalPlaceBlock('page_title_block');
 | 
			
		||||
 | 
			
		||||
    $permissions = [
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
      'administer content translation',
 | 
			
		||||
      'administer content types',
 | 
			
		||||
      'administer languages',
 | 
			
		||||
      'administer url aliases',
 | 
			
		||||
      'create content translations',
 | 
			
		||||
      'create page content',
 | 
			
		||||
      'create url aliases',
 | 
			
		||||
      'edit any page content',
 | 
			
		||||
      'translate any entity',
 | 
			
		||||
    ];
 | 
			
		||||
    // Create and log in user.
 | 
			
		||||
    $this->webUser = $this->drupalCreateUser($permissions);
 | 
			
		||||
    $this->drupalLogin($this->webUser);
 | 
			
		||||
 | 
			
		||||
    // Enable French language.
 | 
			
		||||
    static::createLanguageFromLangcode('fr');
 | 
			
		||||
 | 
			
		||||
    // Enable translation for page node.
 | 
			
		||||
    static::enableContentTranslation('node', 'page');
 | 
			
		||||
 | 
			
		||||
    // Create a field with settings to validate.
 | 
			
		||||
    $field_storage = FieldStorageConfig::create([
 | 
			
		||||
      'field_name' => 'field_link',
 | 
			
		||||
      'entity_type' => 'node',
 | 
			
		||||
      'type' => 'link',
 | 
			
		||||
    ]);
 | 
			
		||||
    $field_storage->save();
 | 
			
		||||
    $field = FieldConfig::create([
 | 
			
		||||
      'field_storage' => $field_storage,
 | 
			
		||||
      'bundle' => 'page',
 | 
			
		||||
      'settings' => [
 | 
			
		||||
        'title' => DRUPAL_OPTIONAL,
 | 
			
		||||
        'link_type' => LinkItemInterface::LINK_GENERIC,
 | 
			
		||||
      ],
 | 
			
		||||
    ]);
 | 
			
		||||
    $field->save();
 | 
			
		||||
 | 
			
		||||
    \Drupal::service('entity_display.repository')->getFormDisplay('node', 'page', 'default')
 | 
			
		||||
      ->setComponent('field_link', [
 | 
			
		||||
        'type' => 'link_default',
 | 
			
		||||
      ])
 | 
			
		||||
      ->save();
 | 
			
		||||
    \Drupal::service('entity_display.repository')->getViewDisplay('node', 'page', 'full')
 | 
			
		||||
      ->setComponent('field_link', [
 | 
			
		||||
        'type' => 'link',
 | 
			
		||||
      ])
 | 
			
		||||
      ->save();
 | 
			
		||||
 | 
			
		||||
    // Enable URL language detection and selection and set a prefix for both
 | 
			
		||||
    // languages.
 | 
			
		||||
    \Drupal::configFactory()->getEditable('language.types')
 | 
			
		||||
      ->set('negotiation.language_interface.enabled.language_url', 1)
 | 
			
		||||
      ->save();
 | 
			
		||||
    \Drupal::configFactory()->getEditable('language.negotiation')
 | 
			
		||||
      ->set('url.prefixes.en', 'en')
 | 
			
		||||
      ->save();
 | 
			
		||||
 | 
			
		||||
    // Reset the cache after changing the negotiation settings as that changes
 | 
			
		||||
    // how links are built.
 | 
			
		||||
    $this->resetAll();
 | 
			
		||||
 | 
			
		||||
    $definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'page');
 | 
			
		||||
    $this->assertTrue($definitions['path']->isTranslatable(), 'Node path is translatable.');
 | 
			
		||||
    $this->assertTrue($definitions['body']->isTranslatable(), 'Node body is translatable.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates content with a link field pointing to an alias of another language.
 | 
			
		||||
   *
 | 
			
		||||
   * @dataProvider providerLanguage
 | 
			
		||||
   */
 | 
			
		||||
  public function testLinkTranslationWithAlias($source_langcode): void {
 | 
			
		||||
    $source_url_options = [
 | 
			
		||||
      'language' => ConfigurableLanguage::load($source_langcode),
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // Create a target node in the source language that is the link target.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'langcode[0][value]' => $source_langcode,
 | 
			
		||||
      'title[0][value]' => 'Target page',
 | 
			
		||||
      'path[0][alias]' => '/target-page',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/add/page', $source_url_options);
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Confirm that the alias works.
 | 
			
		||||
    $assert_session = $this->assertSession();
 | 
			
		||||
    $assert_session->addressEquals($source_langcode . '/target-page');
 | 
			
		||||
    $assert_session->statusCodeEquals(200);
 | 
			
		||||
    $assert_session->pageTextContains('Target page');
 | 
			
		||||
 | 
			
		||||
    // Create a second node that links to the first through the link field.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'langcode[0][value]' => $source_langcode,
 | 
			
		||||
      'title[0][value]' => 'Link page',
 | 
			
		||||
      'field_link[0][uri]' => '/target-page',
 | 
			
		||||
      'field_link[0][title]' => 'Target page',
 | 
			
		||||
      'path[0][alias]' => '/link-page',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('node/add/page', $source_url_options);
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
 | 
			
		||||
    // Make sure the link node is displayed with a working link.
 | 
			
		||||
    $assert_session->pageTextContains('Link page');
 | 
			
		||||
    $this->clickLink('Target page');
 | 
			
		||||
    $assert_session->addressEquals($source_langcode . '/target-page');
 | 
			
		||||
    $assert_session->statusCodeEquals(200);
 | 
			
		||||
    $assert_session->pageTextContains('Target page');
 | 
			
		||||
 | 
			
		||||
    // Clear all caches, then add a translation for the link node.
 | 
			
		||||
    $this->resetAll();
 | 
			
		||||
 | 
			
		||||
    $this->drupalGet('link-page', $source_url_options);
 | 
			
		||||
    $this->clickLink('Translate');
 | 
			
		||||
    $this->clickLink('Add');
 | 
			
		||||
 | 
			
		||||
    // Do not change the link field.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'title[0][value]' => 'Translated link page',
 | 
			
		||||
      'path[0][alias]' => '/translated-link-page',
 | 
			
		||||
    ];
 | 
			
		||||
    $this->submitForm($edit, 'Save (this translation)');
 | 
			
		||||
 | 
			
		||||
    $assert_session->pageTextContains('Translated link page');
 | 
			
		||||
 | 
			
		||||
    // @todo Clicking on the link does not include the language prefix.
 | 
			
		||||
    $this->drupalGet('target-page', $source_url_options);
 | 
			
		||||
    $assert_session->statusCodeEquals(200);
 | 
			
		||||
    $assert_session->pageTextContains('Target page');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Data provider for testFromUri().
 | 
			
		||||
   */
 | 
			
		||||
  public static function providerLanguage() {
 | 
			
		||||
    return [
 | 
			
		||||
      ['en'],
 | 
			
		||||
      ['fr'],
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,111 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\language\Entity\ConfigurableLanguage;
 | 
			
		||||
use Drupal\Core\Language\LanguageInterface;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the route cache when the language is not in the path.
 | 
			
		||||
 *
 | 
			
		||||
 * @group language
 | 
			
		||||
 */
 | 
			
		||||
class RouteCachingNonPathLanguageNegotiationTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['language', 'block'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The admin user.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\user\UserInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $adminUser;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    // Create and log in user.
 | 
			
		||||
    $this->adminUser = $this->drupalCreateUser([
 | 
			
		||||
      'administer blocks',
 | 
			
		||||
      'administer languages',
 | 
			
		||||
      'access administration pages',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->drupalLogin($this->adminUser);
 | 
			
		||||
 | 
			
		||||
    // Add language.
 | 
			
		||||
    ConfigurableLanguage::createFromLangcode('fr')->save();
 | 
			
		||||
 | 
			
		||||
    // Enable session language detection and selection.
 | 
			
		||||
    $edit = [
 | 
			
		||||
      'language_interface[enabled][language-url]' => FALSE,
 | 
			
		||||
      'language_interface[enabled][language-session]' => TRUE,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->drupalGet('admin/config/regional/language/detection');
 | 
			
		||||
    $this->submitForm($edit, 'Save settings');
 | 
			
		||||
 | 
			
		||||
    // A more common scenario is domain-based negotiation but that can not be
 | 
			
		||||
    // tested. Session negotiation by default is not considered by the URL
 | 
			
		||||
    // language type that is used to resolve the alias. Explicitly enable
 | 
			
		||||
    // that to be able to test this scenario.
 | 
			
		||||
    // @todo Improve in https://www.drupal.org/project/drupal/issues/1125428.
 | 
			
		||||
    $this->config('language.types')
 | 
			
		||||
      ->set('negotiation.language_url.enabled', ['language-session' => 0])
 | 
			
		||||
      ->save();
 | 
			
		||||
 | 
			
		||||
    // Enable the language switching block.
 | 
			
		||||
    $this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, [
 | 
			
		||||
      'id' => 'test_language_block',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests aliases when the negotiated language is not in the path.
 | 
			
		||||
   */
 | 
			
		||||
  public function testAliases(): void {
 | 
			
		||||
    // Switch to French and try to access the now inaccessible block.
 | 
			
		||||
    $this->drupalGet('');
 | 
			
		||||
 | 
			
		||||
    // Create an alias for user/UID just for en, make sure that this is a 404
 | 
			
		||||
    // on the french page exist in english, no matter which language is
 | 
			
		||||
    // checked first. Create the alias after visiting frontpage to make sure
 | 
			
		||||
    // there is no existing cache entry for this that affects the tests.
 | 
			
		||||
    $this->createPathAlias('/user/' . $this->adminUser->id(), '/user-page', 'en');
 | 
			
		||||
 | 
			
		||||
    $this->clickLink('French');
 | 
			
		||||
    $this->drupalGet('user-page');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(404);
 | 
			
		||||
 | 
			
		||||
    // Switch to english, make sure it works now.
 | 
			
		||||
    $this->clickLink('English');
 | 
			
		||||
    $this->drupalGet('user-page');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
 | 
			
		||||
    // Clear cache and repeat the check, this time with english first.
 | 
			
		||||
    $this->resetAll();
 | 
			
		||||
    $this->drupalGet('user-page');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(200);
 | 
			
		||||
 | 
			
		||||
    $this->clickLink('French');
 | 
			
		||||
    $this->drupalGet('user-page');
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(404);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,67 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\FunctionalTests\Routing;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the route cache when the request's query parameters are altered.
 | 
			
		||||
 *
 | 
			
		||||
 * This happens either in the normal course of operations or due to an
 | 
			
		||||
 * exception.
 | 
			
		||||
 *
 | 
			
		||||
 * @group routing
 | 
			
		||||
 */
 | 
			
		||||
class RouteCachingQueryAlteredTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['router_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    // page_cache module is enabled in the testing profile, however by default
 | 
			
		||||
    // exceptions which create 4xx responses are cached for 1 hour. This is
 | 
			
		||||
    // undesirable for certain response types (e.g., 401) which vary on other
 | 
			
		||||
    // elements of the request than the URL. For this reason, do not cache 4xx
 | 
			
		||||
    // responses for the purposes of this test.
 | 
			
		||||
    $settings['settings']['cache_ttl_4xx'] = (object) [
 | 
			
		||||
      'value' => 0,
 | 
			
		||||
      'required' => TRUE,
 | 
			
		||||
    ];
 | 
			
		||||
    $this->writeSettings($settings);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests route collection cache after an exception.
 | 
			
		||||
   */
 | 
			
		||||
  public function testRouteCollectionCacheAfterException(): void {
 | 
			
		||||
    // Force an exception early in the Kernel middleware on a cold cache by
 | 
			
		||||
    // simulating bad Bearer authentication.
 | 
			
		||||
    $this->drupalGet('/router-test/rejects-query-strings', [], [
 | 
			
		||||
      'Authorization' => 'Bearer invalid',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(Response::HTTP_UNAUTHORIZED);
 | 
			
		||||
    // Check that the route collection cache does not recover any unexpected
 | 
			
		||||
    // query strings from the earlier request that involved an exception.
 | 
			
		||||
    // The requested controller returns 400 if there are any query parameters
 | 
			
		||||
    // present, similar to JSON:API paths that strictly filter requests.
 | 
			
		||||
    $this->drupalGet('/router-test/rejects-query-strings', [], [
 | 
			
		||||
      'Authorization' => 'Bearer valid',
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user