Skip to content
Snippets Groups Projects
Verified Commit 46b718d4 authored by Lee Rowlands's avatar Lee Rowlands
Browse files

Issue #3348592 by alexpott, kunal_sahu, joseph.olstad, catch, larowlan,...

Issue #3348592 by alexpott, kunal_sahu, joseph.olstad, catch, larowlan, amaria, james.williams, longwave: [regression] Language switcher block throws exception when no route is matched

(cherry picked from commit fca42b9d)
parent 5638aefb
No related branches found
No related tags found
11 merge requests!8394[warning] array_flip(): Can only flip STRING and INTEGER values, when saving a non-revisionable custom content entity,!7780issue 3443822: fix for 'No route found for the specified format html. Supported formats: json, xml.',!5013Issue #3071143: Table Render Array Example Is Incorrect,!4848Issue #1566662: Update module should send notifications on Thursdays,!4792Issue #2230689: Remove redundant "Italic" style,!4220Issue #3368223: Link field > Access to internal links is not checked on display.,!3884Issue #3356842,!3812Draft: Issue #3339373 by alexpott, andypost, mondrake:...,!2205Quote all names in the regions section.,!1459Issue #3087632: menu_name max length is too long,!866Issue #2845319: The highlighting of the 'Home' menu-link does not respect query strings and fragment identifiers
......@@ -84,7 +84,11 @@ protected function blockAccess(AccountInterface $account) {
public function build() {
$build = [];
$type = $this->getDerivativeId();
$links = $this->languageManager->getLanguageSwitchLinks($type, Url::fromRouteMatch(\Drupal::routeMatch()));
$route_match = \Drupal::routeMatch();
// If there is no route match, for example when creating blocks on 404 pages
// for logged-in users with big_pipe enabled using the front page instead.
$url = $route_match->getRouteObject() ? Url::fromRouteMatch($route_match) : Url::fromRoute('<front>');
$links = $this->languageManager->getLanguageSwitchLinks($type, $url);
if (isset($links->links)) {
$build = [
......
......@@ -8,6 +8,8 @@
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\BrowserTestBase;
// cspell:ignore publi publié
/**
* Functional tests for the language switching feature.
*
......@@ -47,6 +49,7 @@ protected function setUp(): void {
'administer blocks',
'administer languages',
'access administration pages',
'access content',
]);
$this->drupalLogin($admin_user);
}
......@@ -79,6 +82,18 @@ public function testLanguageBlock() {
$this->doTestLanguageBlockAuthenticated($block->label());
$this->doTestLanguageBlockAnonymous($block->label());
$this->doTestLanguageBlock404($block->label(), 'system/404');
// Test 404s with big_pipe where the behaviour is different for logged-in
// users.
\Drupal::service('module_installer')->install(['big_pipe']);
$this->rebuildAll();
$this->doTestLanguageBlock404($block->label(), 'system/404');
$this->drupalLogin($this->drupalCreateUser());
// @todo This is testing the current behaviour with the big_pipe module
// enabled. This behaviour is a bug will be fixed in
// https://www.drupal.org/project/drupal/issues/3349201.
$this->doTestLanguageBlock404($block->label(), '<front>');
}
/**
......@@ -181,6 +196,52 @@ protected function doTestLanguageBlockAnonymous($block_label) {
$this->assertSame(['English', 'français'], $labels, 'The language links labels are in their own language on the language switcher block.');
}
/**
* Tests the language switcher block on 404 pages.
*
* @param string $block_label
* The label of the language switching block.
* @param string $system_path
* The expected system path for the links in the language switcher.
*
* @see self::testLanguageBlock()
*/
protected function doTestLanguageBlock404(string $block_label, string $system_path) {
$this->drupalGet('does-not-exist-' . $this->randomMachineName());
$this->assertSession()->pageTextContains($block_label);
// Assert that each list item and anchor element has the appropriate data-
// attributes.
$language_switchers = $this->xpath('//div[@id=:id]/ul/li', [':id' => 'block-test-language-block']);
$list_items = [];
$anchors = [];
$labels = [];
foreach ($language_switchers as $list_item) {
$list_items[] = [
'hreflang' => $list_item->getAttribute('hreflang'),
'data-drupal-link-system-path' => $list_item->getAttribute('data-drupal-link-system-path'),
];
$link = $list_item->find('xpath', 'a');
$anchors[] = [
'hreflang' => $link->getAttribute('hreflang'),
'data-drupal-link-system-path' => $link->getAttribute('data-drupal-link-system-path'),
];
$labels[] = $link->getText();
}
$expected_list_items = [
0 => ['hreflang' => 'en', 'data-drupal-link-system-path' => $system_path],
1 => ['hreflang' => 'fr', 'data-drupal-link-system-path' => $system_path],
];
$this->assertSame($expected_list_items, $list_items, 'The list items have the correct attributes that will allow the drupal.active-link library to mark them as active.');
$expected_anchors = [
0 => ['hreflang' => 'en', 'data-drupal-link-system-path' => $system_path],
1 => ['hreflang' => 'fr', 'data-drupal-link-system-path' => $system_path],
];
$this->assertSame($expected_anchors, $anchors, 'The anchors have the correct attributes that will allow the drupal.active-link library to mark them as active.');
$this->assertSame(['English', 'français'], $labels, 'The language links labels are in their own language on the language switcher block.');
}
/**
* Tests language switcher links for domain based negotiation.
*/
......@@ -439,6 +500,120 @@ public function testLanguageSessionSwitchLinks() {
$this->assertSession()->addressEquals('user/2');
}
/**
* Test that the language switching block does not expose restricted paths.
*/
public function testRestrictedPaths(): void {
\Drupal::service('module_installer')->install(['node']);
$entity_type_manager = \Drupal::entityTypeManager();
// Add the French language.
ConfigurableLanguage::createFromLangcode('fr')->save();
// Enable URL language detection and selection.
$this->config('language.types')
->set('negotiation.language_interface.enabled.language-url', 1)
->save();
// Enable the language switching block.
$block = $this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE);
// Create a node type and make it translatable.
$entity_type_manager->getStorage('node_type')
->create([
'type' => 'page',
'name' => 'Page',
])
->save();
// Create a published node with an unpublished translation.
$node = $entity_type_manager->getStorage('node')
->create([
'type' => 'page',
'title' => $this->randomMachineName(),
'status' => 1,
]);
$node->save();
$node->addTranslation('fr', ['title' => 'Non publié', 'status' => 0]);
$node->save();
// Create path aliases.
$alias_storage = $entity_type_manager->getStorage('path_alias');
$alias_storage->create([
'path' => '/user/1',
'alias' => '/secret-identity/peter-parker',
])->save();
$alias_storage->create([
'path' => '/node/1',
'langcode' => 'en',
'alias' => '/press-release/published-report',
])->save();
$alias_storage->create([
'path' => '/node/1',
'langcode' => 'fr',
'alias' => '/press-release/rapport-non-publié',
])->save();
// Visit a restricted user page.
// Assert that the language switching block is displayed on the
// access-denied page, but it does not contain the path alias.
$this->assertLinkMarkup('/user/1', 403, $block->label(), 'peter-parker');
// Visit the node and its translation. Use internal paths and aliases. The
// non-ASCII character may be escaped, so remove it from the search string.
$this->assertLinkMarkup('/node/1', 200, $block->label(), 'rapport-non-publi');
$this->assertLinkMarkup('/press-release/published-report', 200, $block->label(), 'rapport-non-publi');
$this->assertLinkMarkup('/fr/node/1', 403, $block->label(), 'rapport-non-publi');
$this->assertLinkMarkup('/fr/press-release/rapport-non-publié', 403, $block->label(), 'rapport-non-publi');
// Test as a user with access to other users and unpublished content.
$privileged_user = $this->drupalCreateUser([
'access user profiles',
'bypass node access',
]);
$this->drupalLogin($privileged_user);
$this->assertLinkMarkup('/user/1', 200, $block->label(), 'peter-parker', TRUE);
$this->assertLinkMarkup('/node/1', 200, $block->label(), 'rapport-non-publi', TRUE);
$this->assertLinkMarkup('/press-release/published-report', 200, $block->label(), 'rapport-non-publi', TRUE);
$this->assertLinkMarkup('/fr/node/1', 200, $block->label(), 'rapport-non-publi', TRUE);
$this->assertLinkMarkup('/fr/press-release/rapport-non-publié', 200, $block->label(), 'rapport-non-publi', TRUE);
// Test as an anonymous user.
$this->drupalLogout();
$this->assertLinkMarkup('/user/1', 403, $block->label(), 'peter-parker');
$this->assertLinkMarkup('/node/1', 200, $block->label(), 'rapport-non-publi');
$this->assertLinkMarkup('/press-release/published-report', 200, $block->label(), 'rapport-non-publi');
$this->assertLinkMarkup('/fr/node/1', 403, $block->label(), 'rapport-non-publi');
$this->assertLinkMarkup('/fr/press-release/rapport-non-publié', 403, $block->label(), 'rapport-non-publi');
}
/**
* Asserts that restricted text is or is not present in the page response.
*
* @param string $path
* The path to test.
* @param int $status
* The HTTP status code, such as 200 or 403.
* @param string $marker
* Text that should always be present.
* @param string $restricted
* Text that should be tested.
* @param bool $found
* (optional) If TRUE, then the restricted text is present. Defaults to
* FALSE.
*/
protected function assertLinkMarkup(string $path, int $status, string $marker, string $restricted, bool $found = FALSE): void {
$this->drupalGet($path);
$this->assertSession()->statusCodeEquals($status);
$this->assertSession()->pageTextContains($marker);
if ($found) {
$this->assertSession()->responseContains($restricted);
}
else {
$this->assertSession()->responseNotContains($restricted);
}
}
/**
* Saves the native name of a language entity in configuration as a label.
*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment