Initial Drupal 11 with DDEV setup
This commit is contained in:
26
web/core/modules/block/tests/fixtures/update/add-menu-block-with-zero-depth.php
vendored
Normal file
26
web/core/modules/block/tests/fixtures/update/add-menu-block-with-zero-depth.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Adds a menu block with a `depth` setting of 0.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
$data = $connection->select('config')
|
||||
->condition('name', 'block.block.olivero_account_menu')
|
||||
->fields('config', ['data'])
|
||||
->execute()
|
||||
->fetchField();
|
||||
$data = unserialize($data);
|
||||
// Change the depth setting to 0, which the update hook should change to NULL.
|
||||
// @see system_post_update_set_menu_block_depth_to_null_if_zero().
|
||||
$data['settings']['depth'] = 0;
|
||||
$connection->update('config')
|
||||
->condition('name', 'block.block.olivero_account_menu')
|
||||
->fields([
|
||||
'data' => serialize($data),
|
||||
])
|
||||
->execute();
|
||||
@ -0,0 +1,7 @@
|
||||
name: 'Block test'
|
||||
type: module
|
||||
description: 'Provides test blocks.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- drupal:block
|
||||
@ -0,0 +1,7 @@
|
||||
block_test.test_multiple_forms:
|
||||
path: '/test-multiple-forms'
|
||||
defaults:
|
||||
_controller: '\Drupal\block_test\Controller\TestMultipleFormController::testMultipleForms'
|
||||
_title: 'Multiple forms'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
@ -0,0 +1,6 @@
|
||||
services:
|
||||
block_test.multiple_static_context:
|
||||
class: Drupal\block_test\ContextProvider\MultipleStaticContext
|
||||
arguments: ['@current_user', '@entity_type.manager']
|
||||
tags:
|
||||
- { name: 'context_provider' }
|
||||
@ -0,0 +1,17 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- block_test
|
||||
theme:
|
||||
- stark
|
||||
id: test_block
|
||||
theme: stark
|
||||
region: '-1'
|
||||
weight: 0
|
||||
plugin: test_html
|
||||
settings:
|
||||
label: 'Test HTML block'
|
||||
label_display: hidden
|
||||
provider: block_test
|
||||
visibility: { }
|
||||
@ -0,0 +1,10 @@
|
||||
block.settings.test_block_instantiation:
|
||||
type: block_settings
|
||||
label: 'Test block instantiation settings'
|
||||
mapping:
|
||||
display_message:
|
||||
type: string
|
||||
label: 'Message text'
|
||||
|
||||
condition.plugin.baloney_spam:
|
||||
type: condition.plugin
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderCallbackInterface;
|
||||
|
||||
/**
|
||||
* Implements a trusted preRender callback.
|
||||
*/
|
||||
class BlockRenderAlterContent implements RenderCallbackInterface {
|
||||
|
||||
/**
|
||||
* Render API callback: Alters the content of a block.
|
||||
*
|
||||
* This function is assigned as a #pre_render callback.
|
||||
*/
|
||||
public static function preRender(array $build) {
|
||||
$build['#prefix'] = 'Hiya!<br>';
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\ContextProvider;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextProviderInterface;
|
||||
use Drupal\Core\Plugin\Context\EntityContext;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Sets multiple contexts for a static value.
|
||||
*/
|
||||
class MultipleStaticContext implements ContextProviderInterface {
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* Constructs a new MultipleStaticContext.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(AccountInterface $account, EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->account = $account;
|
||||
$this->userStorage = $entity_type_manager->getStorage('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRuntimeContexts(array $unqualified_context_ids) {
|
||||
$current_user = $this->userStorage->load($this->account->id());
|
||||
|
||||
$context1 = EntityContext::fromEntity($current_user, 'User A');
|
||||
$context2 = EntityContext::fromEntity($current_user, 'User B');
|
||||
|
||||
$cacheability = new CacheableMetadata();
|
||||
$cacheability->setCacheContexts(['user']);
|
||||
|
||||
$context1->addCacheableDependency($cacheability);
|
||||
$context2->addCacheableDependency($cacheability);
|
||||
|
||||
return [
|
||||
'userA' => $context1,
|
||||
'userB' => $context2,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAvailableContexts() {
|
||||
return $this->getRuntimeContexts([]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Form\FormState;
|
||||
|
||||
/**
|
||||
* Controller for block_test module.
|
||||
*/
|
||||
class TestMultipleFormController extends ControllerBase {
|
||||
|
||||
public function testMultipleForms() {
|
||||
$form_state = new FormState();
|
||||
$build = [
|
||||
'form1' => $this->formBuilder()->buildForm('\Drupal\block_test\Form\TestForm', $form_state),
|
||||
'form2' => $this->formBuilder()->buildForm('\Drupal\block_test\Form\FavoriteAnimalTestForm', $form_state),
|
||||
];
|
||||
|
||||
// Output all attached placeholders trough
|
||||
// \Drupal\Core\Messenger\MessengerInterface::addMessage(), so we can
|
||||
// see if there's only one in the tests.
|
||||
$post_render_callable = function ($elements) {
|
||||
$matches = [];
|
||||
preg_match_all('<form\s(.*?)action="(.*?)"(.*)>', (string) $elements, $matches);
|
||||
|
||||
$action_values = $matches[2];
|
||||
|
||||
foreach ($action_values as $action_value) {
|
||||
$this->messenger()->addStatus('Form action: ' . $action_value);
|
||||
}
|
||||
return $elements;
|
||||
};
|
||||
|
||||
$build['#post_render'] = [$post_render_callable];
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form that performs favorite animal test.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FavoriteAnimalTestForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'block_test_form_favorite_animal_test';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['favorite_animal'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Your favorite animal.'),
|
||||
];
|
||||
|
||||
$form['submit_animal'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Submit your chosen animal'),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->messenger()->addStatus($this->t('Your favorite animal is: @favorite_animal', ['@favorite_animal' => $form['favorite_animal']['#value']]));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form that performs base block form test.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TestForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'block_test_form_test';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['email'] = [
|
||||
'#type' => 'email',
|
||||
'#title' => $this->t('Your .com email address.'),
|
||||
];
|
||||
|
||||
$form['show'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Submit'),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
if (!str_contains($form_state->getValue('email'), '.com')) {
|
||||
$form_state->setErrorByName('email', $this->t('This is not a .com email address.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->messenger()->addStatus($this->t('Your email address is @email', ['@email' => $form['email']['#value']]));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Hook;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\Core\Hook\Attribute\Hook;
|
||||
|
||||
/**
|
||||
* Hook implementations for block_test.
|
||||
*/
|
||||
class BlockTestHooks {
|
||||
|
||||
/**
|
||||
* Implements hook_block_alter().
|
||||
*/
|
||||
#[Hook('block_alter')]
|
||||
public function blockAlter(&$block_info): void {
|
||||
if (\Drupal::state()->get('block_test_info_alter') && isset($block_info['test_block_instantiation'])) {
|
||||
$block_info['test_block_instantiation']['category'] = 'Custom category';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view_BASE_BLOCK_ID_alter().
|
||||
*/
|
||||
#[Hook('block_view_test_cache_alter')]
|
||||
public function blockViewTestCacheAlter(array &$build, BlockPluginInterface $block): void {
|
||||
if (\Drupal::state()->get('block_test_view_alter_suffix') !== NULL) {
|
||||
$build['#attributes']['foo'] = 'bar';
|
||||
}
|
||||
if (\Drupal::state()->get('block_test_view_alter_append_pre_render_prefix') !== NULL) {
|
||||
$build['#pre_render'][] = '\Drupal\block_test\BlockRenderAlterContent::preRender';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view_BASE_BLOCK_ID_alter().
|
||||
*
|
||||
* @see \Drupal\Tests\block\Kernel\BlockViewBuilderTest::testBlockViewBuilderCacheTitleBlock()
|
||||
*/
|
||||
#[Hook('block_view_page_title_block_alter')]
|
||||
public function blockViewPageTitleBlockAlter(array &$build, BlockPluginInterface $block): void {
|
||||
$build['#cache']['tags'][] = 'custom_cache_tag';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_build_BASE_BLOCK_ID_alter().
|
||||
*/
|
||||
#[Hook('block_build_test_cache_alter')]
|
||||
public function blockBuildTestCacheAlter(array &$build, BlockPluginInterface $block): void {
|
||||
// Test altering cache keys, contexts, tags and max-age.
|
||||
if (\Drupal::state()->get('block_test_block_alter_cache_key') !== NULL) {
|
||||
$build['#cache']['keys'][] = \Drupal::state()->get('block_test_block_alter_cache_key');
|
||||
}
|
||||
if (\Drupal::state()->get('block_test_block_alter_cache_context') !== NULL) {
|
||||
$build['#cache']['contexts'][] = \Drupal::state()->get('block_test_block_alter_cache_context');
|
||||
}
|
||||
if (\Drupal::state()->get('block_test_block_alter_cache_tag') !== NULL) {
|
||||
$build['#cache']['tags'] = Cache::mergeTags($build['#cache']['tags'], [\Drupal::state()->get('block_test_block_alter_cache_tag')]);
|
||||
}
|
||||
if (\Drupal::state()->get('block_test_block_alter_cache_max_age') !== NULL) {
|
||||
$build['#cache']['max-age'] = \Drupal::state()->get('block_test_block_alter_cache_max_age');
|
||||
}
|
||||
// Test setting #create_placeholder.
|
||||
if (\Drupal::state()->get('block_test_block_alter_create_placeholder') !== NULL) {
|
||||
$build['#create_placeholder'] = \Drupal::state()->get('block_test_block_alter_create_placeholder');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a block to test access.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_access",
|
||||
admin_label: new TranslatableMarkup("Test block access"),
|
||||
)]
|
||||
class TestAccessBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* Tests the test access block.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The plugin configuration, i.e. an array with configuration values keyed
|
||||
* by configuration option name. The special key 'context' may be used to
|
||||
* initialize the defined contexts by setting it to an array of context
|
||||
* values keyed by context names.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $keyValue
|
||||
* The key value store.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, protected KeyValueStoreInterface $keyValue) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('keyvalue')->get('block_test')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
return $this->keyValue->get('access', FALSE) ? AccessResult::allowed()->setCacheMaxAge(0) : AccessResult::forbidden()->setCacheMaxAge(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return ['#markup' => 'Hello test world'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a basic block for testing block instantiation and configuration.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_block_instantiation",
|
||||
admin_label: new TranslatableMarkup("Display message")
|
||||
)]
|
||||
class TestBlockInstantiation extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'display_message' => 'no message set',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
return AccessResult::allowedIfHasPermission($account, 'access content');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
$form['display_message'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Display message'),
|
||||
'#default_value' => $this->configuration['display_message'],
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
$this->configuration['display_message'] = $form_state->getValue('display_message');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [
|
||||
'#children' => $this->configuration['display_message'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a block to test caching.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_cache",
|
||||
admin_label: new TranslatableMarkup("Test block caching")
|
||||
)]
|
||||
class TestCacheBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$content = \Drupal::keyValue('block_test')->get('content');
|
||||
|
||||
$build = [];
|
||||
if (!empty($content)) {
|
||||
$build['#markup'] = $content;
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return \Drupal::state()->get('block_test.cache_contexts', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return \Drupal::state()->get('block_test.cache_max_age', parent::getCacheMaxAge());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Plugin\Context\EntityContextDefinition;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Provides a context-aware block.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_context_aware",
|
||||
admin_label: new TranslatableMarkup("Test context-aware block"),
|
||||
context_definitions: [
|
||||
'user' => new EntityContextDefinition(
|
||||
data_type: 'entity:user',
|
||||
label: new TranslatableMarkup("User Context"),
|
||||
required: FALSE,
|
||||
constraints: [
|
||||
"NotNull" => [],
|
||||
]
|
||||
),
|
||||
]
|
||||
)]
|
||||
class TestContextAwareBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->getContextValue('user');
|
||||
return [
|
||||
'#prefix' => '<div id="' . $this->getPluginId() . '--username">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => $user ? $user->getAccountName() : 'No context mapping selected.',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
if ($this->getContextValue('user') instanceof UserInterface) {
|
||||
$this->messenger()->addStatus('User context found.');
|
||||
}
|
||||
|
||||
return parent::blockAccess($account);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a context-aware block that uses a not-passed, non-required context.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_context_aware_no_valid_context_options",
|
||||
admin_label: new TranslatableMarkup("Test context-aware block - no valid context options"),
|
||||
context_definitions: [
|
||||
'user' => new ContextDefinition(data_type: 'email', required: FALSE),
|
||||
]
|
||||
)]
|
||||
class TestContextAwareNoValidContextOptionsBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [
|
||||
'#markup' => 'Rendered block with no valid context options',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Plugin\Context\EntityContextDefinition;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a context-aware block.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_context_aware_unsatisfied",
|
||||
admin_label: new TranslatableMarkup("Test context-aware unsatisfied block"),
|
||||
context_definitions: [
|
||||
'user' => new EntityContextDefinition('entity:foobar'),
|
||||
]
|
||||
)]
|
||||
class TestContextAwareUnsatisfiedBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [
|
||||
'#markup' => 'test',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a block that returns an empty array.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_empty",
|
||||
admin_label: new TranslatableMarkup("Test Empty block"),
|
||||
)]
|
||||
class TestEmptyBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a block to test caching.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_form_in_block",
|
||||
admin_label: new TranslatableMarkup("Test form block caching"),
|
||||
)]
|
||||
class TestFormBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return \Drupal::formBuilder()->getForm('Drupal\block_test\Form\TestForm');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a block to test HTML.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_html",
|
||||
admin_label: new TranslatableMarkup("Test HTML block"),
|
||||
)]
|
||||
class TestHtmlBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [
|
||||
'#attributes' => \Drupal::keyvalue('block_test')->get('attributes'),
|
||||
'#children' => \Drupal::keyValue('block_test')->get('content'),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\block_test\PluginForm\EmptyBlockForm;
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a block with multiple forms.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_multiple_forms_block",
|
||||
forms: [
|
||||
'secondary' => EmptyBlockForm::class,
|
||||
],
|
||||
admin_label: new TranslatableMarkup("Multiple forms test block"),
|
||||
)]
|
||||
class TestMultipleFormsBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\Attribute\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a test settings validation block.
|
||||
*/
|
||||
#[Block(
|
||||
id: "test_settings_validation",
|
||||
admin_label: new TranslatableMarkup("Test settings validation block"),
|
||||
)]
|
||||
class TestSettingsValidationBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
return ['digits' => ['#type' => 'textfield']] + $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockValidate($form, FormStateInterface $form_state) {
|
||||
if (!ctype_digit($form_state->getValue('digits'))) {
|
||||
$form_state->setErrorByName('digits', $this->t('Only digits are allowed'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return ['#markup' => 'foo'];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\Attribute\Condition;
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a 'baloney_spam' condition.
|
||||
*/
|
||||
#[Condition(
|
||||
id: "baloney_spam",
|
||||
label: new TranslatableMarkup("Baloney spam"),
|
||||
)]
|
||||
class BaloneySpam extends ConditionPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
return 'Summary';
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\Attribute\Condition;
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a 'missing_schema' condition.
|
||||
*/
|
||||
#[Condition(
|
||||
id: "missing_schema",
|
||||
label: new TranslatableMarkup("Missing schema"),
|
||||
)]
|
||||
class MissingSchema extends ConditionPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
return 'Summary';
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\block_test\PluginForm;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\PluginFormBase;
|
||||
|
||||
/**
|
||||
* Provides a form for a block that is empty.
|
||||
*/
|
||||
class EmptyBlockForm extends PluginFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $plugin;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
// Intentionally empty.
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
name: '<"Cat" & ''Mouse''>'
|
||||
type: theme
|
||||
base theme: stable9
|
||||
description: 'Theme for testing special characters in block admin.'
|
||||
regions:
|
||||
content: Content
|
||||
help: Help
|
||||
@ -0,0 +1,16 @@
|
||||
name: 'Block test theme'
|
||||
type: theme
|
||||
base theme: stable9
|
||||
description: 'Theme for testing the block system'
|
||||
version: VERSION
|
||||
regions:
|
||||
sidebar_first: 'Left sidebar'
|
||||
sidebar_second: 'Right sidebar'
|
||||
content: Content
|
||||
header: Header
|
||||
footer: Footer
|
||||
highlighted: Highlighted
|
||||
help: Help
|
||||
regions_hidden:
|
||||
- sidebar_first
|
||||
- sidebar_second
|
||||
@ -0,0 +1,8 @@
|
||||
name: 'Block test views'
|
||||
type: module
|
||||
description: 'Provides a view and block to test block displays in views.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- drupal:block
|
||||
- drupal:views
|
||||
@ -0,0 +1,56 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: test_view_block
|
||||
label: test_view_block
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: views_test_data
|
||||
base_field: id
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Default
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: views_test_data
|
||||
field: name
|
||||
title: test_view_block
|
||||
footer:
|
||||
area_text_custom:
|
||||
id: area_text_custom
|
||||
table: views
|
||||
field: area_text_custom
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: text_custom
|
||||
empty: false
|
||||
content: '[view:title]'
|
||||
tokenize: false
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: Block
|
||||
position: null
|
||||
@ -0,0 +1,56 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_view_block2
|
||||
label: test_view_block2
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: views_test_data
|
||||
base_field: id
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Default
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: views_test_data
|
||||
field: name
|
||||
title: test_view_block2
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: Block
|
||||
position: null
|
||||
block_2:
|
||||
display_plugin: block
|
||||
id: block_2
|
||||
display_title: Block
|
||||
position: null
|
||||
block_3:
|
||||
display_plugin: block
|
||||
id: block_3
|
||||
display_title: Block
|
||||
position: null
|
||||
@ -0,0 +1,426 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_view_block_with_context
|
||||
label: test_view_block_with_context
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Default
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: true
|
||||
text: 'Test view row: {{ title }}'
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
settings:
|
||||
link_to_entity: true
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
plugin_id: field
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
entity_type: node
|
||||
entity_field: created
|
||||
plugin_id: date
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
title: test_view_block_with_context
|
||||
header: { }
|
||||
footer: { }
|
||||
empty:
|
||||
area_text_custom:
|
||||
id: area_text_custom
|
||||
table: views
|
||||
field: area_text_custom
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: true
|
||||
tokenize: false
|
||||
content: 'Test view: No results found.'
|
||||
plugin_id: text_custom
|
||||
relationships: { }
|
||||
arguments:
|
||||
'null':
|
||||
id: 'null'
|
||||
table: views
|
||||
field: 'null'
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: default
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: foo
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
must_not_be: false
|
||||
plugin_id: 'null'
|
||||
null_1:
|
||||
id: null_1
|
||||
table: views
|
||||
field: 'null'
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: ignore
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
must_not_be: false
|
||||
plugin_id: 'null'
|
||||
nid:
|
||||
id: nid
|
||||
table: node_field_data
|
||||
field: nid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: empty
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: 'entity:node'
|
||||
fail: 'not found'
|
||||
validate_options:
|
||||
operation: view
|
||||
multiple: 0
|
||||
bundles: { }
|
||||
access: false
|
||||
break_phrase: false
|
||||
not: false
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
plugin_id: node_nid
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
cacheable: false
|
||||
max-age: -1
|
||||
tags: { }
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: Block
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
cacheable: false
|
||||
max-age: -1
|
||||
tags: { }
|
||||
block_2:
|
||||
display_plugin: block
|
||||
id: block_2
|
||||
display_title: 'Block 2'
|
||||
position: 2
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
arguments:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: ignore
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: true
|
||||
validate:
|
||||
type: numeric
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
entity_type: node
|
||||
entity_field: created
|
||||
plugin_id: date
|
||||
vid:
|
||||
id: vid
|
||||
table: node_field_data
|
||||
field: vid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: ignore
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
break_phrase: false
|
||||
not: false
|
||||
entity_type: node
|
||||
entity_field: vid
|
||||
plugin_id: numeric
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: ignore
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
glossary: false
|
||||
limit: 0
|
||||
case: none
|
||||
path_case: none
|
||||
transform_dash: false
|
||||
break_phrase: false
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
plugin_id: string
|
||||
defaults:
|
||||
arguments: false
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Provides test assertions for testing block appearance.
|
||||
*
|
||||
* Can be used by test classes that extend \Drupal\Tests\BrowserTestBase.
|
||||
*/
|
||||
trait AssertBlockAppearsTrait {
|
||||
|
||||
/**
|
||||
* Checks to see whether a block appears on the page.
|
||||
*
|
||||
* @param \Drupal\block\Entity\Block $block
|
||||
* The block entity to find on the page.
|
||||
*/
|
||||
protected function assertBlockAppears(Block $block) {
|
||||
$this->assertSession()->elementExists('xpath', "//div[@id = 'block-{$block->id()}']");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see whether a block does not appears on the page.
|
||||
*
|
||||
* @param \Drupal\block\Entity\Block $block
|
||||
* The block entity to find on the page.
|
||||
*/
|
||||
protected function assertNoBlockAppears(Block $block) {
|
||||
$this->assertSession()->elementNotExists('xpath', "//div[@id = 'block-{$block->id()}']");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the block system with admin themes.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockAdminThemeTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'contextual'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Check for the accessibility of the admin theme on the block admin page.
|
||||
*/
|
||||
public function testAdminTheme(): void {
|
||||
// Create administrative user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer themes',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Ensure that access to block admin page is denied when theme is not
|
||||
// installed.
|
||||
$this->drupalGet('admin/structure/block/list/olivero');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Install admin theme and confirm that tab is accessible.
|
||||
\Drupal::service('theme_installer')->install(['olivero']);
|
||||
$edit['admin_theme'] = 'olivero';
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
$this->drupalGet('admin/structure/block/list/olivero');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure contextual links are disabled in Claro theme.
|
||||
*/
|
||||
public function testClaroAdminTheme(): void {
|
||||
// Create administrative user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'administer themes',
|
||||
'access contextual links',
|
||||
'view the administration theme',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Install admin theme and confirm that tab is accessible.
|
||||
\Drupal::service('theme_installer')->install(['claro']);
|
||||
$edit['admin_theme'] = 'claro';
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
|
||||
// Define our block settings.
|
||||
$settings = [
|
||||
'theme' => 'claro',
|
||||
'region' => 'header',
|
||||
];
|
||||
|
||||
// Place a block.
|
||||
$block = $this->drupalPlaceBlock('local_tasks_block', $settings);
|
||||
|
||||
// Open admin page.
|
||||
$this->drupalGet('admin');
|
||||
|
||||
// Check if contextual link classes are unavailable.
|
||||
$this->assertSession()->responseNotContains('<div data-contextual-id="block:block=' . $block->id() . ':langcode=en"></div>');
|
||||
$this->assertSession()->responseNotContains('contextual-region');
|
||||
}
|
||||
|
||||
}
|
||||
240
web/core/modules/block/tests/src/Functional/BlockCacheTest.php
Normal file
240
web/core/modules/block/tests/src/Functional/BlockCacheTest.php
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests block caching.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockCacheTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test', 'test_page_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* A user with permission to administer blocks.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* An authenticated user to test block caching.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $normalUser;
|
||||
|
||||
/**
|
||||
* Another authenticated user to test block caching.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $normalUserAlt;
|
||||
|
||||
/**
|
||||
* The block used by this test.
|
||||
*
|
||||
* @var \Drupal\block\BlockInterface
|
||||
*/
|
||||
protected $block;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create an admin user, log in and enable test blocks.
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Create additional users to test caching modes.
|
||||
$this->normalUser = $this->drupalCreateUser();
|
||||
$this->normalUserAlt = $this->drupalCreateUser();
|
||||
// Sync the roles, since drupalCreateUser() creates separate roles for
|
||||
// the same permission sets.
|
||||
$this->normalUserAlt->roles = $this->normalUser->getRoles();
|
||||
$this->normalUserAlt->save();
|
||||
|
||||
// Enable our test block.
|
||||
$this->block = $this->drupalPlaceBlock('test_cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests "user.roles" cache context.
|
||||
*/
|
||||
public function testCachePerRole(): void {
|
||||
\Drupal::state()->set('block_test.cache_contexts', ['user.roles']);
|
||||
|
||||
// Enable our test block. Set some content for it to display.
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
$this->drupalLogin($this->normalUser);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
// Change the content, but the cached copy should still be served.
|
||||
$old_content = $current_content;
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
|
||||
// Clear the cache and verify that the stale data is no longer there.
|
||||
Cache::invalidateTags(['block_view']);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextNotContains($old_content);
|
||||
// Fresh block content is displayed after clearing the cache.
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
// Test whether the cached data is served for the correct users.
|
||||
$old_content = $current_content;
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('');
|
||||
// Anonymous user does not see content cached per-role for normal user.
|
||||
$this->assertSession()->pageTextNotContains($old_content);
|
||||
|
||||
// User with the same roles sees per-role cached content.
|
||||
$this->drupalLogin($this->normalUserAlt);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
|
||||
// Admin user does not see content cached per-role for normal user.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextNotContains($old_content);
|
||||
|
||||
// Block is served from the per-role cache.
|
||||
$this->drupalLogin($this->normalUser);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a cacheable block without any additional cache context.
|
||||
*/
|
||||
public function testCachePermissions(): void {
|
||||
// user.permissions is a required context, so a user with different
|
||||
// permissions will see a different version of the block.
|
||||
\Drupal::state()->set('block_test.cache_contexts', []);
|
||||
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
$old_content = $current_content;
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
|
||||
// Block content served from cache.
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
|
||||
// Block content not served from cache.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests non-cacheable block.
|
||||
*/
|
||||
public function testNoCache(): void {
|
||||
\Drupal::state()->set('block_test.cache_max_age', 0);
|
||||
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
|
||||
// If max_age = 0 has no effect, the next request would be cached.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
// A cached copy should not be served.
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
$this->drupalGet('');
|
||||
// Maximum age of zero prevents blocks from being cached.
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests "user" cache context.
|
||||
*/
|
||||
public function testCachePerUser(): void {
|
||||
\Drupal::state()->set('block_test.cache_contexts', ['user']);
|
||||
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
$this->drupalLogin($this->normalUser);
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
$old_content = $current_content;
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
|
||||
// Block is served from per-user cache.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
|
||||
// Per-user block cache is not served for other users.
|
||||
$this->drupalLogin($this->normalUserAlt);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
// Per-user block cache is persistent.
|
||||
$this->drupalLogin($this->normalUser);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests "url" cache context.
|
||||
*/
|
||||
public function testCachePerPage(): void {
|
||||
\Drupal::state()->set('block_test.cache_contexts', ['url']);
|
||||
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertSession()->pageTextContains($current_content);
|
||||
|
||||
$old_content = $current_content;
|
||||
$current_content = $this->randomMachineName();
|
||||
\Drupal::keyValue('block_test')->set('content', $current_content);
|
||||
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Verify that block content cached for the test page does not show up
|
||||
// for the user page.
|
||||
$this->assertSession()->pageTextNotContains($old_content);
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Verify that the block content is cached for the test page.
|
||||
$this->assertSession()->pageTextContains($old_content);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the block demo page with admin themes.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockDemoTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Check for the accessibility of the admin block demo page.
|
||||
*/
|
||||
public function testBlockDemo(): void {
|
||||
// Create administrative user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer themes',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Confirm we have access to the block demo page for the default theme.
|
||||
$config = $this->container->get('config.factory')->get('system.theme');
|
||||
$default_theme = $config->get('default');
|
||||
$this->drupalGet('admin/structure/block/demo/' . $default_theme);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->linkByHrefExists('admin/structure/block');
|
||||
$this->assertSession()->linkByHrefNotExists('admin/structure/block/list/' . $default_theme);
|
||||
|
||||
// All available themes in core.
|
||||
$available_themes = [
|
||||
'olivero',
|
||||
'claro',
|
||||
'stark',
|
||||
];
|
||||
|
||||
// All available themes minute minus the default theme.
|
||||
$themes = array_diff($available_themes, [$default_theme]);
|
||||
|
||||
foreach ($themes as $theme) {
|
||||
// Install theme.
|
||||
$this->container->get('theme_installer')->install([$theme]);
|
||||
// Confirm access to the block demo page for the theme.
|
||||
$this->drupalGet('admin/structure/block/demo/' . $theme);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Confirm existence of link for "Exit block region demonstration".
|
||||
$this->assertSession()->linkByHrefExists('admin/structure/block/list/' . $theme);
|
||||
}
|
||||
|
||||
// Confirm access to the block demo page is denied for an invalid theme.
|
||||
$this->drupalGet('admin/structure/block/demo/invalid_theme');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests form in block caching.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockFormInBlockTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test', 'test_page_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Enable our test block.
|
||||
$this->drupalPlaceBlock('test_form_in_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if form in block's redirect isn't cached.
|
||||
*/
|
||||
public function testCachePerPage(): void {
|
||||
$form_values = ['email' => 'test@example.com'];
|
||||
|
||||
// Go to "test-page" and test if the block is enabled.
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Your .com email address.');
|
||||
|
||||
// Make sure that we're currently still on /test-page after submitting the
|
||||
// form.
|
||||
$this->submitForm($form_values, 'Submit');
|
||||
$this->assertSession()->addressEquals('test-page');
|
||||
$this->assertSession()->pageTextContains('Your email address is test@example.com');
|
||||
|
||||
// Go to a different page and see if the block is enabled there as well.
|
||||
$this->drupalGet('test-render-title');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Your .com email address.');
|
||||
|
||||
// Make sure that submitting the form didn't redirect us to the first page
|
||||
// we submitted the form from after submitting the form from
|
||||
// /test-render-title.
|
||||
$this->submitForm($form_values, 'Submit');
|
||||
$this->assertSession()->addressEquals('test-render-title');
|
||||
$this->assertSession()->pageTextContains('Your email address is test@example.com');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the actual placeholders.
|
||||
*/
|
||||
public function testPlaceholders(): void {
|
||||
$this->drupalGet('test-multiple-forms');
|
||||
|
||||
$placeholder = 'form_action_' . Crypt::hashBase64('Drupal\Core\Form\FormBuilder::prepareForm');
|
||||
$this->assertSession()->pageTextContains('Form action: ' . $placeholder);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that blocks are not added to hidden regions on theme installation.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockHiddenRegionTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* An administrative user to configure the test environment.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User|false
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test', 'search'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create administrative user.
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer themes',
|
||||
'search content',
|
||||
]);
|
||||
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPlaceBlock('search_form_block');
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that hidden regions do not inherit blocks when a theme is installed.
|
||||
*/
|
||||
public function testBlockNotInHiddenRegion(): void {
|
||||
|
||||
// Ensure that the search form block is displayed.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains('Search');
|
||||
|
||||
// Install "block_test_theme" and set it as the default theme.
|
||||
$theme = 'block_test_theme';
|
||||
// We need to install a non-hidden theme so that there is more than one
|
||||
// local task.
|
||||
\Drupal::service('theme_installer')->install([$theme, 'stark']);
|
||||
$this->config('system.theme')
|
||||
->set('default', $theme)
|
||||
->save();
|
||||
// Installing a theme will cause the kernel terminate event to rebuild the
|
||||
// router. Simulate that here.
|
||||
\Drupal::service('router.builder')->rebuildIfNeeded();
|
||||
|
||||
// Ensure that "block_test_theme" is set as the default theme.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertSession()->pageTextContains('Block test theme');
|
||||
|
||||
// Ensure that the search form block is displayed.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains('Search');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests for Block module regarding hook_entity_operations_alter().
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockHookOperationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'entity_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$permissions = [
|
||||
'administer blocks',
|
||||
];
|
||||
|
||||
// Create and log in user.
|
||||
$admin_user = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block list to see if the test_operation link is added.
|
||||
*/
|
||||
public function testBlockOperationAlter(): void {
|
||||
// Add a test block, any block will do.
|
||||
// Set the machine name so the test_operation link can be built later.
|
||||
$block_id = $this->randomMachineName(16);
|
||||
$this->drupalPlaceBlock('system_powered_by_block', ['id' => $block_id]);
|
||||
|
||||
// Get the Block listing.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
|
||||
$test_operation_link = 'admin/structure/block/manage/' . $block_id . '/test_operation';
|
||||
// Test if the test_operation link is on the page.
|
||||
$this->assertSession()->linkByHrefExists($test_operation_link);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests block HTML ID validity.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockHtmlTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
]));
|
||||
|
||||
// Enable the test_html block, to test HTML ID and attributes.
|
||||
\Drupal::keyValue('block_test')->set('attributes', ['data-custom-attribute' => 'foo']);
|
||||
\Drupal::keyValue('block_test')->set('content', $this->randomMachineName());
|
||||
$this->drupalPlaceBlock('test_html', ['id' => 'test_html_block']);
|
||||
|
||||
// Enable a menu block, to test more complicated HTML.
|
||||
$this->drupalPlaceBlock('system_menu_block:admin', ['id' => 'test_menu_block']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for valid HTML for a block.
|
||||
*/
|
||||
public function testHtml(): void {
|
||||
$this->drupalGet('');
|
||||
|
||||
// Ensure that a block's ID is converted to an HTML valid ID, and that
|
||||
// block-specific attributes are added to the same DOM element.
|
||||
$this->assertSession()->elementExists('xpath', '//div[@id="block-test-html-block" and @data-custom-attribute="foo"]');
|
||||
|
||||
// Ensure expected markup for a menu block.
|
||||
$this->assertSession()->elementExists('xpath', '//nav[@id="block-test-menu-block"]/ul/li');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests block module's installation.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockInstallTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests cache tag invalidation after installing the block module.
|
||||
*/
|
||||
public function testCacheTagInvalidationUponInstallation(): void {
|
||||
// Warm the page cache.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'config:block_list');
|
||||
|
||||
// Install the block module, and place the "Powered by Drupal" block.
|
||||
$this->container->get('module_installer')->install(['block', 'shortcut']);
|
||||
$this->rebuildContainer();
|
||||
$this->drupalPlaceBlock('system_powered_by_block');
|
||||
|
||||
// Check the same page, block.module's hook_install() should have
|
||||
// invalidated the 'rendered' cache tag to make blocks show up.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:block_list');
|
||||
$this->assertSession()->pageTextContains('Powered by Drupal');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Tests that blocks assigned to invalid regions are disabled with a warning.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockInvalidRegionTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $configSchemaCheckerExclusions = [
|
||||
// This block is intentionally put in an invalid region, so it will violate
|
||||
// config schema.
|
||||
// @see ::testBlockInvalidRegion()
|
||||
'block.block.invalid_region',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Create an admin user.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer site configuration',
|
||||
'access administration pages',
|
||||
'administer blocks',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that blocks assigned to invalid regions work correctly.
|
||||
*/
|
||||
public function testBlockInInvalidRegion(): void {
|
||||
// Enable a test block and place it in an invalid region.
|
||||
$block = $this->drupalPlaceBlock('test_html', ['id' => 'invalid_region']);
|
||||
\Drupal::configFactory()->getEditable('block.block.' . $block->id())->set('region', 'invalid_region')->save();
|
||||
$block = Block::load($block->id());
|
||||
|
||||
$warning_message = 'The block ' . $block->id() . ' was assigned to the invalid region invalid_region and has been disabled.';
|
||||
|
||||
// Clearing the cache should disable the test block placed in the invalid
|
||||
// region.
|
||||
$this->drupalGet('admin/config/development/performance');
|
||||
$this->submitForm([], 'Clear all caches');
|
||||
$this->assertSession()->statusMessageContains($warning_message, 'warning');
|
||||
|
||||
// Clear the cache to check if the warning message is not triggered.
|
||||
$this->drupalGet('admin/config/development/performance');
|
||||
$this->submitForm([], 'Clear all caches');
|
||||
$this->assertSession()->statusMessageNotContains($warning_message, 'warning');
|
||||
|
||||
// Place disabled test block in the invalid region of the default theme.
|
||||
\Drupal::configFactory()->getEditable('block.block.' . $block->id())->set('region', 'invalid_region')->save();
|
||||
$block = Block::load($block->id());
|
||||
|
||||
// Clear the cache to check if the warning message is not triggered.
|
||||
$this->drupalGet('admin/config/development/performance');
|
||||
$this->submitForm([], 'Clear all caches');
|
||||
$this->assertSession()->statusMessageNotContains($warning_message, 'warning');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests display of menu blocks with multiple languages.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockLanguageCacheTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'language', 'menu_ui'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* List of langcodes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $langcodes = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Create test languages.
|
||||
$this->langcodes = [ConfigurableLanguage::load('en')];
|
||||
for ($i = 1; $i < 3; ++$i) {
|
||||
$language = ConfigurableLanguage::create([
|
||||
'id' => 'l' . $i,
|
||||
'label' => $this->randomString(),
|
||||
]);
|
||||
$language->save();
|
||||
$this->langcodes[$i] = $language;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a block in a language, check blocks page in all languages.
|
||||
*/
|
||||
public function testBlockLinks(): void {
|
||||
// Create admin user to be able to access block admin.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
'administer menu',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create the block cache for all languages.
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
$this->drupalGet('admin/structure/block', ['language' => $langcode]);
|
||||
$this->clickLink('Place block');
|
||||
}
|
||||
|
||||
// Create a menu in the default language.
|
||||
$edit['label'] = $this->randomMachineName();
|
||||
$edit['id'] = mb_strtolower($edit['label']);
|
||||
$this->drupalGet('admin/structure/menu/add');
|
||||
$this->submitForm($edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Menu ' . $edit['label'] . ' has been added.');
|
||||
|
||||
// Check that the block is listed for all languages.
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
$this->drupalGet('admin/structure/block', ['language' => $langcode]);
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->pageTextContains($edit['label']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Tests per-language block configuration.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockLanguageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* An administrative user to configure the test environment.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User|false
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['language', 'block', 'content_translation', 'node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer languages',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Add predefined language.
|
||||
$edit = [
|
||||
'predefined_langcode' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/add');
|
||||
$this->submitForm($edit, 'Add language');
|
||||
|
||||
// Verify that language was added successfully.
|
||||
$this->assertSession()->pageTextContains('French');
|
||||
|
||||
// Set path prefixes for both languages.
|
||||
$this->config('language.negotiation')->set('url', [
|
||||
'source' => 'path_prefix',
|
||||
'prefixes' => [
|
||||
'en' => 'en',
|
||||
'fr' => 'fr',
|
||||
],
|
||||
])->save();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->drupalCreateNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the visibility settings for the blocks based on language.
|
||||
*/
|
||||
public function testLanguageBlockVisibility(): void {
|
||||
// Check if the visibility setting is available.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme);
|
||||
// Ensure that the language visibility field is visible without a type
|
||||
// setting.
|
||||
$this->assertSession()->fieldExists('visibility[language][langcodes][en]');
|
||||
$this->assertSession()->fieldNotExists('visibility[language][context_mapping][language]');
|
||||
|
||||
// Enable a standard block and set the visibility setting for one language.
|
||||
$edit = [
|
||||
'visibility[language][langcodes][en]' => TRUE,
|
||||
'id' => $this->randomMachineName(8),
|
||||
'region' => 'sidebar_first',
|
||||
];
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
// Change the default language.
|
||||
$edit = [
|
||||
'site_default_language' => 'fr',
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->submitForm($edit, 'Save configuration');
|
||||
|
||||
// Check that a page has a block.
|
||||
$this->drupalGet('en');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Powered by Drupal');
|
||||
|
||||
// Check that a page doesn't has a block for the current language anymore.
|
||||
$this->drupalGet('fr');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the visibility settings are removed if the language is deleted.
|
||||
*/
|
||||
public function testLanguageBlockVisibilityLanguageDelete(): void {
|
||||
// Enable a standard block and set the visibility setting for one language.
|
||||
$edit = [
|
||||
'visibility' => [
|
||||
'language' => [
|
||||
'langcodes' => [
|
||||
'fr' => 'fr',
|
||||
],
|
||||
'context_mapping' => ['language' => '@language.current_language_context:language_interface'],
|
||||
],
|
||||
],
|
||||
];
|
||||
$block = $this->drupalPlaceBlock('system_powered_by_block', $edit);
|
||||
|
||||
// Check that we have the language in config after saving the setting.
|
||||
$visibility = $block->getVisibility();
|
||||
$this->assertEquals('fr', $visibility['language']['langcodes']['fr'], 'Language is set in the block configuration.');
|
||||
|
||||
// Delete the language.
|
||||
$this->drupalGet('admin/config/regional/language/delete/fr');
|
||||
$this->submitForm([], 'Delete');
|
||||
|
||||
// Check that the language is no longer stored in the configuration after
|
||||
// it is deleted.
|
||||
$block = Block::load($block->id());
|
||||
$visibility = $block->getVisibility();
|
||||
$this->assertArrayNotHasKey('language', $visibility, 'Language is no longer not set in the block configuration after deleting the block.');
|
||||
|
||||
// Ensure that the block visibility for language is gone from the UI.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Configure');
|
||||
$this->assertSession()->elementNotExists('xpath', '//details[@id="edit-visibility-language"]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block language visibility with different language types.
|
||||
*/
|
||||
public function testMultipleLanguageTypes(): void {
|
||||
// Customize content language detection to be different from interface
|
||||
// language detection.
|
||||
$edit = [
|
||||
// Interface language detection: only using session.
|
||||
'language_interface[enabled][language-url]' => FALSE,
|
||||
'language_interface[enabled][language-session]' => TRUE,
|
||||
// Content language detection: only using URL.
|
||||
'language_content[configurable]' => TRUE,
|
||||
'language_content[enabled][language-url]' => TRUE,
|
||||
'language_content[enabled][language-interface]' => FALSE,
|
||||
];
|
||||
$this->drupalGet('admin/config/regional/language/detection');
|
||||
$this->submitForm($edit, 'Save settings');
|
||||
|
||||
// Check if the visibility setting is available with a type setting.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme);
|
||||
$this->assertSession()->fieldExists('visibility[language][langcodes][en]');
|
||||
$this->assertSession()->fieldExists('visibility[language][context_mapping][language]');
|
||||
|
||||
// Enable a standard block and set visibility to French only.
|
||||
$block_id = $this->randomMachineName(8);
|
||||
$edit = [
|
||||
'visibility[language][context_mapping][language]' => '@language.current_language_context:language_interface',
|
||||
'visibility[language][langcodes][fr]' => TRUE,
|
||||
'id' => $block_id,
|
||||
'region' => 'sidebar_first',
|
||||
];
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
// Interface negotiation depends on request arguments.
|
||||
$this->drupalGet('node/1', ['query' => ['language' => 'en']]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
$this->drupalGet('node/1', ['query' => ['language' => 'fr']]);
|
||||
$this->assertSession()->pageTextContains('Powered by Drupal');
|
||||
|
||||
// Log in again in order to clear the interface language stored in the
|
||||
// session.
|
||||
$this->drupalLogout();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Content language does not depend on session/request arguments.
|
||||
// It will fall back on English (site default) and not display the block.
|
||||
$this->drupalGet('en');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
$this->drupalGet('fr');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
|
||||
// Change visibility to now depend on content language for this block.
|
||||
$edit = [
|
||||
'visibility[language][context_mapping][language]' => '@language.current_language_context:language_content',
|
||||
];
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block_id);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
// Content language negotiation does not depend on request arguments.
|
||||
// It will fall back on English (site default) and not display the block.
|
||||
$this->drupalGet('node/1', ['query' => ['language' => 'en']]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
$this->drupalGet('node/1', ['query' => ['language' => 'fr']]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
|
||||
// Content language negotiation depends on path prefix.
|
||||
$this->drupalGet('en');
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
$this->drupalGet('fr');
|
||||
$this->assertSession()->pageTextContains('Powered by Drupal');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests blocks are being rendered in order by weight.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockRenderOrderTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['node', 'block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Create a test user.
|
||||
$end_user = $this->drupalCreateUser([
|
||||
'access content',
|
||||
]);
|
||||
$this->drupalLogin($end_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the render order of the blocks.
|
||||
*/
|
||||
public function testBlockRenderOrder(): void {
|
||||
// Enable test blocks and place them in the same region.
|
||||
$region = 'header';
|
||||
$test_blocks = [
|
||||
'stark_powered' => [
|
||||
'weight' => -3,
|
||||
'id' => 'stark_powered',
|
||||
'label' => 'Test block A',
|
||||
],
|
||||
'stark_by' => [
|
||||
'weight' => 3,
|
||||
'id' => 'stark_by',
|
||||
'label' => 'Test block C',
|
||||
],
|
||||
'stark_drupal' => [
|
||||
'weight' => 3,
|
||||
'id' => 'stark_drupal',
|
||||
'label' => 'Test block B',
|
||||
],
|
||||
];
|
||||
|
||||
// Place the test blocks.
|
||||
foreach ($test_blocks as $test_block) {
|
||||
$this->drupalPlaceBlock('system_powered_by_block', [
|
||||
'label' => $test_block['label'],
|
||||
'region' => $region,
|
||||
'weight' => $test_block['weight'],
|
||||
'id' => $test_block['id'],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->drupalGet('');
|
||||
$test_content = $this->getSession()->getPage()->getContent();
|
||||
|
||||
$controller = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
foreach ($controller->loadMultiple() as $return_block) {
|
||||
$id = $return_block->id();
|
||||
if ($return_block_weight = $return_block->getWeight()) {
|
||||
$this->assertSame((int) $test_blocks[$id]['weight'], $return_block_weight, 'Block weight is set as "' . $return_block_weight . '" for ' . $id . ' block.');
|
||||
$position[$id] = strpos($test_content, Html::getClass('block-' . $test_blocks[$id]['id']));
|
||||
}
|
||||
}
|
||||
// Verify that blocks with different weight are rendered in the correct
|
||||
// order.
|
||||
$this->assertLessThan($position['stark_by'], $position['stark_powered']);
|
||||
// Verify that blocks with identical weight are rendered in alphabetical
|
||||
// order.
|
||||
$this->assertLessThan($position['stark_by'], $position['stark_drupal']);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
/**
|
||||
* Tests branding block display.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockSystemBrandingTest extends BlockTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Set a site slogan.
|
||||
$this->config('system.site')
|
||||
->set('slogan', 'Community plumbing')
|
||||
->save();
|
||||
// Add the system branding block to the page.
|
||||
$this->drupalPlaceBlock('system_branding_block', ['region' => 'header', 'id' => 'site_branding']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests system branding block configuration.
|
||||
*/
|
||||
public function testSystemBrandingSettings(): void {
|
||||
$site_logo_xpath = '//div[@id="block-site-branding"]/a/img';
|
||||
$site_name_xpath = '//div[@id="block-site-branding"]/a[text() = "Drupal"]';
|
||||
$site_slogan_xpath = '//div[@id="block-site-branding"]/descendant::text()[last()]';
|
||||
|
||||
// Set default block settings.
|
||||
$this->drupalGet('');
|
||||
|
||||
// Test that all branding elements are displayed.
|
||||
$this->assertSession()->elementExists('xpath', $site_logo_xpath);
|
||||
$this->assertSession()->elementExists('xpath', $site_name_xpath);
|
||||
$this->assertSession()->elementExists('xpath', $site_slogan_xpath);
|
||||
$this->assertSession()->elementTextContains('xpath', $site_slogan_xpath, 'Community plumbing');
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:system.site');
|
||||
// Just this once, assert that the img src of the logo is as expected.
|
||||
$theme_path = \Drupal::service('extension.list.theme')->getPath($this->defaultTheme);
|
||||
$this->assertSession()->elementAttributeContains('xpath', $site_logo_xpath, 'src', $theme_path . '/logo.svg');
|
||||
|
||||
// Be sure the slogan is XSS-filtered.
|
||||
$this->config('system.site')
|
||||
->set('slogan', '<script>alert("Community carpentry");</script>')
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->elementTextEquals('xpath', $site_slogan_xpath, 'alert("Community carpentry");');
|
||||
$this->assertSession()->responseNotContains('<script>alert("Community carpentry");</script>');
|
||||
|
||||
// Turn just the logo off.
|
||||
$this->config('block.block.site_branding')
|
||||
->set('settings.use_site_logo', 0)
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
|
||||
// Re-test all branding elements.
|
||||
$this->assertSession()->elementNotExists('xpath', $site_logo_xpath);
|
||||
$this->assertSession()->elementExists('xpath', $site_name_xpath);
|
||||
$this->assertSession()->elementTextContains('xpath', $site_slogan_xpath, 'alert("Community carpentry");');
|
||||
$this->assertSession()->responseNotContains('<script>alert("Community carpentry");</script>');
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:system.site');
|
||||
|
||||
// Turn just the site name off.
|
||||
$this->config('block.block.site_branding')
|
||||
->set('settings.use_site_logo', 1)
|
||||
->set('settings.use_site_name', 0)
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
|
||||
// Re-test all branding elements.
|
||||
$this->assertSession()->elementExists('xpath', $site_logo_xpath);
|
||||
$this->assertSession()->elementNotExists('xpath', $site_name_xpath);
|
||||
$this->assertSession()->elementTextContains('xpath', $site_slogan_xpath, 'alert("Community carpentry");');
|
||||
$this->assertSession()->responseNotContains('<script>alert("Community carpentry");</script>');
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:system.site');
|
||||
|
||||
// Turn just the site slogan off.
|
||||
$this->config('block.block.site_branding')
|
||||
->set('settings.use_site_name', 1)
|
||||
->set('settings.use_site_slogan', 0)
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
|
||||
// Re-test all branding elements.
|
||||
$this->assertSession()->elementExists('xpath', $site_logo_xpath);
|
||||
$this->assertSession()->elementExists('xpath', $site_name_xpath);
|
||||
$this->assertSession()->elementTextNotContains('xpath', $site_slogan_xpath, 'Community carpentry');
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:system.site');
|
||||
|
||||
// Turn the site name and the site slogan off.
|
||||
$this->config('block.block.site_branding')
|
||||
->set('settings.use_site_name', 0)
|
||||
->set('settings.use_site_slogan', 0)
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
|
||||
// Re-test all branding elements.
|
||||
$this->assertSession()->elementExists('xpath', $site_logo_xpath);
|
||||
$this->assertSession()->elementNotExists('xpath', $site_name_xpath);
|
||||
$this->assertSession()->elementTextNotContains('xpath', $site_slogan_xpath, 'Community carpentry');
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:system.site');
|
||||
}
|
||||
|
||||
}
|
||||
646
web/core/modules/block/tests/src/Functional/BlockTest.php
Normal file
646
web/core/modules/block/tests/src/Functional/BlockTest.php
Normal file
@ -0,0 +1,646 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests basic block functionality.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockTest extends BlockTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests block visibility.
|
||||
*/
|
||||
public function testBlockVisibility(): void {
|
||||
$block_name = 'system_powered_by_block';
|
||||
// Create a random title for the block.
|
||||
$title = $this->randomMachineName(8);
|
||||
// Enable a standard block.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$edit = [
|
||||
'id' => $this->randomMachineName(8),
|
||||
'region' => 'sidebar_first',
|
||||
'settings[label]' => $title,
|
||||
'settings[label_display]' => TRUE,
|
||||
];
|
||||
// Set the block to be hidden on any user path, to be shown only to
|
||||
// authenticated users, and to be shown only on 200 and 404 responses.
|
||||
$edit['visibility[request_path][pages]'] = '/user*';
|
||||
$edit['visibility[request_path][negate]'] = TRUE;
|
||||
$edit['visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']'] = TRUE;
|
||||
$edit['visibility[response_status][status_codes][200]'] = 200;
|
||||
$edit['visibility[response_status][status_codes][404]'] = 404;
|
||||
$this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme);
|
||||
$this->assertSession()->checkboxChecked('edit-visibility-request-path-negate-0');
|
||||
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->assertSession()->statusMessageContains('The block configuration has been saved.', 'status');
|
||||
|
||||
$this->clickLink('Configure');
|
||||
$this->assertSession()->checkboxChecked('edit-visibility-request-path-negate-1');
|
||||
$this->assertSession()->checkboxChecked('edit-visibility-response-status-status-codes-200');
|
||||
$this->assertSession()->checkboxChecked('edit-visibility-response-status-status-codes-404');
|
||||
|
||||
// Confirm that the block is displayed on the front page (200 response).
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($title);
|
||||
|
||||
// Confirm that the block is not displayed according to path visibility
|
||||
// rules.
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
|
||||
// Confirm that the block is displayed on a 404 response.
|
||||
$this->drupalGet('/0/null');
|
||||
$this->assertSession()->pageTextContains($title);
|
||||
|
||||
// Confirm that the block is not displayed on a 403 response.
|
||||
$this->drupalGet('/admin/config/system/cron');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
|
||||
// Confirm that the block is not displayed to anonymous users.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
|
||||
// Confirm that an empty block is not displayed.
|
||||
$this->assertSession()->pageTextNotContains('Powered by Drupal');
|
||||
$this->assertSession()->responseNotContains('sidebar-first');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that visibility can be properly toggled.
|
||||
*/
|
||||
public function testBlockToggleVisibility(): void {
|
||||
$block_name = 'system_powered_by_block';
|
||||
// Create a random title for the block.
|
||||
$title = $this->randomMachineName(8);
|
||||
// Enable a standard block.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$edit = [
|
||||
'id' => $this->randomMachineName(8),
|
||||
'region' => 'sidebar_first',
|
||||
'settings[label]' => $title,
|
||||
];
|
||||
$block_id = $edit['id'];
|
||||
// Set the block to be shown only to authenticated users.
|
||||
$edit['visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']'] = TRUE;
|
||||
$this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->clickLink('Configure');
|
||||
$this->assertSession()->checkboxChecked('edit-visibility-user-role-roles-authenticated');
|
||||
|
||||
$edit = [
|
||||
'visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']' => FALSE,
|
||||
];
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->clickLink('Configure');
|
||||
$this->assertSession()->checkboxNotChecked('edit-visibility-user-role-roles-authenticated');
|
||||
|
||||
// Ensure that no visibility is configured.
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$block = Block::load($block_id);
|
||||
$visibility_config = $block->getVisibilityConditions()->getConfiguration();
|
||||
$this->assertSame([], $visibility_config);
|
||||
$this->assertSame([], $block->get('visibility'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block visibility when leaving "pages" textarea empty.
|
||||
*/
|
||||
public function testBlockVisibilityListedEmpty(): void {
|
||||
$block_name = 'system_powered_by_block';
|
||||
// Create a random title for the block.
|
||||
$title = $this->randomMachineName(8);
|
||||
// Enable a standard block.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$edit = [
|
||||
'id' => $this->randomMachineName(8),
|
||||
'region' => 'sidebar_first',
|
||||
'settings[label]' => $title,
|
||||
'visibility[request_path][negate]' => TRUE,
|
||||
];
|
||||
// Set the block to be hidden on any user path, and to be shown only to
|
||||
// authenticated users.
|
||||
$this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->assertSession()->statusMessageContains('The block configuration has been saved.', 'status');
|
||||
|
||||
// Confirm that block was not displayed according to block visibility
|
||||
// rules.
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
|
||||
// Confirm that block was not displayed according to block visibility
|
||||
// rules regardless of path case.
|
||||
$this->drupalGet('USER');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
|
||||
// Confirm that the block is not displayed to anonymous users.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests adding a block from the library page with a weight query string.
|
||||
*/
|
||||
public function testAddBlockFromLibraryWithWeight(): void {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
// Test one positive, zero, and one negative weight.
|
||||
foreach (['7', '0', '-9'] as $weight) {
|
||||
$options = [
|
||||
'query' => [
|
||||
'region' => 'sidebar_first',
|
||||
'weight' => $weight,
|
||||
],
|
||||
];
|
||||
$this->drupalGet(Url::fromRoute('block.admin_library', ['theme' => $default_theme], $options));
|
||||
|
||||
$block_name = 'system_powered_by_block';
|
||||
$add_url = Url::fromRoute('block.admin_add', [
|
||||
'plugin_id' => $block_name,
|
||||
'theme' => $default_theme,
|
||||
]);
|
||||
|
||||
// Verify that one link is found, with the expected link text.
|
||||
$xpath = $this->assertSession()->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $add_url->toString()]);
|
||||
$this->assertSession()->elementsCount('xpath', $xpath, 1);
|
||||
$this->assertSession()->elementTextEquals('xpath', $xpath, 'Place block');
|
||||
|
||||
$link = $this->getSession()->getPage()->find('xpath', $xpath);
|
||||
[, $query_string] = explode('?', $link->getAttribute('href'), 2);
|
||||
parse_str($query_string, $query_parts);
|
||||
$this->assertEquals($weight, $query_parts['weight'], 'Found the expected weight query string.');
|
||||
|
||||
// Create a random title for the block.
|
||||
$title = $this->randomMachineName(8);
|
||||
$block_id = $this->randomMachineName(8);
|
||||
$edit = [
|
||||
'id' => $block_id,
|
||||
'settings[label]' => $title,
|
||||
];
|
||||
// Create the block using the link parsed from the library page.
|
||||
$this->drupalGet($this->getAbsoluteUrl($link->getAttribute('href')));
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
// Ensure that the block was created with the expected weight.
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$block = Block::load($block_id);
|
||||
$this->assertEquals($weight, $block->getWeight(), 'Found the block with expected weight.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests configuring and moving a module-define block to specific regions.
|
||||
*/
|
||||
public function testBlock(): void {
|
||||
// Place page title block to test error messages.
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
// Disable the block.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Disable');
|
||||
|
||||
// Select the 'Powered by Drupal' block to be configured and moved.
|
||||
$block = [];
|
||||
$block['id'] = 'system_powered_by_block';
|
||||
$block['settings[label]'] = $this->randomMachineName(8);
|
||||
$block['settings[label_display]'] = TRUE;
|
||||
$block['theme'] = $this->config('system.theme')->get('default');
|
||||
$block['region'] = 'header';
|
||||
|
||||
// Set block title to confirm that interface works and override any custom
|
||||
// titles.
|
||||
$this->drupalGet('admin/structure/block/add/' . $block['id'] . '/' . $block['theme']);
|
||||
$this->submitForm([
|
||||
'settings[label]' => $block['settings[label]'],
|
||||
'settings[label_display]' => $block['settings[label_display]'],
|
||||
'id' => $block['id'],
|
||||
'region' => $block['region'],
|
||||
], 'Save block');
|
||||
$this->assertSession()->statusMessageContains('The block configuration has been saved.', 'status');
|
||||
// Check to see if the block was created by checking its configuration.
|
||||
$instance = Block::load($block['id']);
|
||||
|
||||
$this->assertEquals($block['settings[label]'], $instance->label(), 'Stored block title found.');
|
||||
|
||||
// Check whether the block can be moved to all available regions.
|
||||
foreach ($this->regions as $region) {
|
||||
$this->moveBlockToRegion($block, $region);
|
||||
}
|
||||
|
||||
// Disable the block.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Disable');
|
||||
|
||||
// Confirm that the block is now listed as disabled.
|
||||
$this->assertSession()->statusMessageContains('The block settings have been updated.', 'status');
|
||||
|
||||
// Confirm that the block instance title and markup are not displayed.
|
||||
$this->drupalGet('node');
|
||||
$this->assertSession()->pageTextNotContains($block['settings[label]']);
|
||||
// Check for <div id="block-my-block-instance-name"> if the machine name
|
||||
// is my_block_instance_name.
|
||||
$xpath = $this->assertSession()->buildXPathQuery('//div[@id=:id]/*', [':id' => 'block-' . str_replace('_', '-', strtolower($block['id']))]);
|
||||
$this->assertSession()->elementNotExists('xpath', $xpath);
|
||||
|
||||
$pages = [
|
||||
'',
|
||||
'<front>',
|
||||
'/valid-page',
|
||||
'user/login',
|
||||
];
|
||||
// Test error when not including forward slash.
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block['id']);
|
||||
$this->submitForm(['visibility[request_path][pages]' => implode("\n", $pages)], 'Save block');
|
||||
$this->assertSession()->pageTextContains('The path user/login requires a leading forward slash when used with the Pages setting.');
|
||||
|
||||
// Test deleting the block from the edit form.
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block['id']);
|
||||
$this->clickLink('Remove block');
|
||||
$this->assertSession()->pageTextContains('Are you sure you want to remove the block ' . $block['settings[label]'] . ' from the Footer region?');
|
||||
$this->submitForm([], 'Remove');
|
||||
$this->assertSession()->statusMessageContains('The block ' . $block['settings[label]'] . ' has been removed from the Footer region.', 'status');
|
||||
|
||||
// Test deleting a block via "Configure block" link.
|
||||
$block = $this->drupalPlaceBlock('system_powered_by_block', [
|
||||
'region' => 'left_sidebar',
|
||||
]);
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block->id(), ['query' => ['destination' => 'admin']]);
|
||||
$this->clickLink('Remove block');
|
||||
$this->assertSession()->pageTextContains('Are you sure you want to remove the block ' . $block->label() . ' from the Left sidebar region?');
|
||||
$this->submitForm([], 'Remove');
|
||||
$this->assertSession()->statusMessageContains('The block ' . $block->label() . ' has been removed from the Left sidebar region.', 'status');
|
||||
$this->assertSession()->addressEquals('admin');
|
||||
$this->assertSession()->responseNotContains($block->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the block form has a theme selector when not passed via the URL.
|
||||
*/
|
||||
public function testBlockThemeSelector(): void {
|
||||
// Install all themes.
|
||||
$themes = [
|
||||
'olivero',
|
||||
'claro',
|
||||
'stark',
|
||||
];
|
||||
\Drupal::service('theme_installer')->install($themes);
|
||||
$theme_settings = $this->config('system.theme');
|
||||
foreach ($themes as $theme) {
|
||||
$this->drupalGet('admin/structure/block/list/' . $theme);
|
||||
$this->assertSession()->titleEquals('Block layout | Drupal');
|
||||
// Select the 'Powered by Drupal' block to be placed.
|
||||
$block = [];
|
||||
$block['id'] = $this->randomMachineName();
|
||||
$block['theme'] = $theme;
|
||||
$block['region'] = 'content';
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block');
|
||||
$this->submitForm($block, 'Save block');
|
||||
$this->assertSession()->statusMessageContains('The block configuration has been saved.', 'status');
|
||||
$this->assertSession()->addressEquals('admin/structure/block/list/' . $theme . '?block-placement=' . Html::getClass($block['id']));
|
||||
|
||||
// Set the default theme and ensure the block is placed.
|
||||
$theme_settings->set('default', $theme)->save();
|
||||
$this->drupalGet('');
|
||||
$block_id = Html::getUniqueId('block-' . $block['id']);
|
||||
$this->assertSession()->elementExists('xpath', "//div[@id = '$block_id']");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block display of theme titles.
|
||||
*/
|
||||
public function testThemeName(): void {
|
||||
// Enable the help block.
|
||||
$this->drupalPlaceBlock('help_block', ['region' => 'help']);
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
// Explicitly set the default and admin themes.
|
||||
$theme = 'block_test_special_chars_theme';
|
||||
\Drupal::service('theme_installer')->install([$theme]);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertSession()->assertEscaped('<"Cat" & \'Mouse\'>');
|
||||
$this->drupalGet('admin/structure/block/list/block_test_special_chars_theme');
|
||||
$this->assertSession()->assertEscaped('Demonstrate block regions (<"Cat" & \'Mouse\'>)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block title display settings.
|
||||
*/
|
||||
public function testHideBlockTitle(): void {
|
||||
$block_name = 'system_powered_by_block';
|
||||
// Create a random title for the block.
|
||||
$title = $this->randomMachineName(8);
|
||||
$id = $this->randomMachineName(8);
|
||||
// Enable a standard block.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$edit = [
|
||||
'id' => $id,
|
||||
'region' => 'sidebar_first',
|
||||
'settings[label]' => $title,
|
||||
];
|
||||
$this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->assertSession()->statusMessageContains('The block configuration has been saved.', 'status');
|
||||
|
||||
// Confirm that the block is not displayed by default.
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->pageTextNotContains($title);
|
||||
|
||||
$edit = [
|
||||
'settings[label_display]' => TRUE,
|
||||
];
|
||||
$this->drupalGet('admin/structure/block/manage/' . $id);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->assertSession()->statusMessageContains('The block configuration has been saved.', 'status');
|
||||
|
||||
$this->drupalGet('admin/structure/block/manage/' . $id);
|
||||
$this->assertSession()->checkboxChecked('edit-settings-label-display');
|
||||
|
||||
// Confirm that the block is displayed when enabled.
|
||||
$this->drupalGet('user');
|
||||
$this->assertSession()->pageTextContains($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a block to a given region via the UI and confirms the result.
|
||||
*
|
||||
* @param array $block
|
||||
* An array of information about the block, including the following keys:
|
||||
* - module: The module providing the block.
|
||||
* - title: The title of the block.
|
||||
* - delta: The block's delta key.
|
||||
* @param string $region
|
||||
* The machine name of the theme region to move the block to, for example
|
||||
* 'header' or 'sidebar_first'.
|
||||
*/
|
||||
public function moveBlockToRegion(array $block, $region): void {
|
||||
// Set the created block to a specific region.
|
||||
$block += ['theme' => $this->config('system.theme')->get('default')];
|
||||
$edit = [];
|
||||
$edit['blocks[' . $block['id'] . '][region]'] = $region;
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->submitForm($edit, 'Save blocks');
|
||||
|
||||
// Confirm that the block was moved to the proper region.
|
||||
$this->assertSession()->statusMessageContains('The block settings have been updated.', 'status');
|
||||
|
||||
// Confirm that the block is being displayed.
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains($block['settings[label]']);
|
||||
|
||||
$region_xpath = [
|
||||
'header' => '//header[@role = "banner"]',
|
||||
'sidebar_first' => '//aside[contains(@class, "layout-sidebar-first")]',
|
||||
'content' => '//div[contains(@class, "layout-content")]',
|
||||
'sidebar_second' => '//aside[contains(@class, "layout-sidebar-second")]',
|
||||
'footer' => '//footer[@role = "contentinfo"]',
|
||||
];
|
||||
|
||||
// Confirm that the content block was found at the proper region.
|
||||
$xpath = $this->assertSession()->buildXPathQuery($region_xpath[$region] . '//div[@id=:block-id]/*', [
|
||||
':block-id' => 'block-' . str_replace('_', '-', strtolower($block['id'])),
|
||||
]);
|
||||
$this->assertSession()->elementExists('xpath', $xpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that cache tags are properly set and bubbled up to the page cache.
|
||||
*
|
||||
* Verify that invalidation of these cache tags works:
|
||||
* - "block:<block ID>"
|
||||
* - "block_plugin:<block plugin ID>"
|
||||
*/
|
||||
public function testBlockCacheTags(): void {
|
||||
// The page cache only works for anonymous users.
|
||||
$this->drupalLogout();
|
||||
|
||||
// Enable page caching.
|
||||
$config = $this->config('system.performance');
|
||||
$config->set('cache.page.max_age', 300);
|
||||
$config->save();
|
||||
|
||||
// Place the "Powered by Drupal" block.
|
||||
$block = $this->drupalPlaceBlock('system_powered_by_block', ['id' => 'powered']);
|
||||
|
||||
// Prime the page cache.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
|
||||
// Verify a cache hit, but also the presence of the correct cache tags in
|
||||
// both the page and block caches.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
$cid_parts = [Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(), ''];
|
||||
$cid = implode(':', $cid_parts);
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
$expected_cache_tags = [
|
||||
'config:block_list',
|
||||
'block_view',
|
||||
'config:block.block.powered',
|
||||
'config:user.role.anonymous',
|
||||
'http_response',
|
||||
'rendered',
|
||||
];
|
||||
sort($expected_cache_tags);
|
||||
$keys = \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:language_interface', 'theme', 'user.permissions'])->getKeys();
|
||||
$this->assertSame($expected_cache_tags, $cache_entry->tags);
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:' . implode(':', $keys));
|
||||
$expected_cache_tags = [
|
||||
'block_view',
|
||||
'config:block.block.powered',
|
||||
'rendered',
|
||||
];
|
||||
sort($expected_cache_tags);
|
||||
$this->assertSame($expected_cache_tags, $cache_entry->tags);
|
||||
|
||||
// The "Powered by Drupal" block is modified; verify a cache miss.
|
||||
$block->setRegion('content');
|
||||
$block->save();
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
|
||||
// Now we should have a cache hit again.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
|
||||
// Place the "Powered by Drupal" block another time; verify a cache miss.
|
||||
$this->drupalPlaceBlock('system_powered_by_block', ['id' => 'powered_2']);
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
|
||||
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
$cid_parts = [Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(), ''];
|
||||
$cid = implode(':', $cid_parts);
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
$expected_cache_tags = [
|
||||
'config:block_list',
|
||||
'block_view',
|
||||
'config:block.block.powered',
|
||||
'config:block.block.powered_2',
|
||||
'config:user.role.anonymous',
|
||||
'http_response',
|
||||
'rendered',
|
||||
];
|
||||
sort($expected_cache_tags);
|
||||
$this->assertEquals($expected_cache_tags, $cache_entry->tags);
|
||||
$expected_cache_tags = [
|
||||
'block_view',
|
||||
'config:block.block.powered',
|
||||
'rendered',
|
||||
];
|
||||
sort($expected_cache_tags);
|
||||
$keys = \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:language_interface', 'theme', 'user.permissions'])->getKeys();
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:' . implode(':', $keys));
|
||||
$this->assertSame($expected_cache_tags, $cache_entry->tags);
|
||||
$expected_cache_tags = [
|
||||
'block_view',
|
||||
'config:block.block.powered_2',
|
||||
'rendered',
|
||||
];
|
||||
sort($expected_cache_tags);
|
||||
$keys = \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:language_interface', 'theme', 'user.permissions'])->getKeys();
|
||||
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered_2:' . implode(':', $keys));
|
||||
$this->assertSame($expected_cache_tags, $cache_entry->tags);
|
||||
|
||||
// Now we should have a cache hit again.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
|
||||
// Delete the "Powered by Drupal" blocks; verify a cache miss.
|
||||
$block_storage = \Drupal::entityTypeManager()->getStorage('block');
|
||||
$block_storage->load('powered')->delete();
|
||||
$block_storage->load('powered_2')->delete();
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a link exists to block layout from the appearance form.
|
||||
*/
|
||||
public function testThemeAdminLink(): void {
|
||||
$this->drupalPlaceBlock('help_block', ['region' => 'help']);
|
||||
$theme_admin = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer themes',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($theme_admin);
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->assertSession()->pageTextContains('You can place blocks for each theme on the block layout page');
|
||||
$this->assertSession()->linkByHrefExists('admin/structure/block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that uninstalling a theme removes its block configuration.
|
||||
*/
|
||||
public function testUninstallTheme(): void {
|
||||
/** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */
|
||||
$theme_installer = \Drupal::service('theme_installer');
|
||||
|
||||
$theme_installer->install(['claro']);
|
||||
$this->config('system.theme')->set('default', 'claro')->save();
|
||||
$block = $this->drupalPlaceBlock('system_powered_by_block', ['theme' => 'claro', 'region' => 'help']);
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->pageTextContains('Powered by Drupal');
|
||||
|
||||
$this->config('system.theme')->set('default', 'stark')->save();
|
||||
$theme_installer->uninstall(['claro']);
|
||||
|
||||
// Ensure that the block configuration does not exist anymore.
|
||||
$this->assertNull(Block::load($block->id()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block access.
|
||||
*/
|
||||
public function testBlockAccess(): void {
|
||||
$this->drupalPlaceBlock('test_access', ['region' => 'help']);
|
||||
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->pageTextNotContains('Hello test world');
|
||||
|
||||
\Drupal::keyValue('block_test')->set('access', TRUE);
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertSession()->pageTextContains('Hello test world');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block_user_role_delete.
|
||||
*/
|
||||
public function testBlockUserRoleDelete(): void {
|
||||
$role1 = Role::create(['id' => 'test_role1', 'label' => 'Test role 1']);
|
||||
$role1->save();
|
||||
|
||||
$role2 = Role::create(['id' => 'test_role2', 'label' => 'Test role 2']);
|
||||
$role2->save();
|
||||
|
||||
$block = Block::create([
|
||||
'id' => $this->randomMachineName(),
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'theme' => 'stark',
|
||||
]);
|
||||
|
||||
$block->setVisibilityConfig('user_role', [
|
||||
'roles' => [
|
||||
$role1->id() => $role1->id(),
|
||||
$role2->id() => $role2->id(),
|
||||
],
|
||||
]);
|
||||
|
||||
$block->save();
|
||||
|
||||
$this->assertEquals([$role1->id() => $role1->id(), $role2->id() => $role2->id()], $block->getVisibility()['user_role']['roles']);
|
||||
|
||||
$role1->delete();
|
||||
|
||||
$block = Block::load($block->id());
|
||||
$this->assertEquals([$role2->id() => $role2->id()], $block->getVisibility()['user_role']['roles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block title.
|
||||
*/
|
||||
public function testBlockTitle(): void {
|
||||
// Create a custom title for the block.
|
||||
$title = "This block's <b>great!</b>";
|
||||
// Enable a standard block.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$edit = [
|
||||
'id' => 'test',
|
||||
'region' => 'sidebar_first',
|
||||
'settings[label]' => $title,
|
||||
'settings[label_display]' => TRUE,
|
||||
];
|
||||
// Set the block to be shown only to authenticated users.
|
||||
$edit['visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']'] = TRUE;
|
||||
$this->drupalGet('admin/structure/block/add/foo/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
// Ensure that the title is displayed as plain text.
|
||||
$elements = $this->xpath('//table/tbody/tr//td[contains(@class, "block")]');
|
||||
$this->assertEquals($title, $elements[0]->getText());
|
||||
|
||||
$this->clickLink('Disable');
|
||||
$elements = $this->xpath('//table/tbody/tr//td[contains(@class, "block")]');
|
||||
$this->assertEquals("$title (disabled)", $elements[0]->getText());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Provides setup and helper methods for block module tests.
|
||||
*/
|
||||
abstract class BlockTestBase extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'filter',
|
||||
'test_page_test',
|
||||
'help',
|
||||
'block_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* A list of theme regions to test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $regions;
|
||||
|
||||
/**
|
||||
* A test user with administrative privileges.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Use the test page as the front page.
|
||||
$this->config('system.site')->set('page.front', '/test-page')->save();
|
||||
|
||||
// Create Full HTML text format.
|
||||
$full_html_format = FilterFormat::create([
|
||||
'format' => 'full_html',
|
||||
'name' => 'Full HTML',
|
||||
]);
|
||||
$full_html_format->save();
|
||||
|
||||
// Create and log in an administrative user having access to the Full HTML
|
||||
// text format.
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
$full_html_format->getPermissionName(),
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Define the existing regions.
|
||||
$this->regions = [
|
||||
'header',
|
||||
'sidebar_first',
|
||||
'content',
|
||||
'sidebar_second',
|
||||
'footer',
|
||||
];
|
||||
$block_storage = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
$blocks = $block_storage->loadByProperties(['theme' => $this->config('system.theme')->get('default')]);
|
||||
foreach ($blocks as $block) {
|
||||
$block->delete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
414
web/core/modules/block/tests/src/Functional/BlockUiTest.php
Normal file
414
web/core/modules/block/tests/src/Functional/BlockUiTest.php
Normal file
@ -0,0 +1,414 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
// cspell:ignore displaymessage scriptalertxsssubjectscript
|
||||
// cspell:ignore testcontextawareblock
|
||||
|
||||
/**
|
||||
* Tests that the block configuration UI exists and stores data correctly.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockUiTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'block_test',
|
||||
'help',
|
||||
'condition_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* The submitted block values used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $blockValues;
|
||||
|
||||
/**
|
||||
* The block entities used by this test.
|
||||
*
|
||||
* @var \Drupal\block\BlockInterface[]
|
||||
*/
|
||||
protected $blocks;
|
||||
|
||||
/**
|
||||
* An administrative user to configure the test environment.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User|false
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Create and log in an administrative user.
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Enable some test blocks.
|
||||
$this->blockValues = [
|
||||
[
|
||||
'label' => 'Tools',
|
||||
'tr' => '6',
|
||||
'plugin_id' => 'system_menu_block:tools',
|
||||
'settings' => ['region' => 'sidebar_second', 'id' => 'tools'],
|
||||
'test_weight' => '-1',
|
||||
],
|
||||
[
|
||||
'label' => 'Powered by Drupal',
|
||||
'tr' => '17',
|
||||
'plugin_id' => 'system_powered_by_block',
|
||||
'settings' => ['region' => 'footer', 'id' => 'powered'],
|
||||
'test_weight' => '0',
|
||||
],
|
||||
];
|
||||
$this->blocks = [];
|
||||
foreach ($this->blockValues as $values) {
|
||||
$this->blocks[] = $this->drupalPlaceBlock($values['plugin_id'], $values['settings']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block demo page exists and functions correctly.
|
||||
*/
|
||||
public function testBlockDemoUiPage(): void {
|
||||
$this->drupalPlaceBlock('help_block', ['region' => 'help']);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Demonstrate block regions (Stark)');
|
||||
$this->assertSession()->elementExists('xpath', '//header[@role = "banner"]/div/div[contains(@class, "block-region") and contains(text(), "Header")]');
|
||||
|
||||
// Ensure that other themes can use the block demo page.
|
||||
\Drupal::service('theme_installer')->install(['test_theme']);
|
||||
$this->drupalGet('admin/structure/block/demo/test_theme');
|
||||
$this->assertSession()->assertEscaped('<strong>Test theme</strong>');
|
||||
|
||||
// Ensure that a hidden theme cannot use the block demo page.
|
||||
\Drupal::service('theme_installer')->install(['stable9']);
|
||||
$this->drupalGet('admin/structure/block/demo/stable9');
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
|
||||
// Delete all blocks and verify saving the block layout results in a
|
||||
// validation error.
|
||||
$block_storage = \Drupal::service('entity_type.manager')->getStorage('block');
|
||||
$blocks = $block_storage->loadMultiple();
|
||||
foreach ($blocks as $block) {
|
||||
$block->delete();
|
||||
}
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$blocks_table = $this->xpath("//tr[@class='block-enabled']");
|
||||
$this->assertEmpty($blocks_table, 'The blocks table is now empty.');
|
||||
$this->submitForm([], 'Save blocks');
|
||||
$this->assertSession()->pageTextContains('No blocks settings to update');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block admin page exists and functions correctly.
|
||||
*/
|
||||
public function testBlockAdminUiPage(): void {
|
||||
// Visit the blocks admin ui.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
// Look for the blocks table.
|
||||
$this->assertSession()->elementExists('xpath', "//table[@id='blocks']");
|
||||
// Look for test blocks in the table.
|
||||
foreach ($this->blockValues as $delta => $values) {
|
||||
$block = $this->blocks[$delta];
|
||||
$label = $block->label();
|
||||
$this->assertSession()->elementTextEquals('xpath', '//*[@id="blocks"]/tbody/tr[' . $values['tr'] . ']/td[1]/text()', $label);
|
||||
// Look for a test block region select form element.
|
||||
$this->assertSession()->fieldExists('blocks[' . $values['settings']['id'] . '][region]');
|
||||
// Move the test block to the header region.
|
||||
$edit['blocks[' . $values['settings']['id'] . '][region]'] = 'header';
|
||||
// Look for a test block weight select form element.
|
||||
$this->assertSession()->fieldExists('blocks[' . $values['settings']['id'] . '][weight]');
|
||||
// Change the test block's weight.
|
||||
$edit['blocks[' . $values['settings']['id'] . '][weight]'] = $values['test_weight'];
|
||||
}
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->submitForm($edit, 'Save blocks');
|
||||
foreach ($this->blockValues as $values) {
|
||||
// Check if the region and weight settings changes have persisted.
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-blocks-' . $values['settings']['id'] . '-region', 'header')->isSelected());
|
||||
$this->assertTrue($this->assertSession()->optionExists('edit-blocks-' . $values['settings']['id'] . '-weight', $values['test_weight'])->isSelected());
|
||||
}
|
||||
|
||||
// Add a block with a machine name the same as a region name.
|
||||
$this->drupalPlaceBlock('system_powered_by_block', ['region' => 'header', 'id' => 'header']);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertSession()->elementExists('xpath', '//tr[contains(@class, "region-title-header")]');
|
||||
|
||||
// Ensure hidden themes do not appear in the UI. Enable another non base
|
||||
// theme and place the local tasks block.
|
||||
$this->assertTrue(\Drupal::service('theme_handler')->themeExists('stark'), 'The stark base theme is enabled');
|
||||
$this->drupalPlaceBlock('local_tasks_block', ['region' => 'header', 'theme' => 'stark']);
|
||||
// We have to enable at least one extra theme that is not hidden so that
|
||||
// local tasks will show up. That's why we enable test_theme_theme.
|
||||
\Drupal::service('theme_installer')->install(['stable9', 'test_theme_theme']);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$theme_handler = \Drupal::service('theme_handler');
|
||||
$this->assertSession()->linkExists($theme_handler->getName('stark'));
|
||||
$this->assertSession()->linkExists($theme_handler->getName('test_theme_theme'));
|
||||
$this->assertSession()->linkNotExists($theme_handler->getName('stable9'));
|
||||
|
||||
// Ensure that a hidden theme cannot use the block demo page.
|
||||
$this->drupalGet('admin/structure/block/list/stable9');
|
||||
$this->assertSession()->statusCodeEquals(404);
|
||||
|
||||
// Ensure that a hidden theme set as the admin theme can use the block demo
|
||||
// page.
|
||||
\Drupal::configFactory()->getEditable('system.theme')->set('admin', 'stable9')->save();
|
||||
\Drupal::service('router.builder')->rebuildIfNeeded();
|
||||
$this->drupalPlaceBlock('local_tasks_block', ['region' => 'header', 'theme' => 'stable9']);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertSession()->linkExists($theme_handler->getName('stable9'));
|
||||
$this->drupalGet('admin/structure/block/list/stable9');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block categories on the listing page.
|
||||
*/
|
||||
public function testCandidateBlockList(): void {
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->elementExists('xpath', '//tr[.//td/div[text()="Display message"] and .//td[text()="Block test"] and .//td//a[contains(@href, "admin/structure/block/add/test_block_instantiation/stark")]]');
|
||||
|
||||
// Trigger the custom category addition in block_test_block_alter().
|
||||
$this->container->get('state')->set('block_test_info_alter', TRUE);
|
||||
$this->container->get('plugin.manager.block')->clearCachedDefinitions();
|
||||
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->elementExists('xpath', '//tr[.//td/div[text()="Display message"] and .//td[text()="Custom category"] and .//td//a[contains(@href, "admin/structure/block/add/test_block_instantiation/stark")]]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of unsatisfied context-aware blocks.
|
||||
*/
|
||||
public function testContextAwareUnsatisfiedBlocks(): void {
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Place block');
|
||||
// Verify that the context-aware test block does not appear.
|
||||
$this->assertSession()->elementNotExists('xpath', '//tr[.//td/div[text()="Test context-aware unsatisfied block"] and .//td[text()="Block test"] and .//td//a[contains(@href, "admin/structure/block/add/test_context_aware_unsatisfied/stark")]]');
|
||||
|
||||
$definition = \Drupal::service('plugin.manager.block')->getDefinition('test_context_aware_unsatisfied');
|
||||
$this->assertNotEmpty($definition, 'The context-aware test block does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of context-aware blocks.
|
||||
*/
|
||||
public function testContextAwareBlocks(): void {
|
||||
$expected_text = '<div id="test_context_aware--username">' . \Drupal::currentUser()->getAccountName() . '</div>';
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextNotContains('Test context-aware block');
|
||||
$this->assertSession()->responseNotContains($expected_text);
|
||||
|
||||
$block_url = 'admin/structure/block/add/test_context_aware/stark';
|
||||
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->elementExists('xpath', '//tr[.//td/div[text()="Test context-aware block"] and .//td[text()="Block test"] and .//td//a[contains(@href, "' . $block_url . '")]]');
|
||||
$definition = \Drupal::service('plugin.manager.block')->getDefinition('test_context_aware');
|
||||
$this->assertNotEmpty($definition, 'The context-aware test block exists.');
|
||||
$edit = [
|
||||
'region' => 'content',
|
||||
'settings[context_mapping][user]' => '@block_test.multiple_static_context:userB',
|
||||
];
|
||||
$this->drupalGet($block_url);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains('Test context-aware block');
|
||||
$this->assertSession()->pageTextContains('User context found.');
|
||||
$this->assertSession()->responseContains($expected_text);
|
||||
|
||||
// Test context mapping form element is not visible if there are no valid
|
||||
// context options for the block (the
|
||||
// test_context_aware_no_valid_context_options block has one context defined
|
||||
// which is not available for it on the Block Layout interface).
|
||||
$this->drupalGet('admin/structure/block/add/test_context_aware_no_valid_context_options/stark');
|
||||
$this->assertSession()->fieldNotExists('edit-settings-context-mapping-email');
|
||||
|
||||
// Test context mapping allows empty selection for optional contexts.
|
||||
$this->drupalGet('admin/structure/block/manage/stark_testcontextawareblock');
|
||||
$edit = [
|
||||
'settings[context_mapping][user]' => '',
|
||||
];
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->pageTextContains('No context mapping selected.');
|
||||
$this->assertSession()->pageTextNotContains('User context found.');
|
||||
|
||||
// Tests that conditions with missing context are not displayed.
|
||||
$this->drupalGet('admin/structure/block/manage/stark_testcontextawareblock');
|
||||
$this->assertSession()->responseNotContains('No existing type');
|
||||
$this->assertSession()->elementNotExists('xpath', '//*[@name="visibility[condition_test_no_existing_type][negate]"]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the BlockForm populates machine name correctly.
|
||||
*/
|
||||
public function testMachineNameSuggestion(): void {
|
||||
// Check the form uses the raw machine name suggestion when no instance
|
||||
// already exists.
|
||||
$url = 'admin/structure/block/add/test_block_instantiation/stark';
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->fieldValueEquals('id', 'stark_displaymessage');
|
||||
$edit = ['region' => 'content'];
|
||||
$this->drupalGet($url);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->assertSession()->pageTextContains('The block configuration has been saved.');
|
||||
|
||||
// Now, check to make sure the form starts by auto-incrementing correctly.
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->fieldValueEquals('id', 'stark_displaymessage_2');
|
||||
$this->drupalGet($url);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$this->assertSession()->pageTextContains('The block configuration has been saved.');
|
||||
|
||||
// And verify that it continues working beyond just the first two.
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->fieldValueEquals('id', 'stark_displaymessage_3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block placement indicator.
|
||||
*/
|
||||
public function testBlockPlacementIndicator(): void {
|
||||
// Test the block placement indicator with using the domain as URL language
|
||||
// indicator. This causes destination query parameters to be absolute URLs.
|
||||
\Drupal::service('module_installer')->install(['language', 'locale']);
|
||||
$this->container = \Drupal::getContainer();
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
$config = $this->config('language.types');
|
||||
$config->set('negotiation.language_interface.enabled', [
|
||||
LanguageNegotiationUrl::METHOD_ID => -10,
|
||||
]);
|
||||
$config->save();
|
||||
$config = $this->config('language.negotiation');
|
||||
$config->set('url.source', LanguageNegotiationUrl::CONFIG_DOMAIN);
|
||||
$config->set('url.domains', [
|
||||
'en' => \Drupal::request()->getHost(),
|
||||
'it' => 'it.example.com',
|
||||
]);
|
||||
$config->save();
|
||||
|
||||
// Select the 'Powered by Drupal' block to be placed.
|
||||
$block = [];
|
||||
$block['id'] = $this->randomMachineName();
|
||||
$block['theme'] = 'stark';
|
||||
$block['region'] = 'content';
|
||||
|
||||
// After adding a block, it will indicate which block was just added.
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block');
|
||||
$this->submitForm($block, 'Save block');
|
||||
$this->assertSession()->addressEquals('admin/structure/block/list/stark?block-placement=' . Html::getClass($block['id']));
|
||||
|
||||
// Resaving the block page will remove the block placement indicator.
|
||||
$this->submitForm([], 'Save blocks');
|
||||
$this->assertSession()->addressEquals('admin/structure/block/list/stark');
|
||||
|
||||
// Place another block and test the remove functionality works with the
|
||||
// block placement indicator. Click the first 'Place block' link to bring up
|
||||
// the list of blocks to place in the first available region.
|
||||
$this->clickLink('Place block');
|
||||
// Select the first available block, which is the 'test_block_instantiation'
|
||||
// plugin, with a default machine name 'stark-displaymessage' that is used
|
||||
// for the 'block-placement' querystring parameter.
|
||||
$this->clickLink('Place block');
|
||||
$this->submitForm([], 'Save block');
|
||||
$this->assertSession()->addressEquals('admin/structure/block/list/stark?block-placement=stark-displaymessage');
|
||||
|
||||
// Removing a block will remove the block placement indicator.
|
||||
$this->clickLink('Remove');
|
||||
$this->submitForm([], 'Remove');
|
||||
$this->assertSession()->addressEquals('admin/structure/block/list/stark');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if validation errors are passed plugin form to the parent form.
|
||||
*/
|
||||
public function testBlockValidateErrors(): void {
|
||||
$this->drupalGet('admin/structure/block/add/test_settings_validation/stark');
|
||||
$this->submitForm([
|
||||
'region' => 'content',
|
||||
'settings[digits]' => 'abc',
|
||||
], 'Save block');
|
||||
|
||||
$this->assertSession()->statusMessageContains('Only digits are allowed', 'error');
|
||||
$this->assertSession()->elementExists('xpath', '//div[contains(@class,"form-item-settings-digits")]/input[contains(@class,"error")]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the enable/disable routes are protected from CSRF.
|
||||
*/
|
||||
public function testRouteProtection(): void {
|
||||
// Get the first block generated in our setUp method.
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$block = reset($this->blocks);
|
||||
// Ensure that the enable and disable routes are protected.
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block->id() . '/disable');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block->id() . '/enable');
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that users without permission are not able to view broken blocks.
|
||||
*/
|
||||
public function testBrokenBlockVisibility(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$block = $this->drupalPlaceBlock('broken');
|
||||
|
||||
// Ensure that broken block configuration can be accessed.
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block->id());
|
||||
$assert_session->statusCodeEquals(200);
|
||||
|
||||
// Login as an admin user to the site.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
// Check that this user can view the Broken Block message.
|
||||
$assert_session->pageTextContains('This block is broken or missing. You may be missing content or you might need to install the original module.');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Visit the same page as anonymous.
|
||||
$this->drupalGet('');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
// Check that this user cannot view the Broken Block message.
|
||||
$assert_session->pageTextNotContains('This block is broken or missing. You may be missing content or you might need to install the original module.');
|
||||
|
||||
// Visit same page as an authorized user that does not have access to
|
||||
// administer blocks.
|
||||
$this->drupalLogin($this->drupalCreateUser(['access administration pages']));
|
||||
$this->drupalGet('');
|
||||
$assert_session->statusCodeEquals(200);
|
||||
// Check that this user cannot view the Broken Block message.
|
||||
$assert_session->pageTextNotContains('This block is broken or missing. You may be missing content or you might need to install the original module.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* @covers block_post_update_make_weight_integer
|
||||
* @group block
|
||||
*/
|
||||
class BlockWeightUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-10.3.0.filled.standard.php.gz',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests update path for blocks' `weight` property.
|
||||
*/
|
||||
public function testRunUpdates() {
|
||||
// Find a block and change it to have a null weight.
|
||||
/** @var \Drupal\Core\Database\Connection $database */
|
||||
$database = $this->container->get('database');
|
||||
$block = $database->select('config', 'c')
|
||||
->fields('c', ['data'])
|
||||
->condition('name', 'block.block.claro_content')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$block = unserialize($block);
|
||||
$block['weight'] = NULL;
|
||||
$database->update('config')
|
||||
->fields([
|
||||
'data' => serialize($block),
|
||||
])
|
||||
->condition('name', 'block.block.claro_content')
|
||||
->execute();
|
||||
|
||||
$this->assertNull(Block::load('claro_content')->get('weight'));
|
||||
$this->runUpdates();
|
||||
$this->assertSame(0, Block::load('claro_content')->get('weight'));
|
||||
}
|
||||
|
||||
}
|
||||
176
web/core/modules/block/tests/src/Functional/BlockXssTest.php
Normal file
176
web/core/modules/block/tests/src/Functional/BlockXssTest.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\block_content\Entity\BlockContent;
|
||||
use Drupal\block_content\Entity\BlockContentType;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\system\Entity\Menu;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\views\Entity\View;
|
||||
|
||||
/**
|
||||
* Tests that the block module properly escapes block descriptions.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockXssTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_content', 'menu_ui', 'views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests that nothing is escaped other than the blocks explicitly tested.
|
||||
*/
|
||||
public function testNoUnexpectedEscaping(): void {
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
]));
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->assertNoEscaped('<');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests XSS in title.
|
||||
*/
|
||||
public function testXssInTitle(): void {
|
||||
$this->drupalPlaceBlock('system_powered_by_block', [
|
||||
'label' => '<script>alert("XSS label");</script>',
|
||||
'label_display' => 'visible',
|
||||
]);
|
||||
|
||||
$this->drupalGet('');
|
||||
// Check that the block title was properly sanitized when rendered.
|
||||
$this->assertSession()->assertEscaped('<script>alert("XSS label");</script>');
|
||||
$this->assertSession()->responseNotContains('<script>alert("XSS label");</script>');
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
]));
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalGet('admin/structure/block/list/' . $default_theme);
|
||||
// Check that the block title was properly sanitized in Block Plugin UI
|
||||
// Admin page.
|
||||
$this->assertSession()->assertEscaped('<script>alert("XSS label");</script>');
|
||||
$this->assertSession()->responseNotContains("<script>alert('XSS subject');</script>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests various modules that provide blocks for XSS.
|
||||
*/
|
||||
public function testBlockXss(): void {
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
]));
|
||||
|
||||
$this->doViewTest();
|
||||
$this->doMenuTest();
|
||||
$this->doBlockContentTest();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('Place block');
|
||||
// Check that the page does not have double escaped HTML tags.
|
||||
$this->assertSession()->responseNotContains('&lt;');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests XSS coming from View block labels.
|
||||
*/
|
||||
protected function doViewTest(): void {
|
||||
// Create a View without a custom label for its block Display. The
|
||||
// admin_label of the block then becomes just the View's label.
|
||||
$view = View::create([
|
||||
'id' => $this->randomMachineName(),
|
||||
'label' => '<script>alert("view1");</script>',
|
||||
]);
|
||||
$view->addDisplay('block');
|
||||
$view->save();
|
||||
|
||||
// Create a View with a custom label for its block Display. The
|
||||
// admin_label of the block then becomes the View's label combined with
|
||||
// the Display's label.
|
||||
$view = View::create([
|
||||
'id' => $this->randomMachineName(),
|
||||
'label' => '<script>alert("view2");</script>',
|
||||
]);
|
||||
$view->addDisplay('block', 'Fish & chips');
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('Place block');
|
||||
|
||||
// \Drupal\views\Plugin\Derivative\ViewsBlock::getDerivativeDefinitions()
|
||||
// has a different code path for an admin label based only on the View
|
||||
// label versus one based on both the View label and the Display label.
|
||||
// Ensure that this test is covering both code paths by asserting the
|
||||
// absence of a ":" for the first View and the presence of a ":" for the
|
||||
// second one. Note that the second assertion is redundant with the one
|
||||
// further down which also checks for the Display label, but is included
|
||||
// here for clarity.
|
||||
$this->assertSession()->assertNoEscaped('<script>alert("view1");</script>:');
|
||||
$this->assertSession()->assertEscaped('<script>alert("view2");</script>:');
|
||||
|
||||
// Assert that the blocks have their admin labels escaped and
|
||||
// don't appear anywhere unescaped.
|
||||
$this->assertSession()->assertEscaped('<script>alert("view1");</script>');
|
||||
$this->assertSession()->responseNotContains('<script>alert("view1");</script>');
|
||||
$this->assertSession()->assertEscaped('<script>alert("view2");</script>: Fish & chips');
|
||||
$this->assertSession()->responseNotContains('<script>alert("view2");</script>');
|
||||
$this->assertSession()->responseNotContains('Fish & chips');
|
||||
|
||||
// Assert the Display label doesn't appear anywhere double escaped.
|
||||
$this->assertSession()->responseNotContains('Fish & chips');
|
||||
$this->assertSession()->responseNotContains('Fish &amp; chips');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests XSS coming from Menu block labels.
|
||||
*/
|
||||
protected function doMenuTest(): void {
|
||||
Menu::create([
|
||||
'id' => $this->randomMachineName(),
|
||||
'label' => '<script>alert("menu");</script>',
|
||||
])->save();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('Place block');
|
||||
|
||||
$this->assertSession()->assertEscaped('<script>alert("menu");</script>');
|
||||
$this->assertSession()->responseNotContains('<script>alert("menu");</script>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests XSS coming from Block Content block info.
|
||||
*/
|
||||
protected function doBlockContentTest(): void {
|
||||
BlockContentType::create([
|
||||
'id' => 'basic',
|
||||
'label' => 'basic',
|
||||
'revision' => TRUE,
|
||||
])->save();
|
||||
BlockContent::create([
|
||||
'type' => 'basic',
|
||||
'info' => '<script>alert("block_content");</script>',
|
||||
])->save();
|
||||
|
||||
$this->drupalGet(Url::fromRoute('block.admin_display'));
|
||||
$this->clickLink('Place block');
|
||||
|
||||
$this->assertSession()->assertEscaped('<script>alert("block_content");</script>');
|
||||
$this->assertSession()->responseNotContains('<script>alert("block_content");</script>');
|
||||
}
|
||||
|
||||
}
|
||||
14
web/core/modules/block/tests/src/Functional/GenericTest.php
Normal file
14
web/core/modules/block/tests/src/Functional/GenericTest.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
|
||||
|
||||
/**
|
||||
* Generic module test for block.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class GenericTest extends GenericModuleTestBase {}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the block administration page for a non-default theme.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class NonDefaultBlockAdminTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests non-default theme admin.
|
||||
*/
|
||||
public function testNonDefaultBlockAdmin(): void {
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'administer themes',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
$new_theme = 'olivero';
|
||||
\Drupal::service('theme_installer')->install([$new_theme]);
|
||||
// Ensure that the Olivero tab is shown.
|
||||
$this->drupalGet('admin/structure/block/list/' . $new_theme);
|
||||
$this->assertSession()->pageTextContains('Olivero');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockJsonAnonTest extends BlockResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockJsonBasicAuthTest extends BlockResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockJsonCookieTest extends BlockResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\ConfigEntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* Resource test base for the block entity.
|
||||
*/
|
||||
abstract class BlockResourceTestBase extends ConfigEntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'block';
|
||||
|
||||
/**
|
||||
* @var \Drupal\block\BlockInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->entity->setVisibilityConfig('user_role', [])->save();
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
$this->grantPermissionsToTestedRole(['administer blocks']);
|
||||
break;
|
||||
|
||||
case 'PATCH':
|
||||
$this->grantPermissionsToTestedRole(['administer blocks']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$block = Block::create([
|
||||
'plugin' => 'llama_block',
|
||||
'region' => 'header',
|
||||
'id' => 'llama',
|
||||
'theme' => 'stark',
|
||||
]);
|
||||
// All blocks can be viewed by the anonymous user by default. An interesting
|
||||
// side effect of this is that any anonymous user is also able to read the
|
||||
// corresponding block config entity via REST, even if an authentication
|
||||
// provider is configured for the block config entity REST resource! In
|
||||
// other words: Block entities do not distinguish between 'view' as in
|
||||
// "render on a page" and 'view' as in "read the configuration".
|
||||
// This prevents that.
|
||||
// @todo Fix this in https://www.drupal.org/node/2820315.
|
||||
$block->setVisibilityConfig('user_role', [
|
||||
'id' => 'user_role',
|
||||
'roles' => ['non-existing-role' => 'non-existing-role'],
|
||||
'negate' => FALSE,
|
||||
'context_mapping' => [
|
||||
'user' => '@user.current_user_context:current_user',
|
||||
],
|
||||
]);
|
||||
$block->save();
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$normalization = [
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'id' => 'llama',
|
||||
'weight' => 0,
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'dependencies' => [
|
||||
'theme' => [
|
||||
'stark',
|
||||
],
|
||||
],
|
||||
'theme' => 'stark',
|
||||
'region' => 'header',
|
||||
'provider' => NULL,
|
||||
'plugin' => 'llama_block',
|
||||
'settings' => [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => 'visible',
|
||||
],
|
||||
'visibility' => [],
|
||||
];
|
||||
|
||||
return $normalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// @see ::createEntity()
|
||||
return ['url.site'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
// Because the 'user.permissions' cache context is missing, the cache tag
|
||||
// for the anonymous user role is never added automatically.
|
||||
return array_values(array_diff(parent::getExpectedCacheTags(), ['config:user.role.anonymous']));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
return "The block visibility condition 'user_role' denied access.";
|
||||
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Fix this in https://www.drupal.org/node/2820315.
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
return (new CacheableMetadata())
|
||||
->setCacheTags(['4xx-response', 'http_response'])
|
||||
->setCacheContexts(['user.roles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedEntityAccessCacheability($is_authenticated) {
|
||||
// @see \Drupal\block\BlockAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedEntityAccessCacheability($is_authenticated)
|
||||
->addCacheTags([
|
||||
'config:block.block.llama',
|
||||
$is_authenticated ? 'user:2' : 'user:0',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockXmlAnonTest extends BlockResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockXmlBasicAuthTest extends BlockResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockXmlCookieTest extends BlockResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Update;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests update path for the `depth` setting of menu blocks.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
final class MenuBlockDepthTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles(): void {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-10.3.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/add-menu-block-with-zero-depth.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that menu blocks with a `depth` setting of 0 are changed to NULL.
|
||||
*/
|
||||
public function testUpdate(): void {
|
||||
$settings = Block::load('olivero_account_menu')?->get('settings');
|
||||
$this->assertIsArray($settings);
|
||||
$this->assertSame(0, $settings['depth']);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
$settings = Block::load('olivero_account_menu')?->get('settings');
|
||||
$this->assertIsArray($settings);
|
||||
$this->assertNull($settings['depth']);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,412 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Functional\Views;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\block\Functional\AssertBlockAppearsTrait;
|
||||
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\views\Functional\ViewTestBase;
|
||||
use Drupal\views\Entity\View;
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
|
||||
/**
|
||||
* Tests the block display plugin.
|
||||
*
|
||||
* @group block
|
||||
* @see \Drupal\views\Plugin\views\display\Block
|
||||
*/
|
||||
class DisplayBlockTest extends ViewTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
use AssertBlockAppearsTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'block_test_views',
|
||||
'test_page_test',
|
||||
'contextual',
|
||||
'views_ui',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view_block', 'test_view_block2'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE, $modules = ['block_test_views']): void {
|
||||
parent::setUp($import_test_views, $modules);
|
||||
|
||||
$this->enableViewsTestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests default and content block categories.
|
||||
*/
|
||||
public function testBlockCategory(): void {
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer views',
|
||||
'administer blocks',
|
||||
]));
|
||||
|
||||
// Create a new view in the UI.
|
||||
$edit = [];
|
||||
$edit['label'] = $this->randomString();
|
||||
$edit['id'] = $this->randomMachineName();
|
||||
$edit['show[wizard_key]'] = 'standard:views_test_data';
|
||||
$edit['description'] = $this->randomString();
|
||||
$edit['block[create]'] = TRUE;
|
||||
$edit['block[style][row_plugin]'] = 'fields';
|
||||
$this->drupalGet('admin/structure/views/add');
|
||||
$this->submitForm($edit, 'Save and edit');
|
||||
|
||||
$pattern = '//tr[.//td[text()=:category] and .//td//a[contains(@href, :href)]]';
|
||||
$arguments = [
|
||||
':href' => Url::fromRoute('block.admin_add', [
|
||||
'plugin_id' => 'views_block:' . $edit['id'] . '-block_1',
|
||||
'theme' => 'stark',
|
||||
])->toString(),
|
||||
':category' => 'Lists (Views)',
|
||||
];
|
||||
|
||||
// Test that the block was given a default category corresponding to its
|
||||
// base table.
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->elementExists('xpath', $this->assertSession()->buildXPathQuery($pattern, $arguments));
|
||||
|
||||
// Duplicate the block before changing the category.
|
||||
$this->drupalGet('admin/structure/views/view/' . $edit['id'] . '/edit/block_1');
|
||||
$this->submitForm([], 'Duplicate Block');
|
||||
$this->assertSession()->addressEquals('admin/structure/views/view/' . $edit['id'] . '/edit/block_2');
|
||||
|
||||
// Change the block category to a random string.
|
||||
$this->drupalGet('admin/structure/views/view/' . $edit['id'] . '/edit/block_1');
|
||||
$this->assertSession()->elementTextEquals('named', ['id', 'views-block-1-block-category'], 'Lists (Views)');
|
||||
$this->clickLink('Lists (Views)');
|
||||
$category = $this->randomString();
|
||||
$this->submitForm(['block_category' => $category], 'Apply');
|
||||
|
||||
// Duplicate the block after changing the category.
|
||||
$this->submitForm([], 'Duplicate Block');
|
||||
$this->assertSession()->addressEquals('admin/structure/views/view/' . $edit['id'] . '/edit/block_3');
|
||||
|
||||
$this->submitForm([], 'Save');
|
||||
|
||||
// Test that the blocks are listed under the correct categories.
|
||||
$arguments[':category'] = $category;
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->clickLink('Place block');
|
||||
$this->assertSession()->elementExists('xpath', $this->assertSession()->buildXPathQuery($pattern, $arguments));
|
||||
|
||||
// Test that the first duplicated test block remains in the original
|
||||
// category.
|
||||
$arguments = [
|
||||
':href' => Url::fromRoute('block.admin_add', [
|
||||
'plugin_id' => 'views_block:' . $edit['id'] . '-block_2',
|
||||
'theme' => 'stark',
|
||||
])->toString(),
|
||||
':category' => 'Lists (Views)',
|
||||
];
|
||||
$this->assertSession()->elementExists('xpath', $this->assertSession()->buildXPathQuery($pattern, $arguments));
|
||||
|
||||
// Test that the second duplicated test block appears in the custom
|
||||
// category.
|
||||
$arguments = [
|
||||
':href' => Url::fromRoute('block.admin_add', [
|
||||
'plugin_id' => 'views_block:' . $edit['id'] . '-block_3',
|
||||
'theme' => 'stark',
|
||||
])->toString(),
|
||||
':category' => $category,
|
||||
];
|
||||
$this->assertSession()->elementExists('xpath', $this->assertSession()->buildXPathQuery($pattern, $arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests removing a block display.
|
||||
*/
|
||||
public function testDeleteBlockDisplay(): void {
|
||||
// To test all combinations possible we first place create two instances
|
||||
// of the block display of the first view.
|
||||
$block_1 = $this->drupalPlaceBlock('views_block:test_view_block-block_1', ['label' => 'test_view_block-block_1:1']);
|
||||
$block_2 = $this->drupalPlaceBlock('views_block:test_view_block-block_1', ['label' => 'test_view_block-block_1:2']);
|
||||
|
||||
// Then we add one instance of blocks for each of the two displays of the
|
||||
// second view.
|
||||
$block_3 = $this->drupalPlaceBlock('views_block:test_view_block2-block_1', ['label' => 'test_view_block2-block_1']);
|
||||
$block_4 = $this->drupalPlaceBlock('views_block:test_view_block2-block_2', ['label' => 'test_view_block2-block_2']);
|
||||
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertBlockAppears($block_1);
|
||||
$this->assertBlockAppears($block_2);
|
||||
$this->assertBlockAppears($block_3);
|
||||
$this->assertBlockAppears($block_4);
|
||||
|
||||
$block_storage = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
|
||||
// Remove the block display, so both block entities from the first view
|
||||
// should both disappear.
|
||||
$view = Views::getView('test_view_block');
|
||||
$view->initDisplay();
|
||||
$view->displayHandlers->remove('block_1');
|
||||
$view->storage->save();
|
||||
|
||||
$this->assertNull($block_storage->load($block_1->id()), 'The block for this display was removed.');
|
||||
$this->assertNull($block_storage->load($block_2->id()), 'The block for this display was removed.');
|
||||
$this->assertNotEmpty($block_storage->load($block_3->id()), 'A block from another view was unaffected.');
|
||||
$this->assertNotEmpty($block_storage->load($block_4->id()), 'A block from another view was unaffected.');
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertNoBlockAppears($block_1);
|
||||
$this->assertNoBlockAppears($block_2);
|
||||
$this->assertBlockAppears($block_3);
|
||||
$this->assertBlockAppears($block_4);
|
||||
|
||||
// Remove the first block display of the second view and ensure the block
|
||||
// instance of the second block display still exists.
|
||||
$view = Views::getView('test_view_block2');
|
||||
$view->initDisplay();
|
||||
$view->displayHandlers->remove('block_1');
|
||||
$view->storage->save();
|
||||
|
||||
$this->assertNull($block_storage->load($block_3->id()), 'The block for this display was removed.');
|
||||
$this->assertNotEmpty($block_storage->load($block_4->id()), 'A block from another display on the same view was unaffected.');
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertNoBlockAppears($block_3);
|
||||
$this->assertBlockAppears($block_4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block form for a Views block.
|
||||
*/
|
||||
public function testViewsBlockForm(): void {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer blocks']));
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalGet('admin/structure/block/add/views_block:test_view_block-block_1/' . $default_theme);
|
||||
$this->assertSession()->fieldNotExists('label');
|
||||
// Test that the machine name field is hidden from display and has been
|
||||
// saved as expected from the default value.
|
||||
$this->assertSession()->fieldNotExists('edit-machine-name', NULL);
|
||||
|
||||
// Save the block.
|
||||
$edit = ['region' => 'content'];
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$storage = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
$block = $storage->load($default_theme . '_views_block__test_view_block_block_1');
|
||||
// This will only return a result if our new block has been created with the
|
||||
// expected machine name.
|
||||
$this->assertNotEmpty($block, 'The expected block was loaded.');
|
||||
|
||||
for ($i = 2; $i <= 3; $i++) {
|
||||
// Place the same block again and make sure we have a new ID.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:test_view_block-block_1/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
$block = $storage->load($default_theme . '_views_block__test_view_block_block_1_' . $i);
|
||||
// This will only return a result if our new block has been created with
|
||||
// the expected machine name.
|
||||
$this->assertNotEmpty($block, 'The expected block was loaded.');
|
||||
}
|
||||
|
||||
// Tests the override capability of items per page.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:test_view_block-block_1/' . $default_theme);
|
||||
$edit = ['region' => 'content'];
|
||||
$edit['settings[override][items_per_page]'] = 10;
|
||||
|
||||
$this->drupalGet('admin/structure/block/add/views_block:test_view_block-block_1/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
$block = $storage->load($default_theme . '_views_block__test_view_block_block_1_4');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEquals(10, $config['items_per_page'], "'Items per page' is properly saved.");
|
||||
|
||||
$edit['settings[override][items_per_page]'] = 5;
|
||||
$this->drupalGet('admin/structure/block/manage/' . $default_theme . '_views_block__test_view_block_block_1_4');
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
$block = $storage->load($default_theme . '_views_block__test_view_block_block_1_4');
|
||||
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEquals(5, $config['items_per_page'], "'Items per page' is properly saved.");
|
||||
|
||||
// Tests the override of the label capability.
|
||||
$edit = ['region' => 'content'];
|
||||
$edit['settings[views_label_checkbox]'] = 1;
|
||||
$edit['settings[views_label]'] = 'Custom title';
|
||||
$this->drupalGet('admin/structure/block/add/views_block:test_view_block-block_1/' . $default_theme);
|
||||
$this->submitForm($edit, 'Save block');
|
||||
|
||||
$block = $storage->load($default_theme . '_views_block__test_view_block_block_1_5');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEquals('Custom title', $config['views_label'], "'Label' is properly saved.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the actual rendering of the views block.
|
||||
*/
|
||||
public function testBlockRendering(): void {
|
||||
// Create a block and set a custom title.
|
||||
$block = $this->drupalPlaceBlock('views_block:test_view_block-block_1', [
|
||||
'label' => 'test_view_block-block_1:1',
|
||||
'views_label' => 'Custom title',
|
||||
'region' => 'sidebar_first',
|
||||
]);
|
||||
$block_xpath = $this->assertSession()->buildXPathQuery('//aside[contains(@class, "layout-sidebar-first")]//div[@id = :id]', [
|
||||
':id' => 'block-' . $block->id(),
|
||||
]);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->elementTextEquals('xpath', "{$block_xpath}/h2", 'Custom title');
|
||||
$this->assertSession()->elementTextEquals('xpath', "{$block_xpath}//footer", 'Custom title');
|
||||
|
||||
// Don't override the title anymore.
|
||||
$plugin = $block->getPlugin();
|
||||
$plugin->setConfigurationValue('views_label', '');
|
||||
$block->save();
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->elementTextEquals('xpath', "{$block_xpath}/h2", 'test_view_block');
|
||||
$this->assertSession()->elementTextEquals('xpath', "{$block_xpath}//footer", 'test_view_block');
|
||||
|
||||
// Hide the title.
|
||||
$block->getPlugin()->setConfigurationValue('label_display', FALSE);
|
||||
$block->save();
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->elementNotExists('xpath', "{$block_xpath}/h2");
|
||||
|
||||
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:system.site', 'config:views.view.test_view_block', 'http_response', 'CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:form', 'rendered']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the various test cases of empty block rendering.
|
||||
*/
|
||||
public function testBlockEmptyRendering(): void {
|
||||
$url = new Url('test_page_test.test_page');
|
||||
// Remove all views_test_data entries.
|
||||
\Drupal::database()->truncate('views_test_data')->execute();
|
||||
/** @var \Drupal\views\ViewEntityInterface $view */
|
||||
$view = View::load('test_view_block');
|
||||
$view->invalidateCaches();
|
||||
|
||||
$block = $this->drupalPlaceBlock('views_block:test_view_block-block_1', ['label' => 'test_view_block-block_1:1', 'views_label' => 'Custom title']);
|
||||
$block_xpath = $this->assertSession()->buildXPathQuery('//div[@id = :id]', [
|
||||
':id' => 'block-' . $block->id(),
|
||||
]);
|
||||
$this->drupalGet('');
|
||||
$this->assertSession()->elementsCount('xpath', $block_xpath, 1);
|
||||
|
||||
$display = &$view->getDisplay('block_1');
|
||||
$display['display_options']['block_hide_empty'] = TRUE;
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->elementNotExists('xpath', $block_xpath);
|
||||
// Ensure that the view cacheability metadata is propagated even, for an
|
||||
// empty block.
|
||||
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block', 'http_response', 'rendered']));
|
||||
$this->assertCacheContexts(['url.query_args:_wrapper_format']);
|
||||
|
||||
// Add a header displayed on empty result.
|
||||
$display = &$view->getDisplay('block_1');
|
||||
$display['display_options']['defaults']['header'] = FALSE;
|
||||
$display['display_options']['header']['example'] = [
|
||||
'field' => 'area_text_custom',
|
||||
'id' => 'area_text_custom',
|
||||
'table' => 'views',
|
||||
'plugin_id' => 'text_custom',
|
||||
'content' => 'test header',
|
||||
'empty' => TRUE,
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->elementsCount('xpath', $block_xpath, 1);
|
||||
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block', 'http_response', 'rendered']));
|
||||
$this->assertCacheContexts(['url.query_args:_wrapper_format']);
|
||||
|
||||
// Hide the header on empty results.
|
||||
$display = &$view->getDisplay('block_1');
|
||||
$display['display_options']['defaults']['header'] = FALSE;
|
||||
$display['display_options']['header']['example'] = [
|
||||
'field' => 'area_text_custom',
|
||||
'id' => 'area_text_custom',
|
||||
'table' => 'views',
|
||||
'plugin_id' => 'text_custom',
|
||||
'content' => 'test header',
|
||||
'empty' => FALSE,
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->elementNotExists('xpath', $block_xpath);
|
||||
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block', 'http_response', 'rendered']));
|
||||
$this->assertCacheContexts(['url.query_args:_wrapper_format']);
|
||||
|
||||
// Add an empty text.
|
||||
$display = &$view->getDisplay('block_1');
|
||||
$display['display_options']['defaults']['empty'] = FALSE;
|
||||
$display['display_options']['empty']['example'] = [
|
||||
'field' => 'area_text_custom',
|
||||
'id' => 'area_text_custom',
|
||||
'table' => 'views',
|
||||
'plugin_id' => 'text_custom',
|
||||
'content' => 'test empty',
|
||||
];
|
||||
$view->save();
|
||||
|
||||
$this->drupalGet($url);
|
||||
$this->assertSession()->elementsCount('xpath', $block_xpath, 1);
|
||||
$this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block', 'http_response', 'rendered']));
|
||||
$this->assertCacheContexts(['url.query_args:_wrapper_format']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the contextual links on a Views block.
|
||||
*/
|
||||
public function testBlockContextualLinks(): void {
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer views',
|
||||
'access contextual links',
|
||||
'administer blocks',
|
||||
]));
|
||||
$block = $this->drupalPlaceBlock('views_block:test_view_block-block_1');
|
||||
$cached_block = $this->drupalPlaceBlock('views_block:test_view_block-block_1');
|
||||
$this->drupalGet('test-page');
|
||||
|
||||
$id = 'block:block=' . $block->id() . ':langcode=en|entity.view.edit_form:view=test_view_block:location=block&name=test_view_block&display_id=block_1&langcode=en';
|
||||
$id_token = Crypt::hmacBase64($id, Settings::getHashSalt() . $this->container->get('private_key')->get());
|
||||
$cached_id = 'block:block=' . $cached_block->id() . ':langcode=en|entity.view.edit_form:view=test_view_block:location=block&name=test_view_block&display_id=block_1&langcode=en';
|
||||
$cached_id_token = Crypt::hmacBase64($cached_id, Settings::getHashSalt() . $this->container->get('private_key')->get());
|
||||
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
|
||||
// Check existence of the contextual link placeholders.
|
||||
$this->assertSession()->responseContains('<div' . new Attribute(['data-contextual-id' => $id, 'data-contextual-token' => $id_token, 'data-drupal-ajax-container' => '']) . '></div>');
|
||||
$this->assertSession()->responseContains('<div' . new Attribute(['data-contextual-id' => $cached_id, 'data-contextual-token' => $cached_id_token, 'data-drupal-ajax-container' => '']) . '></div>');
|
||||
|
||||
// Get server-rendered contextual links.
|
||||
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks()
|
||||
$post = ['ids[0]' => $id, 'ids[1]' => $cached_id, 'tokens[0]' => $id_token, 'tokens[1]' => $cached_id_token];
|
||||
$url = 'contextual/render?_format=json,destination=test-page';
|
||||
$this->getSession()->getDriver()->getClient()->request('POST', $url, $post);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$json = Json::decode($this->getSession()->getPage()->getContent());
|
||||
$this->assertSame('<ul class="contextual-links"><li><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '/delete">Remove block</a></li><li><a href="' . base_path() . 'admin/structure/views/view/test_view_block/edit/block_1">Edit view</a></li></ul>', $json[$id]);
|
||||
$this->assertSame('<ul class="contextual-links"><li><a href="' . base_path() . 'admin/structure/block/manage/' . $cached_block->id() . '">Configure block</a></li><li><a href="' . base_path() . 'admin/structure/block/manage/' . $cached_block->id() . '/delete">Remove block</a></li><li><a href="' . base_path() . 'admin/structure/views/view/test_view_block/edit/block_1">Edit view</a></li></ul>', $json[$cached_id]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the JS functionality in the block add form.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockAddTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Tests the AJAX for the theme selector.
|
||||
*/
|
||||
public function testBlockAddThemeSelector(): void {
|
||||
\Drupal::service('theme_installer')->install(['claro']);
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
]));
|
||||
|
||||
$this->drupalGet('admin/structure/block/add/system_powered_by_block');
|
||||
$assert_session = $this->assertSession();
|
||||
// Pick a theme with a region that does not exist in another theme.
|
||||
$assert_session->selectExists('Theme')->selectOption('claro');
|
||||
$assert_session->assertWaitOnAjaxRequest();
|
||||
$assert_session->selectExists('Region')->selectOption('pre_content');
|
||||
// Switch to a theme that doesn't contain the region selected above.
|
||||
$assert_session->selectExists('Theme')->selectOption('stark');
|
||||
$assert_session->assertWaitOnAjaxRequest();
|
||||
$assert_session->pageTextNotContains('The submitted value Pre-content in the Region element is not allowed.');
|
||||
$assert_session->optionExists('Region', '- Select -');
|
||||
// Check that the summary line is not present in the title.
|
||||
$summary_text = $this->getSession()->getPage()->find('css', 'li.vertical-tabs__menu-item:nth-child(1) > a:nth-child(1) > span:nth-child(2)')->getText();
|
||||
$assert_session->elementTextContains('css', '.vertical-tabs__menu-item-title', 'Response status');
|
||||
$assert_session->elementTextNotContains('css', '.vertical-tabs__menu-item-title', $summary_text);
|
||||
|
||||
// Search for the "Pages" tab link and click it
|
||||
$this->getSession()->getPage()->find('css', 'a[href="#edit-visibility-request-path"]')->click();
|
||||
// Check that the corresponding form section is open and visible.
|
||||
$form_section = $this->getSession()->getPage()->find('css', '#edit-visibility-request-path');
|
||||
$this->assertNotEmpty($form_section, 'The "Pages" form section exists.');
|
||||
$this->assertTrue($form_section->isVisible(), 'The "Pages" form section is visible after clicking the tab.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the contextual links added while rendering the block.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockContextualLinksTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['user', 'block', 'contextual'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* Block id of the block.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $blockId;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
'access administration pages',
|
||||
'access contextual links',
|
||||
]));
|
||||
$this->blockId = $this->defaultTheme . '_powered';
|
||||
$this->placeBlock('system_powered_by_block', [
|
||||
'id' => $this->blockId,
|
||||
'region' => 'content',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that remove/configure contextual links are present in the block.
|
||||
*/
|
||||
public function testBlockContextualRemoveLinks(): void {
|
||||
$this->drupalGet('<front>');
|
||||
$contextual_id = "[data-contextual-id^='block:block=$this->blockId:langcode=en']";
|
||||
$this->assertSession()->waitForElement('css', "$contextual_id .contextual-links");
|
||||
|
||||
$expected_configure_block_link = base_path() . 'admin/structure/block/manage/' . $this->blockId;
|
||||
$actual_configure_block_link = parse_url($this->getSession()->getPage()->findLink('Configure block')->getAttribute('href'));
|
||||
$this->assertEquals($expected_configure_block_link, $actual_configure_block_link['path']);
|
||||
|
||||
$expected_remove_block_link = base_path() . 'admin/structure/block/manage/' . $this->blockId . '/delete';
|
||||
$actual_remove_block_link = parse_url($this->getSession()->getPage()->findLink('Remove block')->getAttribute('href'));
|
||||
$this->assertEquals($expected_remove_block_link, $actual_remove_block_link['path']);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests drag and drop blocks on block layout page.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockDragTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['user', 'block', 'node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'olivero';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests drag and drop blocks.
|
||||
*/
|
||||
public function testDragAndDropBlocks(): void {
|
||||
// Resize window to work around https://github.com/bitovi/syn/issues/164.
|
||||
$this->getSession()->resizeWindow(1024, 2048);
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$assertSession = $this->assertSession();
|
||||
$session = $this->getSession();
|
||||
$page = $session->getPage();
|
||||
|
||||
// Test if drag orientation on block layout page was applied with success.
|
||||
$this->assertNotEmpty($assertSession->waitForElementVisible('css', '.tabledrag-handle-y'));
|
||||
|
||||
// Dragging main-menu and status messages to header region.
|
||||
$siteBranding = $this->getDragRow($page, 'edit-blocks-olivero-site-branding');
|
||||
$mainMenuRow = $this->getDragRow($page, 'edit-blocks-olivero-main-menu');
|
||||
$mainMenuRow->dragTo($siteBranding);
|
||||
$messages = $this->getDragRow($page, 'edit-blocks-olivero-messages');
|
||||
$messages->dragTo($siteBranding);
|
||||
|
||||
// Test if both blocks above was positioned on the header region.
|
||||
$this->assertEquals(
|
||||
'header',
|
||||
$page->findField('edit-blocks-olivero-main-menu-region')->getValue(),
|
||||
'Main menu should be positioned on header region'
|
||||
);
|
||||
$this->assertEquals(
|
||||
'header',
|
||||
$page->findField('edit-blocks-olivero-messages-region')->getValue(),
|
||||
'Status messages should be positioned on header region'
|
||||
);
|
||||
|
||||
// Check if the message unsaved changed appears.
|
||||
$assertSession->pageTextContains('You have unsaved changes.');
|
||||
|
||||
// Test if the message for empty regions appear after drag the unique block
|
||||
// on the region.
|
||||
$noBlockMessage = $page->find('css', 'tr[data-drupal-selector="edit-blocks-region-primary-menu-message"] td')->getText();
|
||||
$this->assertSession()->assert($noBlockMessage === 'No blocks in this region', 'Region primary menu should be empty.');
|
||||
|
||||
// Testing drag row to an empty region.
|
||||
$pageTitle = $this->getDragRow($page, 'edit-blocks-olivero-page-title');
|
||||
$heroRegion = $page->find('css', 'tr[data-drupal-selector="edit-blocks-region-hero-message"]');
|
||||
$pageTitle->dragTo($heroRegion);
|
||||
$this->assertSession()->assert(
|
||||
$page->find('css', 'tr[data-drupal-selector="edit-blocks-region-hero-message"] td')->getText() !== 'No blocks in this region',
|
||||
"Region here shouldn't be empty"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to find block tr element on the page.
|
||||
*/
|
||||
private function getDragRow($page, $blockId) {
|
||||
return $page->find('css', '#blocks tbody tr[data-drupal-selector="' . $blockId . '"] a.tabledrag-handle');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\FunctionalJavascript;
|
||||
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the JavaScript functionality of the block add filter.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockFilterTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['user', 'block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'administer blocks',
|
||||
]);
|
||||
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block filter.
|
||||
*/
|
||||
public function testBlockFilter(): void {
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$assertSession = $this->assertSession();
|
||||
$session = $this->getSession();
|
||||
$page = $session->getPage();
|
||||
|
||||
// Find the block filter field on the add-block dialog.
|
||||
$page->find('css', '#edit-blocks-region-header-title')->click();
|
||||
$filter = $assertSession->waitForElement('css', '.block-filter-text');
|
||||
|
||||
// Get all block rows, for assertions later.
|
||||
$block_rows = $page->findAll('css', '.block-add-table tbody tr');
|
||||
|
||||
// Test block filter reduces the number of visible rows.
|
||||
$filter->setValue('ad');
|
||||
$session->wait(10000, 'jQuery("#drupal-live-announce").html().indexOf("blocks are available") > -1');
|
||||
$visible_rows = $this->filterVisibleElements($block_rows);
|
||||
if (count($block_rows) > 0) {
|
||||
$this->assertNotSameSize($block_rows, $visible_rows);
|
||||
}
|
||||
|
||||
// Test Drupal.announce() message when multiple matches are expected.
|
||||
$expected_message = count($visible_rows) . ' blocks are available in the modified list.';
|
||||
$this->assertAnnounceContains($expected_message);
|
||||
|
||||
// Test Drupal.announce() message when only one match is expected.
|
||||
$filter->setValue('Powered by');
|
||||
$session->wait(10000, 'jQuery("#drupal-live-announce").html().indexOf("block is available") > -1');
|
||||
$visible_rows = $this->filterVisibleElements($block_rows);
|
||||
$this->assertCount(1, $visible_rows);
|
||||
$expected_message = '1 block is available in the modified list.';
|
||||
$this->assertAnnounceContains($expected_message);
|
||||
|
||||
// Test Drupal.announce() message when no matches are expected.
|
||||
$filter->setValue('Pan-Galactic Gargle Blaster');
|
||||
$session->wait(10000, 'jQuery("#drupal-live-announce").html().indexOf("0 blocks are available") > -1');
|
||||
$visible_rows = $this->filterVisibleElements($block_rows);
|
||||
$this->assertCount(0, $visible_rows);
|
||||
$expected_message = '0 blocks are available in the modified list.';
|
||||
$this->assertAnnounceContains($expected_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any non-visible elements from the passed array.
|
||||
*
|
||||
* @param \Behat\Mink\Element\NodeElement[] $elements
|
||||
* An array of node elements.
|
||||
*
|
||||
* @return \Behat\Mink\Element\NodeElement[]
|
||||
* An array of visible elements.
|
||||
*/
|
||||
protected function filterVisibleElements(array $elements): array {
|
||||
$elements = array_filter($elements, function (NodeElement $element) {
|
||||
return $element->isVisible();
|
||||
});
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for inclusion of text in #drupal-live-announce.
|
||||
*
|
||||
* @param string $expected_message
|
||||
* The text expected to be present in #drupal-live-announce.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertAnnounceContains(string $expected_message): void {
|
||||
$assert_session = $this->assertSession();
|
||||
$this->assertNotEmpty($assert_session->waitForElement('css', "#drupal-live-announce:contains('$expected_message')"));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Tests\SchemaCheckTestTrait;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the block config schema.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockConfigSchemaTest extends KernelTestBase {
|
||||
|
||||
use SchemaCheckTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'block_content',
|
||||
'comment',
|
||||
'node',
|
||||
// \Drupal\block\Entity\Block->preSave() calls system_region_list().
|
||||
'system',
|
||||
'taxonomy',
|
||||
'user',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* The typed config manager.
|
||||
*
|
||||
* @var \Drupal\Core\Config\TypedConfigManagerInterface
|
||||
*/
|
||||
protected $typedConfig;
|
||||
|
||||
/**
|
||||
* The block manager.
|
||||
*
|
||||
* @var \Drupal\Core\Block\BlockManagerInterface
|
||||
*/
|
||||
protected $blockManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->typedConfig = \Drupal::service('config.typed');
|
||||
$this->blockManager = \Drupal::service('plugin.manager.block');
|
||||
$this->installEntitySchema('block_content');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installEntitySchema('node');
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block config schema for block plugins.
|
||||
*/
|
||||
public function testBlockConfigSchema(): void {
|
||||
foreach ($this->blockManager->getDefinitions() as $block_id => $definition) {
|
||||
// Skip the syndicate block as it is deprecated.
|
||||
if ($block_id === 'node_syndicate_block') {
|
||||
continue;
|
||||
}
|
||||
$id = $this->randomMachineName();
|
||||
$block = Block::create([
|
||||
'id' => $id,
|
||||
'theme' => 'stark',
|
||||
'weight' => 00,
|
||||
'status' => TRUE,
|
||||
'region' => 'content',
|
||||
'plugin' => $block_id,
|
||||
'settings' => [
|
||||
'label' => $this->randomMachineName(),
|
||||
'provider' => 'system',
|
||||
'label_display' => FALSE,
|
||||
],
|
||||
'visibility' => [],
|
||||
]);
|
||||
$block->save();
|
||||
|
||||
$config = $this->config("block.block.$id");
|
||||
$this->assertEquals($id, $config->get('id'));
|
||||
$this->assertConfigSchema($this->typedConfig, $config->getName(), $config->get());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\Core\Config\ConfigInstallerInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Extension\ThemeInstallerInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Tests that blocks are not created during config sync.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockConfigSyncTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
\Drupal::service(ThemeInstallerInterface::class)
|
||||
->install(['stark', 'claro']);
|
||||
|
||||
// Delete all existing blocks.
|
||||
foreach (Block::loadMultiple() as $block) {
|
||||
$block->delete();
|
||||
}
|
||||
|
||||
// Set the default theme.
|
||||
$this->config('system.theme')
|
||||
->set('default', 'stark')
|
||||
->save();
|
||||
|
||||
// Create a block for the default theme to be copied later.
|
||||
Block::create([
|
||||
'id' => 'test_block',
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'region' => 'content',
|
||||
'theme' => 'stark',
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register(ContainerBuilder $container): void {
|
||||
parent::register($container);
|
||||
$container->setParameter('install_profile', 'testing');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests blocks are not created during config sync.
|
||||
*
|
||||
* @param bool $syncing
|
||||
* Whether or not config is syncing when the hook is invoked.
|
||||
* @param string|null $expected_block_id
|
||||
* The expected ID of the block that should be created, or NULL if no block
|
||||
* should be created.
|
||||
*
|
||||
* @testWith [true, null]
|
||||
* [false, "claro_test_block"]
|
||||
*/
|
||||
public function testNoBlocksCreatedDuringConfigSync(bool $syncing, ?string $expected_block_id): void {
|
||||
\Drupal::service(ConfigInstallerInterface::class)
|
||||
->setSyncing($syncing);
|
||||
|
||||
// Invoke the hook that should skip block creation due to config sync.
|
||||
\Drupal::moduleHandler()->invoke('block', 'themes_installed', [['claro']]);
|
||||
// This should hold true if the "current" install profile triggers an
|
||||
// invocation of hook_modules_installed().
|
||||
\Drupal::moduleHandler()->invoke('block', 'modules_installed', [['testing'], $syncing]);
|
||||
|
||||
$this->assertSame($expected_block_id, Block::load('claro_test_block')?->id());
|
||||
}
|
||||
|
||||
}
|
||||
110
web/core/modules/block/tests/src/Kernel/BlockInterfaceTest.php
Normal file
110
web/core/modules/block/tests/src/Kernel/BlockInterfaceTest.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
// cspell:ignore displaymessage
|
||||
|
||||
/**
|
||||
* Tests that the block plugin can work properly without a supporting entity.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockInterfaceTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'block', 'block_test', 'user'];
|
||||
|
||||
/**
|
||||
* Tests configuration and subsequent form() and build() method calls.
|
||||
*
|
||||
* This test is attempting to test the existing block plugin api and all
|
||||
* functionality that is expected to remain consistent. The arrays that are
|
||||
* used for comparison can change, but only to include elements that are
|
||||
* contained within BlockBase or the plugin being tested. Likely these
|
||||
* comparison arrays should get smaller, not larger, as more form/build
|
||||
* elements are moved into a more suitably responsible class.
|
||||
*
|
||||
* Instantiation of the plugin is the primary element being tested here. The
|
||||
* subsequent method calls are just attempting to cause a failure if a
|
||||
* dependency outside of the plugin configuration is required.
|
||||
*/
|
||||
public function testBlockInterface(): void {
|
||||
$manager = $this->container->get('plugin.manager.block');
|
||||
$configuration = [
|
||||
'label' => 'Custom Display Message',
|
||||
];
|
||||
$expected_configuration = [
|
||||
'id' => 'test_block_instantiation',
|
||||
'label' => 'Custom Display Message',
|
||||
'label_display' => BlockPluginInterface::BLOCK_LABEL_VISIBLE,
|
||||
'provider' => 'block_test',
|
||||
'display_message' => 'no message set',
|
||||
];
|
||||
// Initial configuration of the block at construction time.
|
||||
/** @var \Drupal\Core\Block\BlockPluginInterface $display_block */
|
||||
$display_block = $manager->createInstance('test_block_instantiation', $configuration);
|
||||
$this->assertSame($expected_configuration, $display_block->getConfiguration(), 'The block was configured correctly.');
|
||||
|
||||
// Updating an element of the configuration.
|
||||
$display_block->setConfigurationValue('display_message', 'My custom display message.');
|
||||
$expected_configuration['display_message'] = 'My custom display message.';
|
||||
$this->assertSame($expected_configuration, $display_block->getConfiguration(), 'The block configuration was updated correctly.');
|
||||
$definition = $display_block->getPluginDefinition();
|
||||
|
||||
$expected_form = [
|
||||
'provider' => [
|
||||
'#type' => 'value',
|
||||
'#value' => 'block_test',
|
||||
],
|
||||
'admin_label' => [
|
||||
'#type' => 'item',
|
||||
'#title' => 'Block description',
|
||||
'#plain_text' => $definition['admin_label'],
|
||||
],
|
||||
'label' => [
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'Title',
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => 'Custom Display Message',
|
||||
'#required' => TRUE,
|
||||
],
|
||||
'label_display' => [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => 'Display title',
|
||||
'#default_value' => TRUE,
|
||||
'#return_value' => 'visible',
|
||||
],
|
||||
'context_mapping' => [],
|
||||
'display_message' => [
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'Display message',
|
||||
'#default_value' => 'My custom display message.',
|
||||
],
|
||||
];
|
||||
$form_state = new FormState();
|
||||
// Ensure there are no form elements that do not belong to the plugin.
|
||||
$actual_form = $display_block->buildConfigurationForm([], $form_state);
|
||||
// Remove the visibility sections, as that just tests condition plugins.
|
||||
unset($actual_form['visibility'], $actual_form['visibility_tabs']);
|
||||
$this->assertEquals($expected_form, $actual_form, 'Only the expected form elements were present.');
|
||||
|
||||
$expected_build = [
|
||||
'#children' => 'My custom display message.',
|
||||
];
|
||||
// Ensure the build array is proper.
|
||||
$this->assertSame($expected_build, $display_block->build(), 'The plugin returned the appropriate build array.');
|
||||
|
||||
// Ensure the machine name suggestion is correct. In truth, this is actually
|
||||
// testing BlockBase's implementation, not the interface itself.
|
||||
$this->assertSame('displaymessage', $display_block->getMachineNameSuggestion(), 'The plugin returned the expected machine name suggestion.');
|
||||
}
|
||||
|
||||
}
|
||||
123
web/core/modules/block/tests/src/Kernel/BlockRebuildTest.php
Normal file
123
web/core/modules/block/tests/src/Kernel/BlockRebuildTest.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\block\Traits\BlockCreationTrait;
|
||||
use Drupal\block\Hook\BlockHooks;
|
||||
|
||||
/**
|
||||
* Tests block_rebuild().
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockRebuildTest extends KernelTestBase {
|
||||
|
||||
use BlockCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $configSchemaCheckerExclusions = [
|
||||
// These blocks are intentionally put into invalid regions, so they will
|
||||
// violate config schema.
|
||||
// @see ::testRebuildInvalidBlocks()
|
||||
'block.block.invalid_block1',
|
||||
'block.block.invalid_block2',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
$this->container->get('config.factory')->getEditable('system.theme')->set('default', 'stark')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\block\Hook\BlockHooks::rebuild
|
||||
*/
|
||||
public function testRebuildNoBlocks(): void {
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
$messages = \Drupal::messenger()->all();
|
||||
\Drupal::messenger()->deleteAll();
|
||||
$this->assertEquals([], $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\block\Hook\BlockHooks::rebuild
|
||||
*/
|
||||
public function testRebuildNoInvalidBlocks(): void {
|
||||
$this->placeBlock('system_powered_by_block', ['region' => 'content']);
|
||||
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
$messages = \Drupal::messenger()->all();
|
||||
\Drupal::messenger()->deleteAll();
|
||||
$this->assertEquals([], $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\block\Hook\BlockHooks::rebuild
|
||||
*/
|
||||
public function testRebuildInvalidBlocks(): void {
|
||||
$this->placeBlock('system_powered_by_block', ['region' => 'content']);
|
||||
$block1 = $this->placeBlock('system_powered_by_block', [
|
||||
'id' => 'invalid_block1',
|
||||
]);
|
||||
$block2 = $this->placeBlock('system_powered_by_block', [
|
||||
'id' => 'invalid_block2',
|
||||
]);
|
||||
$block2->disable()->save();
|
||||
// Use the config API directly to bypass Block::preSave().
|
||||
\Drupal::configFactory()->getEditable('block.block.' . $block1->id())->set('region', 'INVALID')->save();
|
||||
\Drupal::configFactory()->getEditable('block.block.' . $block2->id())->set('region', 'INVALID')->save();
|
||||
|
||||
// Reload block entities.
|
||||
$block1 = Block::load($block1->id());
|
||||
$block2 = Block::load($block2->id());
|
||||
|
||||
$this->assertSame('INVALID', $block1->getRegion());
|
||||
$this->assertTrue($block1->status());
|
||||
$this->assertSame('INVALID', $block2->getRegion());
|
||||
$this->assertFalse($block2->status());
|
||||
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
|
||||
// Reload block entities.
|
||||
$block1 = Block::load($block1->id());
|
||||
$block2 = Block::load($block2->id());
|
||||
|
||||
$messages = \Drupal::messenger()->all();
|
||||
\Drupal::messenger()->deleteAll();
|
||||
$expected = [
|
||||
'warning' => [
|
||||
new TranslatableMarkup('The block %info was assigned to the invalid region %region and has been disabled.', [
|
||||
'%info' => $block1->id(),
|
||||
'%region' => 'INVALID',
|
||||
]),
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected, $messages);
|
||||
|
||||
$default_region = system_default_region('stark');
|
||||
$this->assertSame($default_region, $block1->getRegion());
|
||||
$this->assertFalse($block1->status());
|
||||
$this->assertSame($default_region, $block2->getRegion());
|
||||
$this->assertFalse($block2->status());
|
||||
}
|
||||
|
||||
}
|
||||
161
web/core/modules/block/tests/src/Kernel/BlockStorageUnitTest.php
Normal file
161
web/core/modules/block/tests/src/Kernel/BlockStorageUnitTest.php
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorage;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\block_test\Plugin\Block\TestHtmlBlock;
|
||||
use Drupal\Component\Plugin\Exception\PluginException;
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Tests the storage of blocks.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockStorageUnitTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test', 'system'];
|
||||
|
||||
/**
|
||||
* The block storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->controller = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests CRUD operations.
|
||||
*/
|
||||
public function testBlockCRUD(): void {
|
||||
$this->assertInstanceOf(ConfigEntityStorage::class, $this->controller);
|
||||
|
||||
// Run each test method in the same installation.
|
||||
$this->createTests();
|
||||
$this->loadTests();
|
||||
$this->deleteTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the creation of blocks.
|
||||
*/
|
||||
protected function createTests(): void {
|
||||
// Attempt to create a block without a plugin.
|
||||
try {
|
||||
$entity = $this->controller->create([]);
|
||||
$entity->getPlugin();
|
||||
$this->fail('A block without a plugin was created with no exception thrown.');
|
||||
}
|
||||
catch (PluginException $e) {
|
||||
$this->assertEquals('The block \'\' did not specify a plugin.', $e->getMessage(), 'An exception was thrown when a block was created without a plugin.');
|
||||
}
|
||||
|
||||
// Create a block with only required values.
|
||||
$entity = $this->controller->create([
|
||||
'id' => 'test_block',
|
||||
'theme' => 'stark',
|
||||
'region' => 'content',
|
||||
'plugin' => 'test_html',
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
$this->assertInstanceOf(Block::class, $entity);
|
||||
|
||||
// Verify all of the block properties.
|
||||
$actual_properties = $this->config('block.block.test_block')->get();
|
||||
$this->assertNotEmpty($actual_properties['uuid'], 'The block UUID is set.');
|
||||
unset($actual_properties['uuid']);
|
||||
|
||||
// Ensure that default values are filled in.
|
||||
$expected_properties = [
|
||||
'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
|
||||
'status' => TRUE,
|
||||
'dependencies' => ['module' => ['block_test'], 'theme' => ['stark']],
|
||||
'id' => 'test_block',
|
||||
'theme' => 'stark',
|
||||
'region' => 'content',
|
||||
'weight' => 0,
|
||||
'provider' => NULL,
|
||||
'plugin' => 'test_html',
|
||||
'settings' => [
|
||||
'id' => 'test_html',
|
||||
'label' => '',
|
||||
'label_display' => BlockPluginInterface::BLOCK_LABEL_VISIBLE,
|
||||
'provider' => 'block_test',
|
||||
],
|
||||
'visibility' => [],
|
||||
];
|
||||
|
||||
$this->assertSame($expected_properties, $actual_properties);
|
||||
|
||||
$this->assertInstanceOf(TestHtmlBlock::class, $entity->getPlugin());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the loading of blocks.
|
||||
*/
|
||||
protected function loadTests(): void {
|
||||
$entity = $this->controller->load('test_block');
|
||||
|
||||
$this->assertInstanceOf(Block::class, $entity);
|
||||
|
||||
// Verify several properties of the block.
|
||||
$this->assertSame('content', $entity->getRegion());
|
||||
$this->assertTrue($entity->status());
|
||||
$this->assertEquals('stark', $entity->getTheme());
|
||||
$this->assertNotEmpty($entity->uuid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the deleting of blocks.
|
||||
*/
|
||||
protected function deleteTests(): void {
|
||||
$entity = $this->controller->load('test_block');
|
||||
|
||||
// Ensure that the storage isn't currently empty.
|
||||
$config_storage = $this->container->get('config.storage');
|
||||
$config = $config_storage->listAll('block.block.');
|
||||
$this->assertNotEmpty($config, 'There are blocks in config storage.');
|
||||
|
||||
// Delete the block.
|
||||
$entity->delete();
|
||||
|
||||
// Ensure that the storage is now empty.
|
||||
$config = $config_storage->listAll('block.block.');
|
||||
$this->assertEmpty($config, 'There are no blocks in config storage.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the installation of default blocks.
|
||||
*/
|
||||
public function testDefaultBlocks(): void {
|
||||
\Drupal::service('theme_installer')->install(['stark']);
|
||||
$entities = $this->controller->loadMultiple();
|
||||
$this->assertEmpty($entities, 'There are no blocks initially.');
|
||||
|
||||
// Install the block_test.module, so that its default config is installed.
|
||||
$this->installConfig(['block_test']);
|
||||
|
||||
$entities = $this->controller->loadMultiple();
|
||||
$entity = reset($entities);
|
||||
$this->assertEquals('test_block', $entity->id(), 'The default test block was loaded.');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the block_theme_suggestions_block() function.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockTemplateSuggestionsTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'system',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests template suggestions from block_theme_suggestions_block().
|
||||
*/
|
||||
public function testBlockThemeHookSuggestions(): void {
|
||||
$this->installConfig(['system']);
|
||||
|
||||
// Create a block using a plugin with derivative to be preprocessed.
|
||||
$block = Block::create([
|
||||
'plugin' => 'system_menu_block:admin',
|
||||
'region' => 'footer',
|
||||
'id' => 'machine_name',
|
||||
]);
|
||||
|
||||
$variables = [];
|
||||
/** @var \Drupal\Core\Block\BlockPluginInterface $plugin */
|
||||
$plugin = $block->getPlugin();
|
||||
$variables['elements']['#configuration'] = $plugin->getConfiguration();
|
||||
$variables['elements']['#plugin_id'] = $plugin->getPluginId();
|
||||
$variables['elements']['#id'] = $block->id();
|
||||
$variables['elements']['#base_plugin_id'] = $plugin->getBaseId();
|
||||
$variables['elements']['#derivative_plugin_id'] = $plugin->getDerivativeId();
|
||||
$variables['elements']['content'] = [];
|
||||
$suggestions = block_theme_suggestions_block($variables);
|
||||
$this->assertSame([
|
||||
'block__system',
|
||||
'block__system_menu_block',
|
||||
'block__system_menu_block__admin',
|
||||
'block__machine_name',
|
||||
], $suggestions);
|
||||
}
|
||||
|
||||
}
|
||||
271
web/core/modules/block/tests/src/Kernel/BlockValidationTest.php
Normal file
271
web/core/modules/block/tests/src/Kernel/BlockValidationTest.php
Normal file
@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase;
|
||||
|
||||
/**
|
||||
* Tests validation of block entities.
|
||||
*
|
||||
* @group block
|
||||
* @group #slow
|
||||
*/
|
||||
class BlockValidationTest extends ConfigEntityValidationTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static array $propertiesWithRequiredKeys = [
|
||||
'settings' => [
|
||||
"'id' is a required key.",
|
||||
"'label' is a required key.",
|
||||
"'label_display' is a required key.",
|
||||
"'provider' is a required key.",
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static array $propertiesWithOptionalValues = [
|
||||
'provider',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
|
||||
$this->entity = Block::create([
|
||||
'id' => 'test_block',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'settings' => [
|
||||
'label' => 'Powered by Drupal 🚀',
|
||||
],
|
||||
]);
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validating a block with an unknown plugin ID.
|
||||
*/
|
||||
public function testInvalidPluginId(): void {
|
||||
$this->entity->set('plugin', 'block_content:d7c9d8ba-663f-41b4-8756-86bc55c44653');
|
||||
// Block config entities with invalid block plugin IDs automatically fall
|
||||
// back to the `broken` block plugin.
|
||||
// @see https://www.drupal.org/node/2249303
|
||||
// @see \Drupal\Core\Block\BlockManager::getFallbackPluginId()
|
||||
// @see \Drupal\Core\Block\Plugin\Block\Broken
|
||||
$this->assertValidationErrors([]);
|
||||
|
||||
$this->entity->set('plugin', 'non_existent');
|
||||
// @todo Expect error for this in https://www.drupal.org/project/drupal/issues/3377709
|
||||
$this->assertValidationErrors([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Block names are atypical in that they allow periods in the machine name.
|
||||
*/
|
||||
public static function providerInvalidMachineNameCharacters(): array {
|
||||
$cases = parent::providerInvalidMachineNameCharacters();
|
||||
// Remove the existing test case that verifies a machine name containing
|
||||
// periods is invalid.
|
||||
self::assertSame(['period.separated', FALSE], $cases['INVALID: period separated']);
|
||||
unset($cases['INVALID: period separated']);
|
||||
// And instead add a test case that verifies it is allowed for blocks.
|
||||
$cases['VALID: period separated'] = ['period.separated', TRUE];
|
||||
return $cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function setLabel(ConfigEntityInterface $block, string $label): void {
|
||||
static::assertInstanceOf(Block::class, $block);
|
||||
$settings = $block->get('settings');
|
||||
static::assertNotEmpty($settings['label']);
|
||||
$settings['label'] = $label;
|
||||
$block->set('settings', $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testLabelValidation(): void {
|
||||
static::setLabel($this->entity, "Multi\nLine");
|
||||
// TRICKY: because the Block config entity type does not specify a `label`
|
||||
// key, it is impossible for the generic ::testLabelValidation()
|
||||
// implementation in the base class to know at which property to expect a
|
||||
// validation error. Hence it is hardcoded in this case.
|
||||
$this->assertValidationErrors(['settings.label' => "Labels are not allowed to span multiple lines or contain control characters."]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validating a block with a non-existent theme.
|
||||
*/
|
||||
public function testThemeValidation(): void {
|
||||
$this->entity->set('theme', 'non_existent');
|
||||
$this->assertValidationErrors([
|
||||
'region' => 'This is not a valid region of the <em class="placeholder">non_existent</em> theme.',
|
||||
'theme' => "Theme 'non_existent' is not installed.",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testRequiredPropertyValuesMissing(?array $additional_expected_validation_errors_when_missing = NULL): void {
|
||||
parent::testRequiredPropertyValuesMissing([
|
||||
'region' => [
|
||||
'region' => [
|
||||
'This is not a valid region of the <em class="placeholder">stark</em> theme.',
|
||||
'This value should not be null.',
|
||||
],
|
||||
],
|
||||
'theme' => [
|
||||
'region' => 'This block does not say which theme it appears in.',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validating a block's region in a theme.
|
||||
*/
|
||||
public function testRegionValidation(): void {
|
||||
$this->entity->set('region', 'non_existent');
|
||||
$this->assertValidationErrors([
|
||||
'region' => 'This is not a valid region of the <em class="placeholder">stark</em> theme.',
|
||||
]);
|
||||
// Set a valid region and assert it is saved properly.
|
||||
$this->entity->set('region', 'header');
|
||||
$this->assertValidationErrors([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validating weight.
|
||||
*/
|
||||
public function testWeightValidation(): void {
|
||||
$this->entity->set('weight', $this->randomString());
|
||||
$this->assertValidationErrors([
|
||||
'weight' => [
|
||||
'This value should be a valid number.',
|
||||
'This value should be of the correct primitive type.',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->entity->set('weight', 10);
|
||||
$this->assertValidationErrors([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testWeightCannotBeNull(): void {
|
||||
$this->entity->set('weight', NULL);
|
||||
$this->assertNull($this->entity->getWeight());
|
||||
$this->expectDeprecation('Saving a block with a non-integer weight is deprecated in drupal:11.1.0 and removed in drupal:12.0.0. See https://www.drupal.org/node/3462474');
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testMenuBlockLevelAndDepth().
|
||||
*/
|
||||
public static function providerMenuBlockLevelAndDepth(): iterable {
|
||||
yield 'OK: entire tree from first level' => [0, NULL, []];
|
||||
|
||||
yield 'OK: entire tree from third level' => [2, NULL, []];
|
||||
|
||||
yield 'OK: first three levels' => [0, 3, []];
|
||||
|
||||
yield 'INVALID: level is less than 0' => [
|
||||
-2,
|
||||
NULL,
|
||||
[
|
||||
'settings.level' => 'This value should be between <em class="placeholder">0</em> and <em class="placeholder">9</em>.',
|
||||
],
|
||||
];
|
||||
|
||||
yield 'INVALID: level is greater than 9' => [
|
||||
11,
|
||||
NULL,
|
||||
[
|
||||
'settings.level' => 'This value should be between <em class="placeholder">0</em> and <em class="placeholder">9</em>.',
|
||||
],
|
||||
];
|
||||
|
||||
yield 'INVALID: depth too high' => [
|
||||
0,
|
||||
12,
|
||||
[
|
||||
'settings.depth' => 'This value should be between <em class="placeholder">1</em> and <em class="placeholder">9</em>.',
|
||||
],
|
||||
];
|
||||
|
||||
yield 'INVALID: depth too low' => [
|
||||
0,
|
||||
0,
|
||||
[
|
||||
'settings.depth' => 'This value should be between <em class="placeholder">1</em> and <em class="placeholder">9</em>.',
|
||||
],
|
||||
];
|
||||
|
||||
yield 'INVALID: start at third level, depth too high' => [
|
||||
2,
|
||||
9,
|
||||
[
|
||||
'settings.depth' => 'This value should be between <em class="placeholder">1</em> and <em class="placeholder">7</em>.',
|
||||
],
|
||||
];
|
||||
|
||||
yield 'OK: deepest level only' => [9, 1, []];
|
||||
|
||||
yield 'INVALID: start at deepest level, depth too high' => [
|
||||
9,
|
||||
2,
|
||||
[
|
||||
'settings.depth' => 'This value should be between <em class="placeholder">1</em> and <em class="placeholder">1</em>.',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validating menu block `level` and `depth` settings.
|
||||
*
|
||||
* @dataProvider providerMenuBlockLevelAndDepth
|
||||
*/
|
||||
public function testMenuBlockLevelAndDepth(int $level, ?int $depth, array $expected_errors): void {
|
||||
$this->installConfig('system');
|
||||
|
||||
$this->entity = Block::create([
|
||||
'id' => 'account_menu',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'system_menu_block:account',
|
||||
'settings' => [
|
||||
'id' => 'system_menu_block:account',
|
||||
'label' => 'Account Menu',
|
||||
'label_display' => FALSE,
|
||||
'provider' => 'system',
|
||||
'level' => $level,
|
||||
'depth' => $depth,
|
||||
'expand_all_items' => FALSE,
|
||||
],
|
||||
'region' => 'content',
|
||||
]);
|
||||
|
||||
$this->assertValidationErrors($expected_errors);
|
||||
}
|
||||
|
||||
}
|
||||
383
web/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php
Normal file
383
web/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php
Normal file
@ -0,0 +1,383 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Tests the block view builder.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockViewBuilderTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'block_test', 'system', 'user'];
|
||||
|
||||
/**
|
||||
* The block being tested.
|
||||
*
|
||||
* @var \Drupal\block\BlockInterface
|
||||
*/
|
||||
protected $block;
|
||||
|
||||
/**
|
||||
* The block storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
$this->controller = $this->container
|
||||
->get('entity_type.manager')
|
||||
->getStorage('block');
|
||||
|
||||
\Drupal::keyValue('block_test')->set('content', 'Llamas > unicorns!');
|
||||
|
||||
// Create a block with only required values.
|
||||
$this->block = $this->controller->create([
|
||||
'id' => 'test_block',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'test_cache',
|
||||
]);
|
||||
$this->block->save();
|
||||
|
||||
$this->container->get('cache.render')->deleteAll();
|
||||
|
||||
$this->renderer = $this->container->get('renderer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rendering a block plugin that returns an empty array.
|
||||
*/
|
||||
public function testEmptyRender(): void {
|
||||
\Drupal::keyValue('block_test')->set('content', '');
|
||||
|
||||
$entity = $this->controller->create([
|
||||
'id' => 'test_block1',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'test_empty',
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
// Test the rendering of a block.
|
||||
$entity = Block::load('test_block1');
|
||||
$builder = \Drupal::entityTypeManager()->getViewBuilder('block');
|
||||
$output = $builder->view($entity, 'block');
|
||||
$expected_output = '';
|
||||
$this->assertSame($expected_output, (string) $this->renderer->renderRoot($output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the rendering of blocks.
|
||||
*/
|
||||
public function testBasicRendering(): void {
|
||||
\Drupal::keyValue('block_test')->set('content', '');
|
||||
|
||||
$entity = $this->controller->create([
|
||||
'id' => 'test_block1',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'test_html',
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
// Test the rendering of a block.
|
||||
$entity = Block::load('test_block1');
|
||||
$builder = \Drupal::entityTypeManager()->getViewBuilder('block');
|
||||
$output = $builder->view($entity, 'block');
|
||||
$expected = [];
|
||||
$expected[] = '<div id="block-test-block1">';
|
||||
$expected[] = ' ';
|
||||
$expected[] = ' ';
|
||||
$expected[] = ' ';
|
||||
$expected[] = ' </div>';
|
||||
$expected[] = '';
|
||||
$expected_output = implode("\n", $expected);
|
||||
$this->assertSame($expected_output, (string) $this->renderer->renderRoot($output));
|
||||
|
||||
// Reset the HTML IDs so that the next render is not affected.
|
||||
Html::resetSeenIds();
|
||||
|
||||
// Test the rendering of a block with a given title.
|
||||
$entity = $this->controller->create([
|
||||
'id' => 'test_block2',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'test_html',
|
||||
'settings' => [
|
||||
'label' => 'Powered by Bananas',
|
||||
],
|
||||
]);
|
||||
$entity->save();
|
||||
$output = $builder->view($entity, 'block');
|
||||
$expected = [];
|
||||
$expected[] = '<div id="block-test-block2">';
|
||||
$expected[] = ' ';
|
||||
$expected[] = ' <h2>Powered by Bananas</h2>';
|
||||
$expected[] = ' ';
|
||||
$expected[] = ' ';
|
||||
$expected[] = ' </div>';
|
||||
$expected[] = '';
|
||||
$expected_output = implode("\n", $expected);
|
||||
$this->assertSame($expected_output, (string) $this->renderer->renderRoot($output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block render cache handling.
|
||||
*/
|
||||
public function testBlockViewBuilderCache(): void {
|
||||
// Verify cache handling for a non-empty block.
|
||||
$this->verifyRenderCacheHandling();
|
||||
|
||||
// Create an empty block.
|
||||
$this->block = $this->controller->create([
|
||||
'id' => 'test_block',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'test_cache',
|
||||
]);
|
||||
$this->block->save();
|
||||
\Drupal::keyValue('block_test')->set('content', NULL);
|
||||
|
||||
// Verify cache handling for an empty block.
|
||||
$this->verifyRenderCacheHandling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests title block render cache handling.
|
||||
*
|
||||
* @see \Drupal\block_test\Hook\BlockTestHooks::blockViewPageTitleBlockAlter()
|
||||
*/
|
||||
public function testBlockViewBuilderCacheTitleBlock(): void {
|
||||
// Create title block.
|
||||
$this->block = $this->controller->create([
|
||||
'id' => 'test_block_title',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'page_title_block',
|
||||
]);
|
||||
$this->block->save();
|
||||
|
||||
$entity = Block::load('test_block_title');
|
||||
$builder = \Drupal::entityTypeManager()->getViewBuilder('block');
|
||||
$output = $builder->view($entity, 'block');
|
||||
|
||||
$this->assertSame(
|
||||
['block_view', 'config:block.block.test_block_title', 'custom_cache_tag'],
|
||||
$output['#cache']['tags']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies render cache handling of the block being tested.
|
||||
*
|
||||
* @see ::testBlockViewBuilderCache()
|
||||
*/
|
||||
protected function verifyRenderCacheHandling(): void {
|
||||
/** @var \Drupal\Core\Cache\VariationCacheFactoryInterface $variation_cache_factory */
|
||||
$variation_cache_factory = $this->container->get('variation_cache_factory');
|
||||
$cache_bin = $variation_cache_factory->get('render');
|
||||
|
||||
// Force a request via GET so we can test the render cache.
|
||||
$request = \Drupal::request();
|
||||
$request_method = $request->server->get('REQUEST_METHOD');
|
||||
$request->setMethod('GET');
|
||||
|
||||
// Test that a cache entry is created.
|
||||
$build = $this->getBlockRenderArray();
|
||||
$cache_keys = ['entity_view', 'block', 'test_block'];
|
||||
$this->renderer->renderRoot($build);
|
||||
$this->assertNotEmpty($cache_bin->get($cache_keys, CacheableMetadata::createFromRenderArray($build)), 'The block render element has been cached.');
|
||||
|
||||
// Re-save the block and check that the cache entry has been deleted.
|
||||
$this->block->save();
|
||||
$this->assertFalse($cache_bin->get($cache_keys, CacheableMetadata::createFromRenderArray($build)), 'The block render cache entry has been cleared when the block was saved.');
|
||||
|
||||
// Rebuild the render array (creating a new cache entry in the process) and
|
||||
// delete the block to check the cache entry is deleted.
|
||||
unset($build['#printed']);
|
||||
// Re-add the block because \Drupal\block\BlockViewBuilder::buildBlock()
|
||||
// removes it.
|
||||
$build['#block'] = $this->block;
|
||||
|
||||
$this->renderer->renderRoot($build);
|
||||
$this->assertNotEmpty($cache_bin->get($cache_keys, CacheableMetadata::createFromRenderArray($build)), 'The block render element has been cached.');
|
||||
$this->block->delete();
|
||||
$this->assertFalse($cache_bin->get($cache_keys, CacheableMetadata::createFromRenderArray($build)), 'The block render cache entry has been cleared when the block was deleted.');
|
||||
|
||||
// Restore the previous request method.
|
||||
$request->setMethod($request_method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block view altering.
|
||||
*
|
||||
* @see hook_block_view_alter()
|
||||
* @see hook_block_view_BASE_BLOCK_ID_alter()
|
||||
*/
|
||||
public function testBlockViewBuilderViewAlter(): void {
|
||||
// Establish baseline.
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->setRawContent((string) $this->renderer->renderRoot($build));
|
||||
$this->assertSame('Llamas > unicorns!', trim((string) $this->cssSelect('div')[0]));
|
||||
|
||||
// Enable the block view alter hook that adds a foo=bar attribute.
|
||||
\Drupal::state()->set('block_test_view_alter_suffix', TRUE);
|
||||
Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->setRawContent((string) $this->renderer->renderRoot($build));
|
||||
$this->assertSame('Llamas > unicorns!', trim((string) $this->cssSelect('[foo=bar]')[0]));
|
||||
\Drupal::state()->set('block_test_view_alter_suffix', FALSE);
|
||||
|
||||
\Drupal::keyValue('block_test')->set('content', NULL);
|
||||
Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
|
||||
|
||||
// Advanced: cached block, but an alter hook adds a #pre_render callback to
|
||||
// alter the eventual content.
|
||||
\Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
|
||||
$this->assertSame('Hiya!<br>', (string) $this->renderer->renderRoot($build));
|
||||
// Check that a cached block without content is altered.
|
||||
$this->assertArrayHasKey('#prefix', $build);
|
||||
$this->assertSame('Hiya!<br>', $build['#prefix']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests block build altering.
|
||||
*
|
||||
* @see hook_block_build_alter()
|
||||
* @see hook_block_build_BASE_BLOCK_ID_alter()
|
||||
*/
|
||||
public function testBlockViewBuilderBuildAlter(): void {
|
||||
// Force a request via GET so we can test the render cache.
|
||||
$request = \Drupal::request();
|
||||
$request_method = $request->server->get('REQUEST_METHOD');
|
||||
$request->setMethod('GET');
|
||||
|
||||
$default_keys = ['entity_view', 'block', 'test_block'];
|
||||
$default_contexts = [];
|
||||
$default_tags = ['block_view', 'config:block.block.test_block'];
|
||||
$default_max_age = Cache::PERMANENT;
|
||||
|
||||
// hook_block_build_alter() adds an additional cache key.
|
||||
$alter_add_key = $this->randomMachineName();
|
||||
\Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key);
|
||||
$this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), $default_contexts, $default_tags, $default_max_age);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_key', NULL);
|
||||
|
||||
// hook_block_build_alter() adds an additional cache context.
|
||||
$alter_add_context = 'url.query_args:' . $this->randomMachineName();
|
||||
\Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context);
|
||||
$this->assertBlockRenderedWithExpectedCacheability($default_keys, Cache::mergeContexts($default_contexts, [$alter_add_context]), $default_tags, $default_max_age);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_context', NULL);
|
||||
|
||||
// hook_block_build_alter() adds an additional cache tag.
|
||||
$alter_add_tag = $this->randomMachineName();
|
||||
\Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag);
|
||||
$this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, Cache::mergeTags($default_tags, [$alter_add_tag]), $default_max_age);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_tag', NULL);
|
||||
|
||||
// hook_block_build_alter() alters the max-age.
|
||||
$alter_max_age = 300;
|
||||
\Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age);
|
||||
$this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, $default_tags, $alter_max_age);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_max_age', NULL);
|
||||
|
||||
// hook_block_build_alter() alters cache keys, contexts, tags and max-age.
|
||||
\Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age);
|
||||
$this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), Cache::mergeContexts($default_contexts, [$alter_add_context]), Cache::mergeTags($default_tags, [$alter_add_tag]), $alter_max_age);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_key', NULL);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_context', NULL);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_tag', NULL);
|
||||
\Drupal::state()->set('block_test_block_alter_cache_max_age', NULL);
|
||||
|
||||
// hook_block_build_alter() sets #create_placeholder.
|
||||
foreach ([TRUE, FALSE] as $value) {
|
||||
\Drupal::state()->set('block_test_block_alter_create_placeholder', $value);
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertTrue(isset($build['#create_placeholder']));
|
||||
$this->assertSame($value, $build['#create_placeholder']);
|
||||
}
|
||||
\Drupal::state()->set('block_test_block_alter_create_placeholder', NULL);
|
||||
|
||||
// Restore the previous request method.
|
||||
$request->setMethod($request_method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a block is built/rendered/cached with expected cacheability.
|
||||
*
|
||||
* @param string[] $expected_keys
|
||||
* The expected cache keys.
|
||||
* @param string[] $expected_contexts
|
||||
* The expected cache contexts.
|
||||
* @param string[] $expected_tags
|
||||
* The expected cache tags.
|
||||
* @param int $expected_max_age
|
||||
* The expected max-age.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, int $expected_max_age): void {
|
||||
/** @var \Drupal\Core\Cache\VariationCacheFactoryInterface $variation_cache_factory */
|
||||
$variation_cache_factory = $this->container->get('variation_cache_factory');
|
||||
$cache_bin = $variation_cache_factory->get('render');
|
||||
|
||||
$required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
|
||||
|
||||
// Check that the expected cacheability metadata is present in:
|
||||
// - the built render array;
|
||||
$build = $this->getBlockRenderArray();
|
||||
$this->assertSame($expected_keys, $build['#cache']['keys']);
|
||||
$this->assertEqualsCanonicalizing($expected_contexts, $build['#cache']['contexts']);
|
||||
$this->assertEqualsCanonicalizing($expected_tags, $build['#cache']['tags']);
|
||||
$this->assertSame($expected_max_age, $build['#cache']['max-age']);
|
||||
$this->assertFalse(isset($build['#create_placeholder']));
|
||||
// - the rendered render array;
|
||||
$this->renderer->renderRoot($build);
|
||||
// - the render cache item.
|
||||
$final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
|
||||
$cache_item = $cache_bin->get($expected_keys, CacheableMetadata::createFromRenderArray($build));
|
||||
$this->assertNotEmpty($cache_item, 'The block render element has been cached with the expected cache keys.');
|
||||
$this->assertEqualsCanonicalizing(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
|
||||
$this->assertEqualsCanonicalizing($final_cache_contexts, $cache_item->data['#cache']['contexts']);
|
||||
$this->assertEqualsCanonicalizing($expected_tags, $cache_item->data['#cache']['tags']);
|
||||
$this->assertSame($expected_max_age, $cache_item->data['#cache']['max-age']);
|
||||
|
||||
$cache_bin->delete($expected_keys, CacheableMetadata::createFromRenderArray($build));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fully built render array for a block.
|
||||
*
|
||||
* @return array
|
||||
* The render array.
|
||||
*/
|
||||
protected function getBlockRenderArray() {
|
||||
return $this->container->get('entity_type.manager')->getViewBuilder('block')->view($this->block, 'block');
|
||||
}
|
||||
|
||||
}
|
||||
222
web/core/modules/block/tests/src/Kernel/ConfigActionsTest.php
Normal file
222
web/core/modules/block/tests/src/Kernel/ConfigActionsTest.php
Normal file
@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Config\Action\ConfigActionException;
|
||||
use Drupal\Core\Config\Action\ConfigActionManager;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Extension\ThemeInstallerInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\block\Traits\BlockCreationTrait;
|
||||
|
||||
/**
|
||||
* @covers \Drupal\block\Plugin\ConfigAction\PlaceBlock
|
||||
* @covers \Drupal\block\Plugin\ConfigAction\PlaceBlockDeriver
|
||||
* @group block
|
||||
*/
|
||||
class ConfigActionsTest extends KernelTestBase {
|
||||
|
||||
use BlockCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'system', 'user'];
|
||||
|
||||
/**
|
||||
* The configuration action manager.
|
||||
*/
|
||||
private readonly ConfigActionManager $configActionManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->container->get(ThemeInstallerInterface::class)->install([
|
||||
'olivero',
|
||||
'claro',
|
||||
'umami',
|
||||
]);
|
||||
$this->config('system.theme')
|
||||
->set('default', 'olivero')
|
||||
->set('admin', 'claro')
|
||||
->save();
|
||||
$this->configActionManager = $this->container->get('plugin.manager.config_action');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the application of entity method actions on a block.
|
||||
*/
|
||||
public function testEntityMethodActions(): void {
|
||||
$block = $this->placeBlock('system_messages_block', ['theme' => 'olivero']);
|
||||
$this->assertSame('content', $block->getRegion());
|
||||
$this->assertSame(0, $block->getWeight());
|
||||
|
||||
$this->configActionManager->applyAction(
|
||||
'entity_method:block.block:setRegion',
|
||||
$block->getConfigDependencyName(),
|
||||
'highlighted',
|
||||
);
|
||||
$this->configActionManager->applyAction(
|
||||
'entity_method:block.block:setWeight',
|
||||
$block->getConfigDependencyName(),
|
||||
-10,
|
||||
);
|
||||
|
||||
$block = Block::load($block->id());
|
||||
$this->assertSame('highlighted', $block->getRegion());
|
||||
$this->assertSame(-10, $block->getWeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["placeBlockInDefaultTheme"]
|
||||
* ["placeBlockInAdminTheme"]
|
||||
*/
|
||||
public function testPlaceBlockActionOnlyWorksOnBlocks(string $action): void {
|
||||
$this->expectException(PluginNotFoundException::class);
|
||||
$this->expectExceptionMessage("The \"user_role\" entity does not support the \"$action\" config action.");
|
||||
$this->configActionManager->applyAction($action, 'user.role.anonymous', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies placeBlockInDefaultTheme action doesn't alter an existing block.
|
||||
*/
|
||||
public function testPlaceBlockActionDoesNotChangeExistingBlock(): void {
|
||||
$extant_region = Block::load('olivero_powered')->getRegion();
|
||||
$this->assertNotSame('content', $extant_region);
|
||||
|
||||
$this->configActionManager->applyAction('placeBlockInDefaultTheme', 'block.block.olivero_powered', [
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'region' => [
|
||||
'olivero' => 'content',
|
||||
],
|
||||
]);
|
||||
// The extant block should be unchanged.
|
||||
$this->assertSame($extant_region, Block::load('olivero_powered')->getRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["placeBlockInDefaultTheme", "olivero", "header"]
|
||||
* ["placeBlockInAdminTheme", "claro", "page_bottom"]
|
||||
*/
|
||||
public function testPlaceBlockInDynamicRegion(string $action, string $expected_theme, string $expected_region): void {
|
||||
$this->configActionManager->applyAction($action, 'block.block.test_block', [
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'region' => [
|
||||
'olivero' => 'header',
|
||||
'claro' => 'page_bottom',
|
||||
],
|
||||
'default_region' => 'content',
|
||||
]);
|
||||
|
||||
$block = Block::load('test_block');
|
||||
$this->assertInstanceOf(Block::class, $block);
|
||||
$this->assertSame('system_powered_by_block', $block->getPluginId());
|
||||
$this->assertSame($expected_theme, $block->getTheme());
|
||||
$this->assertSame($expected_region, $block->getRegion());
|
||||
|
||||
$this->expectException(ConfigActionException::class);
|
||||
$this->expectExceptionMessage('Cannot determine which region to place this block into, because no default region was provided.');
|
||||
$this->configActionManager->applyAction($action, 'block.block.no_region', [
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'region' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["placeBlockInDefaultTheme", "olivero"]
|
||||
* ["placeBlockInAdminTheme", "claro"]
|
||||
*/
|
||||
public function testPlaceBlockInStaticRegion(string $action, string $expected_theme): void {
|
||||
$this->configActionManager->applyAction($action, 'block.block.test_block', [
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'region' => 'content',
|
||||
]);
|
||||
|
||||
$block = Block::load('test_block');
|
||||
$this->assertInstanceOf(Block::class, $block);
|
||||
$this->assertSame('system_powered_by_block', $block->getPluginId());
|
||||
$this->assertSame($expected_theme, $block->getTheme());
|
||||
$this->assertSame('content', $block->getRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests placing a block in the default theme's region.
|
||||
*/
|
||||
public function testPlaceBlockInDefaultRegion(): void {
|
||||
$this->config('system.theme')->set('default', 'umami')->save();
|
||||
$this->testPlaceBlockInDynamicRegion('placeBlockInDefaultTheme', 'umami', 'content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests placing a block at the first and last position in a region.
|
||||
*/
|
||||
public function testPlaceBlockAtPosition(): void {
|
||||
// Ensure there's at least one block already in the region.
|
||||
$block = Block::create([
|
||||
'id' => 'block_1',
|
||||
'theme' => 'olivero',
|
||||
'region' => 'content_above',
|
||||
'weight' => 0,
|
||||
'plugin' => 'system_powered_by_block',
|
||||
]);
|
||||
$block->save();
|
||||
|
||||
$this->configActionManager->applyAction('placeBlockInDefaultTheme', 'block.block.first', [
|
||||
'plugin' => $block->getPluginId(),
|
||||
'region' => [
|
||||
$block->getTheme() => $block->getRegion(),
|
||||
],
|
||||
'position' => 'first',
|
||||
]);
|
||||
$this->configActionManager->applyAction('placeBlockInDefaultTheme', 'block.block.last', [
|
||||
'plugin' => $block->getPluginId(),
|
||||
'region' => [
|
||||
$block->getTheme() => $block->getRegion(),
|
||||
],
|
||||
'position' => 'last',
|
||||
]);
|
||||
|
||||
// Query for blocks in the region, ordered by weight.
|
||||
$blocks = $this->container->get(EntityTypeManagerInterface::class)
|
||||
->getStorage('block')
|
||||
->getQuery()
|
||||
->condition('theme', $block->getTheme())
|
||||
->condition('region', $block->getRegion())
|
||||
->sort('weight', 'ASC')
|
||||
->execute();
|
||||
$this->assertGreaterThanOrEqual(3, $blocks);
|
||||
$this->assertSame('first', key($blocks));
|
||||
$this->assertSame('last', end($blocks));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests using the PlaceBlock action in an empty region.
|
||||
*/
|
||||
public function testPlaceBlockInEmptyRegion(): void {
|
||||
/** @var \Drupal\Core\Entity\Query\QueryInterface $query */
|
||||
$query = $this->container->get(EntityTypeManagerInterface::class)
|
||||
->getStorage('block')
|
||||
->getQuery()
|
||||
->count()
|
||||
->condition('theme', 'olivero')
|
||||
->condition('region', 'footer_top');
|
||||
$this->assertSame(0, $query->execute());
|
||||
|
||||
// Place a block in that region.
|
||||
$this->configActionManager->applyAction('placeBlockInDefaultTheme', 'block.block.test', [
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'region' => [
|
||||
'olivero' => 'footer_top',
|
||||
],
|
||||
'position' => 'first',
|
||||
]);
|
||||
$this->assertSame(1, $query->execute());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\block\Hook\BlockHooks;
|
||||
|
||||
/**
|
||||
* Tests migration of i18n block translations.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateBlockContentTranslationTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'comment',
|
||||
'views',
|
||||
'block_content',
|
||||
'config_translation',
|
||||
'language',
|
||||
'locale',
|
||||
'path_alias',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('block_content');
|
||||
$this->installEntitySchema('path_alias');
|
||||
$this->installConfig(['block']);
|
||||
$this->installConfig(['block_content']);
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd6_filter_format',
|
||||
'block_content_type',
|
||||
'block_content_body_field',
|
||||
'd6_menu',
|
||||
'd6_custom_block',
|
||||
'd6_user_role',
|
||||
'd6_block',
|
||||
'd6_block_translation',
|
||||
]);
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration of block title translation.
|
||||
*/
|
||||
public function testBlockContentTranslation(): void {
|
||||
/** @var \Drupal\language\ConfigurableLanguageManagerInterface $language_manager */
|
||||
$language_manager = $this->container->get('language_manager');
|
||||
|
||||
$config = $language_manager->getLanguageConfigOverride('zu', 'block.block.user_1');
|
||||
$this->assertSame('zu - Navigation', $config->get('settings.label'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\block\Hook\BlockHooks;
|
||||
|
||||
/**
|
||||
* Tests migration of blocks to configuration entities.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateBlockTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'views',
|
||||
'comment',
|
||||
'menu_ui',
|
||||
'block_content',
|
||||
'taxonomy',
|
||||
'node',
|
||||
'path_alias',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('path_alias');
|
||||
|
||||
// Install the themes used for this test.
|
||||
$this->installEntitySchema('block_content');
|
||||
$this->container->get('theme_installer')->install(['olivero', 'test_theme']);
|
||||
|
||||
$this->installConfig(['block_content']);
|
||||
|
||||
// Set Olivero as the default public theme.
|
||||
$config = $this->config('system.theme');
|
||||
$config->set('default', 'olivero');
|
||||
$config->save();
|
||||
|
||||
$this->executeMigrations([
|
||||
'd6_filter_format',
|
||||
'block_content_type',
|
||||
'block_content_body_field',
|
||||
'd6_menu',
|
||||
'd6_custom_block',
|
||||
'd6_user_role',
|
||||
'd6_block',
|
||||
]);
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts various aspects of a block.
|
||||
*
|
||||
* @param string $id
|
||||
* The block ID.
|
||||
* @param array $visibility
|
||||
* The block visibility settings.
|
||||
* @param string $region
|
||||
* The display region.
|
||||
* @param string $theme
|
||||
* The theme.
|
||||
* @param int $weight
|
||||
* The block weight.
|
||||
* @param array $settings
|
||||
* (optional) The block settings.
|
||||
* @param bool $status
|
||||
* Whether the block is expected to be enabled or disabled.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function assertEntity(string $id, array $visibility, string $region, string $theme, int $weight, ?array $settings = NULL, bool $status = TRUE): void {
|
||||
$block = Block::load($id);
|
||||
$this->assertInstanceOf(Block::class, $block);
|
||||
$this->assertSame($visibility, $block->getVisibility());
|
||||
$this->assertSame($region, $block->getRegion());
|
||||
$this->assertSame($theme, $block->getTheme());
|
||||
$this->assertSame($weight, $block->getWeight());
|
||||
$this->assertSame($status, $block->status());
|
||||
if ($settings) {
|
||||
$block_settings = $block->get('settings');
|
||||
$block_settings['id'] = current(explode(':', $block_settings['id']));
|
||||
$this->assertEquals($settings, $block_settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block migration.
|
||||
*/
|
||||
public function testBlockMigration(): void {
|
||||
$blocks = Block::loadMultiple();
|
||||
$this->assertCount(24, $blocks);
|
||||
|
||||
// Check user blocks.
|
||||
$visibility = [
|
||||
'request_path' => [
|
||||
'id' => 'request_path',
|
||||
'negate' => TRUE,
|
||||
'pages' => "<front>\n/node/1\n/blog/*",
|
||||
],
|
||||
];
|
||||
$settings = [
|
||||
'id' => 'user_login_block',
|
||||
'label' => '',
|
||||
'provider' => 'user',
|
||||
'label_display' => '0',
|
||||
];
|
||||
$this->assertEntity('user', $visibility, 'sidebar', 'olivero', -10, $settings);
|
||||
|
||||
$visibility = [];
|
||||
$settings = [
|
||||
'id' => 'system_menu_block',
|
||||
'label' => 'zu - Navigation',
|
||||
'provider' => 'system',
|
||||
'label_display' => 'visible',
|
||||
'level' => 1,
|
||||
'expand_all_items' => FALSE,
|
||||
'depth' => 0,
|
||||
];
|
||||
$this->assertEntity('user_1', $visibility, 'sidebar', 'olivero', -11, $settings);
|
||||
|
||||
$visibility = [
|
||||
'user_role' => [
|
||||
'id' => 'user_role',
|
||||
'negate' => FALSE,
|
||||
'context_mapping' => [
|
||||
'user' => '@user.current_user_context:current_user',
|
||||
],
|
||||
'roles' => [
|
||||
'authenticated' => 'authenticated',
|
||||
],
|
||||
],
|
||||
];
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'items_per_page' => '5',
|
||||
];
|
||||
$this->assertEntity('user_2', $visibility, 'sidebar', 'olivero', -11, $settings);
|
||||
|
||||
$visibility = [
|
||||
'user_role' => [
|
||||
'id' => 'user_role',
|
||||
'negate' => FALSE,
|
||||
'context_mapping' => [
|
||||
'user' => '@user.current_user_context:current_user',
|
||||
],
|
||||
'roles' => [
|
||||
'migrate_test_role_1' => 'migrate_test_role_1',
|
||||
],
|
||||
],
|
||||
];
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'items_per_page' => '10',
|
||||
];
|
||||
$this->assertEntity('user_3', $visibility, 'sidebar', 'olivero', -10, $settings);
|
||||
|
||||
// Check system block.
|
||||
$visibility = [
|
||||
'request_path' => [
|
||||
'id' => 'request_path',
|
||||
'negate' => TRUE,
|
||||
'pages' => '/node/1',
|
||||
],
|
||||
];
|
||||
$settings = [
|
||||
'id' => 'system_powered_by_block',
|
||||
'label' => '',
|
||||
'provider' => 'system',
|
||||
'label_display' => '0',
|
||||
];
|
||||
$this->assertEntity('system', $visibility, 'footer_top', 'olivero', -5, $settings);
|
||||
|
||||
// Check menu blocks.
|
||||
$settings = [
|
||||
'id' => 'system_menu_block',
|
||||
'label' => '',
|
||||
'provider' => 'system',
|
||||
'label_display' => '0',
|
||||
'level' => 1,
|
||||
'depth' => NULL,
|
||||
'expand_all_items' => FALSE,
|
||||
];
|
||||
$this->assertEntity('menu', [], 'header', 'olivero', -5, $settings);
|
||||
|
||||
// Check aggregator block.
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'block_count' => 7,
|
||||
'feed' => '5',
|
||||
];
|
||||
$this->assertEntity('aggregator', [], 'sidebar', 'olivero', -2, $settings);
|
||||
|
||||
// Check book block.
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'block_mode' => 'book pages',
|
||||
];
|
||||
$this->assertEntity('book', [], 'sidebar', 'olivero', -4, $settings);
|
||||
|
||||
// Check forum block settings.
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'block_count' => 3,
|
||||
];
|
||||
$this->assertEntity('forum', [], 'sidebar', 'olivero', -8, $settings);
|
||||
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'block_count' => 4,
|
||||
];
|
||||
$this->assertEntity('forum_1', [], 'sidebar', 'olivero', -9, $settings);
|
||||
|
||||
// Check statistic block settings.
|
||||
$settings = [
|
||||
'id' => 'broken',
|
||||
'label' => '',
|
||||
'provider' => 'core',
|
||||
'label_display' => '0',
|
||||
'top_day_num' => 7,
|
||||
'top_all_num' => 8,
|
||||
'top_last_num' => 9,
|
||||
];
|
||||
$this->assertEntity('statistics', [], 'sidebar', 'olivero', 0, $settings);
|
||||
|
||||
// Check content blocks.
|
||||
$visibility = [
|
||||
'request_path' => [
|
||||
'id' => 'request_path',
|
||||
'negate' => FALSE,
|
||||
'pages' => '<front>',
|
||||
],
|
||||
];
|
||||
$settings = [
|
||||
'id' => 'block_content',
|
||||
'label' => 'Static Block',
|
||||
'provider' => 'block_content',
|
||||
'label_display' => 'visible',
|
||||
'status' => TRUE,
|
||||
'info' => '',
|
||||
'view_mode' => 'full',
|
||||
];
|
||||
$this->assertEntity('block', $visibility, 'content', 'olivero', 0, $settings);
|
||||
|
||||
$visibility = [
|
||||
'request_path' => [
|
||||
'id' => 'request_path',
|
||||
'negate' => FALSE,
|
||||
'pages' => '/node',
|
||||
],
|
||||
];
|
||||
$settings = [
|
||||
'id' => 'block_content',
|
||||
'label' => 'Another Static Block',
|
||||
'provider' => 'block_content',
|
||||
'label_display' => 'visible',
|
||||
'status' => TRUE,
|
||||
'info' => '',
|
||||
'view_mode' => 'full',
|
||||
];
|
||||
// We expect this block to be disabled because '' is not a valid region,
|
||||
// and block_rebuild() will disable any block in an invalid region.
|
||||
$this->assertEntity('block_1', $visibility, '', 'bluemarine', -4, $settings, FALSE);
|
||||
|
||||
$settings = [
|
||||
'id' => 'block_content',
|
||||
'label' => '',
|
||||
'provider' => 'block_content',
|
||||
'label_display' => '0',
|
||||
'status' => TRUE,
|
||||
'info' => '',
|
||||
'view_mode' => 'full',
|
||||
];
|
||||
$this->assertEntity('block_2', [], 'right', 'test_theme', -7, $settings);
|
||||
|
||||
// Content block with php code is not migrated.
|
||||
$block = Block::load('block_3');
|
||||
$this->assertNotInstanceOf(Block::class, $block);
|
||||
|
||||
// Check migrate messages.
|
||||
$messages = iterator_to_array($this->getMigration('d6_block')->getIdMap()->getMessages());
|
||||
$this->assertCount(7, $messages);
|
||||
$this->assertSame($messages[0]->message, 'Schema errors for block.block.block_1 with the following errors: 0 [dependencies.theme.0] Theme 'bluemarine' is not installed., 1 [theme] Theme 'bluemarine' is not installed., 2 [region] This value should not be blank., 3 [region] This is not a valid region of the <em class="placeholder">bluemarine</em> theme.');
|
||||
$this->assertSame($messages[1]->message, "d6_block:visibility: The block with bid '13' from module 'block' will have no PHP or request_path visibility configuration.");
|
||||
$this->assertSame($messages[2]->message, 'Schema errors for block.block.aggregator with the following errors: block.block.aggregator:settings.block_count missing schema, block.block.aggregator:settings.feed missing schema, 0 [settings.feed] 'feed' is not a supported key., 1 [settings] 'block_count' is an unknown key because plugin is aggregator_feed_block (see config schema type block.settings.*).');
|
||||
$this->assertSame($messages[3]->message, 'Schema errors for block.block.book with the following errors: block.block.book:settings.block_mode missing schema, 0 [settings.block_mode] 'block_mode' is not a supported key.');
|
||||
$this->assertSame('Schema errors for block.block.forum with the following errors: block.block.forum:settings.block_count missing schema, 0 [settings] 'block_count' is an unknown key because plugin is forum_active_block (see config schema type block.settings.*).', $messages[4]->message);
|
||||
$this->assertSame('Schema errors for block.block.forum_1 with the following errors: block.block.forum_1:settings.block_count missing schema, 0 [settings] 'block_count' is an unknown key because plugin is forum_new_block (see config schema type block.settings.*).', $messages[5]->message);
|
||||
$this->assertSame('Schema errors for block.block.statistics with the following errors: block.block.statistics:settings.top_day_num missing schema, block.block.statistics:settings.top_all_num missing schema, block.block.statistics:settings.top_last_num missing schema, 0 [settings.top_day_num] 'top_day_num' is not a supported key., 1 [settings.top_all_num] 'top_all_num' is not a supported key., 2 [settings.top_last_num] 'top_last_num' is not a supported key.', $messages[6]->message);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\block\Hook\BlockHooks;
|
||||
|
||||
/**
|
||||
* Tests migration of i18n block translations.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateBlockContentTranslationTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'node',
|
||||
'text',
|
||||
'block',
|
||||
'comment',
|
||||
'filter',
|
||||
'views',
|
||||
'block_content',
|
||||
'config_translation',
|
||||
'language',
|
||||
'locale',
|
||||
'path_alias',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('block_content');
|
||||
$this->installEntitySchema('path_alias');
|
||||
$this->installConfig(['block']);
|
||||
$this->installConfig(['block_content']);
|
||||
$this->container->get('theme_installer')->install(['stark']);
|
||||
|
||||
$this->executeMigrations([
|
||||
'language',
|
||||
'd7_filter_format',
|
||||
'block_content_type',
|
||||
'block_content_body_field',
|
||||
'd7_custom_block',
|
||||
'd7_user_role',
|
||||
'd7_block',
|
||||
'd7_block_translation',
|
||||
]);
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the migration of block title translation.
|
||||
*/
|
||||
public function testBlockContentTranslation(): void {
|
||||
// @todo Skipped due to frequent random test failures.
|
||||
// See https://www.drupal.org/project/drupal/issues/3389365
|
||||
$this->markTestSkipped();
|
||||
/** @var \Drupal\language\ConfigurableLanguageManagerInterface $language_manager */
|
||||
$language_manager = $this->container->get('language_manager');
|
||||
|
||||
$config = $language_manager->getLanguageConfigOverride('fr', 'block.block.bartik_user_login');
|
||||
$this->assertSame('fr - User login title', $config->get('settings.label'));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\block\Hook\BlockHooks;
|
||||
|
||||
/**
|
||||
* Tests the migration of blocks without Block Content installed.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class MigrateBlockNoBlockContentTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'views',
|
||||
'comment',
|
||||
'menu_ui',
|
||||
'node',
|
||||
'text',
|
||||
'filter',
|
||||
'path_alias',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Install the themes used for this test.
|
||||
$this->container->get('theme_installer')->install(['olivero', 'claro']);
|
||||
|
||||
$this->installConfig(static::$modules);
|
||||
$this->installEntitySchema('path_alias');
|
||||
|
||||
// Set Olivero and Claro as the default public and admin theme.
|
||||
$config = $this->config('system.theme');
|
||||
$config->set('default', 'olivero');
|
||||
$config->set('admin', 'claro');
|
||||
$config->save();
|
||||
|
||||
$this->executeMigrations([
|
||||
'd7_filter_format',
|
||||
'd7_user_role',
|
||||
'd7_block',
|
||||
]);
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts various aspects of a block.
|
||||
*
|
||||
* @param string $id
|
||||
* The block ID.
|
||||
* @param string $plugin_id
|
||||
* The block's plugin ID.
|
||||
* @param array $roles
|
||||
* Role IDs the block is expected to have.
|
||||
* @param string $pages
|
||||
* The list of pages on which the block should appear.
|
||||
* @param string $region
|
||||
* The display region.
|
||||
* @param string $theme
|
||||
* The theme.
|
||||
* @param int $weight
|
||||
* The block weight.
|
||||
* @param string $label
|
||||
* The block label.
|
||||
* @param string $label_display
|
||||
* The block label display setting.
|
||||
* @param bool $status
|
||||
* Whether the block is expected to be enabled or disabled.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function assertEntity(string $id, string $plugin_id, array $roles, string $pages, string $region, string $theme, int $weight, string $label, string $label_display, bool $status = TRUE): void {
|
||||
$block = Block::load($id);
|
||||
$this->assertInstanceOf(Block::class, $block);
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$this->assertSame($plugin_id, $block->getPluginId());
|
||||
|
||||
$visibility = $block->getVisibility();
|
||||
if ($roles) {
|
||||
$this->assertSame($roles, array_values($visibility['user_role']['roles']));
|
||||
$this->assertSame('@user.current_user_context:current_user', $visibility['user_role']['context_mapping']['user']);
|
||||
}
|
||||
if ($pages) {
|
||||
$this->assertSame($pages, $visibility['request_path']['pages']);
|
||||
}
|
||||
|
||||
$this->assertSame($region, $block->getRegion());
|
||||
$this->assertSame($theme, $block->getTheme());
|
||||
$this->assertSame($weight, $block->getWeight());
|
||||
$this->assertSame($status, $block->status());
|
||||
|
||||
$config = $this->config('block.block.' . $id);
|
||||
$this->assertSame($label, $config->get('settings.label'));
|
||||
$this->assertSame($label_display, $config->get('settings.label_display'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block migration.
|
||||
*/
|
||||
public function testBlockMigration(): void {
|
||||
$this->assertEntity('bartik_system_main', 'system_main_block', [], '', 'content', 'olivero', 0, '', '0');
|
||||
$this->assertEntity('bartik_search_form', 'search_form_block', [], '', 'content', 'olivero', -1, '', '0');
|
||||
$this->assertEntity('bartik_user_login', 'user_login_block', [], '', 'content', 'olivero', 0, 'User login title', 'visible');
|
||||
$this->assertEntity('bartik_system_powered_by', 'system_powered_by_block', [], '', 'footer_bottom', 'olivero', 10, '', '0');
|
||||
$this->assertEntity('seven_system_main', 'system_main_block', [], '', 'content', 'claro', 0, '', '0');
|
||||
$this->assertEntity('seven_user_login', 'user_login_block', [], '', 'content', 'claro', 10, 'User login title', 'visible');
|
||||
|
||||
// Assert that disabled blocks (or enabled blocks whose plugin IDs could
|
||||
// be resolved) did not migrate.
|
||||
$non_existent_blocks = [
|
||||
'bartik_system_navigation',
|
||||
'bartik_system_help',
|
||||
'seven_user_new',
|
||||
'seven_search_form',
|
||||
'bartik_comment_recent',
|
||||
'bartik_node_syndicate',
|
||||
'bartik_node_recent',
|
||||
'bartik_shortcut_shortcuts',
|
||||
'bartik_system_management',
|
||||
'bartik_system_user-menu',
|
||||
'bartik_system_main-menu',
|
||||
'bartik_user_new',
|
||||
'bartik_user_online',
|
||||
'seven_comment_recent',
|
||||
'seven_node_syndicate',
|
||||
'seven_shortcut_shortcuts',
|
||||
'seven_system_powered-by',
|
||||
'seven_system_navigation',
|
||||
'seven_system_management',
|
||||
'seven_system_user-menu',
|
||||
'seven_system_main-menu',
|
||||
'seven_user_online',
|
||||
'bartik_blog_recent',
|
||||
'bartik_book_navigation',
|
||||
'bartik_locale_language',
|
||||
'bartik_forum_active',
|
||||
'bartik_forum_new',
|
||||
'seven_blog_recent',
|
||||
'seven_book_navigation',
|
||||
'seven_locale_language',
|
||||
'seven_forum_active',
|
||||
'seven_forum_new',
|
||||
'bartik_menu_menu-test-menu',
|
||||
'bartik_statistics_popular',
|
||||
'seven_menu_menu-test-menu',
|
||||
'seven_statistics_popular',
|
||||
'seven_block_1',
|
||||
];
|
||||
$this->assertEmpty(Block::loadMultiple($non_existent_blocks));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\block_content\Entity\BlockContent;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\block\Hook\BlockHooks;
|
||||
|
||||
/**
|
||||
* Tests migration of blocks to configuration entities.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class MigrateBlockTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'views',
|
||||
'comment',
|
||||
'menu_ui',
|
||||
'block_content',
|
||||
'node',
|
||||
'text',
|
||||
'filter',
|
||||
'path_alias',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('path_alias');
|
||||
|
||||
// Install the themes used for this test.
|
||||
$this->installEntitySchema('block_content');
|
||||
$this->container->get('theme_installer')->install(['olivero', 'claro']);
|
||||
|
||||
$this->installConfig(static::$modules);
|
||||
|
||||
// Set Olivero and Claro as the default public and admin theme.
|
||||
$config = $this->config('system.theme');
|
||||
$config->set('default', 'olivero');
|
||||
$config->set('admin', 'claro');
|
||||
$config->save();
|
||||
|
||||
$this->executeMigrations([
|
||||
'd7_filter_format',
|
||||
'd7_user_role',
|
||||
'block_content_type',
|
||||
'block_content_body_field',
|
||||
'd7_custom_block',
|
||||
'd7_block',
|
||||
]);
|
||||
$blockRebuild = new BlockHooks();
|
||||
$blockRebuild->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts various aspects of a block.
|
||||
*
|
||||
* @param string $id
|
||||
* The block ID.
|
||||
* @param string $plugin_id
|
||||
* The block's plugin ID.
|
||||
* @param array $roles
|
||||
* Role IDs the block is expected to have.
|
||||
* @param string $pages
|
||||
* The list of pages on which the block should appear.
|
||||
* @param string $region
|
||||
* The display region.
|
||||
* @param string $theme
|
||||
* The theme.
|
||||
* @param int $weight
|
||||
* The block weight.
|
||||
* @param string $label
|
||||
* The block label.
|
||||
* @param string $label_display
|
||||
* The block label display setting.
|
||||
* @param bool $status
|
||||
* Whether the block is expected to be enabled or disabled.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function assertEntity(string $id, string $plugin_id, array $roles, string $pages, string $region, string $theme, int $weight, string $label, string $label_display, bool $status = TRUE): void {
|
||||
$block = Block::load($id);
|
||||
$this->assertInstanceOf(Block::class, $block);
|
||||
/** @var \Drupal\block\BlockInterface $block */
|
||||
$this->assertSame($plugin_id, $block->getPluginId());
|
||||
|
||||
$visibility = $block->getVisibility();
|
||||
if ($roles) {
|
||||
$this->assertSame($roles, array_values($visibility['user_role']['roles']));
|
||||
$this->assertSame('@user.current_user_context:current_user', $visibility['user_role']['context_mapping']['user']);
|
||||
}
|
||||
if ($pages) {
|
||||
$this->assertSame($pages, $visibility['request_path']['pages']);
|
||||
}
|
||||
|
||||
$this->assertSame($region, $block->getRegion());
|
||||
$this->assertSame($theme, $block->getTheme());
|
||||
$this->assertSame($weight, $block->getWeight());
|
||||
$this->assertSame($status, $block->status());
|
||||
|
||||
$config = $this->config('block.block.' . $id);
|
||||
$this->assertSame($label, $config->get('settings.label'));
|
||||
$this->assertSame($label_display, $config->get('settings.label_display'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block migration.
|
||||
*/
|
||||
public function testBlockMigration(): void {
|
||||
$this->assertEntity('bartik_system_main', 'system_main_block', [], '', 'content', 'olivero', 0, '', '0');
|
||||
$this->assertEntity('bartik_search_form', 'search_form_block', [], '', 'content', 'olivero', -1, '', '0');
|
||||
$this->assertEntity('bartik_user_login', 'user_login_block', [], '', 'content', 'olivero', 0, 'User login title', 'visible');
|
||||
$this->assertEntity('bartik_system_powered_by', 'system_powered_by_block', [], '', 'footer_bottom', 'olivero', 10, '', '0');
|
||||
$this->assertEntity('seven_system_main', 'system_main_block', [], '', 'content', 'claro', 0, '', '0');
|
||||
$this->assertEntity('seven_user_login', 'user_login_block', [], '', 'content', 'claro', 10, 'User login title', 'visible');
|
||||
|
||||
// The d7_custom_block migration should have migrated a block containing a
|
||||
// mildly amusing limerick. We'll need its UUID to determine
|
||||
// bartik_block_1's plugin ID.
|
||||
$uuid = BlockContent::load(1)->uuid();
|
||||
$this->assertEntity('bartik_block_1', 'block_content:' . $uuid, ['authenticated'], '', 'content', 'olivero', 0, 'Mildly amusing limerick of the day', 'visible');
|
||||
|
||||
// Assert that disabled blocks (or enabled blocks whose plugin IDs could
|
||||
// be resolved) did not migrate.
|
||||
$non_existent_blocks = [
|
||||
'bartik_system_navigation',
|
||||
'bartik_system_help',
|
||||
'seven_user_new',
|
||||
'seven_search_form',
|
||||
'bartik_comment_recent',
|
||||
'bartik_node_syndicate',
|
||||
'bartik_node_recent',
|
||||
'bartik_shortcut_shortcuts',
|
||||
'bartik_system_management',
|
||||
'bartik_system_user-menu',
|
||||
'bartik_system_main-menu',
|
||||
'bartik_user_new',
|
||||
'bartik_user_online',
|
||||
'seven_comment_recent',
|
||||
'seven_node_syndicate',
|
||||
'seven_shortcut_shortcuts',
|
||||
'seven_system_powered-by',
|
||||
'seven_system_navigation',
|
||||
'seven_system_management',
|
||||
'seven_system_user-menu',
|
||||
'seven_system_main-menu',
|
||||
'seven_user_online',
|
||||
'bartik_blog_recent',
|
||||
'bartik_book_navigation',
|
||||
'bartik_locale_language',
|
||||
'bartik_forum_active',
|
||||
'bartik_forum_new',
|
||||
'seven_blog_recent',
|
||||
'seven_book_navigation',
|
||||
'seven_locale_language',
|
||||
'seven_forum_active',
|
||||
'seven_forum_new',
|
||||
'bartik_menu_menu-test-menu',
|
||||
'bartik_statistics_popular',
|
||||
'seven_menu_menu-test-menu',
|
||||
'seven_statistics_popular',
|
||||
'seven_block_1',
|
||||
];
|
||||
$this->assertEmpty(Block::loadMultiple($non_existent_blocks));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\block\Traits\BlockCreationTrait;
|
||||
|
||||
/**
|
||||
* Tests that a new default theme gets blocks.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class NewDefaultThemeBlocksTest extends KernelTestBase {
|
||||
|
||||
use BlockCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'block',
|
||||
'system',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* The theme installer service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeInstallerInterface
|
||||
*/
|
||||
protected $themeInstaller;
|
||||
|
||||
/**
|
||||
* The default theme.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultTheme;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['system']);
|
||||
$this->themeInstaller = $this->container->get('theme_installer');
|
||||
$this->defaultTheme = $this->config('system.theme')->get('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the blocks are correctly copied.
|
||||
*
|
||||
* This tests that blocks are correctly copied by
|
||||
* \Drupal\block\Hook\BlockHooks::themesInstalled().
|
||||
*/
|
||||
public function testNewDefaultThemeBlocks(): void {
|
||||
$default_theme = $this->defaultTheme;
|
||||
$theme_installer = $this->themeInstaller;
|
||||
$theme_installer->install([$default_theme]);
|
||||
|
||||
// Add two instances of the user login block.
|
||||
$this->placeBlock('user_login_block', [
|
||||
'id' => $default_theme . '_' . $this->randomMachineName(8),
|
||||
]);
|
||||
$this->placeBlock('user_login_block', [
|
||||
'id' => $default_theme . '_' . $this->randomMachineName(8),
|
||||
]);
|
||||
|
||||
// Add an instance of a different block.
|
||||
$this->placeBlock('system_powered_by_block', [
|
||||
'id' => $default_theme . '_' . $this->randomMachineName(8),
|
||||
]);
|
||||
|
||||
// Install a different theme that does not have blocks.
|
||||
$new_theme = 'test_theme';
|
||||
// The new theme is different from the previous default theme.
|
||||
$this->assertNotEquals($new_theme, $default_theme);
|
||||
|
||||
$theme_installer->install([$new_theme]);
|
||||
$this->config('system.theme')
|
||||
->set('default', $new_theme)
|
||||
->save();
|
||||
|
||||
$block_storage = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
|
||||
// Ensure that the new default theme has the same blocks as the previous
|
||||
// default theme.
|
||||
$default_block_names = $block_storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('theme', $default_theme)
|
||||
->execute();
|
||||
$new_blocks = $block_storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('theme', $new_theme)
|
||||
->execute();
|
||||
$this->assertSameSize($default_block_names, $new_blocks);
|
||||
|
||||
foreach ($default_block_names as $default_block_name) {
|
||||
// Remove the matching block from the list of blocks in the new theme.
|
||||
// For example, if the old theme has block.block.stark_admin,
|
||||
// unset block.block.olivero_admin.
|
||||
unset($new_blocks[str_replace($default_theme . '_', $new_theme . '_', $default_block_name)]);
|
||||
}
|
||||
$this->assertEmpty($new_blocks);
|
||||
|
||||
// Install a hidden base theme and ensure blocks are not copied.
|
||||
$base_theme = 'test_base_theme';
|
||||
$theme_installer->install([$base_theme]);
|
||||
$new_blocks = $block_storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('theme', $base_theme)
|
||||
->execute();
|
||||
$this->assertEmpty($new_blocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a theme block is still created when same ID exists.
|
||||
*/
|
||||
public function testBlockCollision(): void {
|
||||
$default_theme = $this->defaultTheme;
|
||||
$theme_installer = $this->themeInstaller;
|
||||
$theme_installer->install([$default_theme]);
|
||||
|
||||
// Add two instances of the user login block with machine
|
||||
// names that will collide.
|
||||
$this->placeBlock('user_login_block', [
|
||||
'id' => 'user_login_block',
|
||||
]);
|
||||
$this->placeBlock('user_login_block', [
|
||||
'id' => $default_theme . '_user_login_block',
|
||||
]);
|
||||
|
||||
// Add an instance of a different block.
|
||||
$this->placeBlock('system_powered_by_block', [
|
||||
'id' => $default_theme . '_' . strtolower($this->randomMachineName(8)),
|
||||
]);
|
||||
|
||||
// Install a different theme that does not have blocks.
|
||||
$new_theme = 'test_theme';
|
||||
// The new theme is different from the previous default theme.
|
||||
$this->assertNotEquals($new_theme, $default_theme);
|
||||
|
||||
$theme_installer->install([$new_theme]);
|
||||
$this->config('system.theme')
|
||||
->set('default', $new_theme)
|
||||
->save();
|
||||
|
||||
$block_storage = $this->container->get('entity_type.manager')->getStorage('block');
|
||||
|
||||
// Ensure that the new default theme has the same blocks as the previous
|
||||
// default theme.
|
||||
$default_block_names = $block_storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('theme', $default_theme)
|
||||
->execute();
|
||||
$new_blocks = $block_storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('theme', $new_theme)
|
||||
->execute();
|
||||
$this->assertSameSize($default_block_names, $new_blocks);
|
||||
|
||||
foreach ($default_block_names as $default_block_name) {
|
||||
// Remove the matching block from the list of blocks in the new theme.
|
||||
// For example, if the old theme has block.block.stark_admin,
|
||||
// unset block.block.olivero_admin.
|
||||
unset($new_blocks[str_replace($default_theme . '_', $new_theme . '_', $default_block_name)]);
|
||||
}
|
||||
// The test_theme_user_login_block machine name is already in use, so
|
||||
// therefore \Drupal\block\BlockRepository::getUniqueMachineName appends a
|
||||
// counter.
|
||||
unset($new_blocks[$new_theme . '_user_login_block_2']);
|
||||
$this->assertEmpty($new_blocks);
|
||||
|
||||
// Install a hidden base theme and ensure blocks are not copied.
|
||||
$base_theme = 'test_base_theme';
|
||||
$theme_installer->install([$base_theme]);
|
||||
$new_blocks = $block_storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->condition('theme', $base_theme)
|
||||
->execute();
|
||||
// Installing a hidden base theme does not copy the blocks from the default
|
||||
// theme.
|
||||
$this->assertEmpty($new_blocks);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Plugin\migrate\source;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests block source plugin.
|
||||
*
|
||||
* @covers \Drupal\block\Plugin\migrate\source\Block
|
||||
* @group block
|
||||
*/
|
||||
class BlockTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['blocks'] = [
|
||||
[
|
||||
'bid' => 1,
|
||||
'module' => 'block',
|
||||
'delta' => '1',
|
||||
'theme' => 'garland',
|
||||
'status' => 1,
|
||||
'weight' => 0,
|
||||
'region' => 'left',
|
||||
'visibility' => 0,
|
||||
'pages' => '',
|
||||
'title' => 'Test Title 01',
|
||||
'cache' => -1,
|
||||
],
|
||||
[
|
||||
'bid' => 2,
|
||||
'module' => 'block',
|
||||
'delta' => '2',
|
||||
'theme' => 'garland',
|
||||
'status' => 1,
|
||||
'weight' => 5,
|
||||
'region' => 'right',
|
||||
'visibility' => 0,
|
||||
'pages' => '<front>',
|
||||
'title' => 'Test Title 02',
|
||||
'cache' => -1,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['blocks_roles'] = [
|
||||
[
|
||||
'module' => 'block',
|
||||
'delta' => 1,
|
||||
'rid' => 2,
|
||||
],
|
||||
[
|
||||
'module' => 'block',
|
||||
'delta' => 2,
|
||||
'rid' => 2,
|
||||
],
|
||||
[
|
||||
'module' => 'block',
|
||||
'delta' => 2,
|
||||
'rid' => 100,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['role'] = [
|
||||
[
|
||||
'rid' => 2,
|
||||
'name' => 'authenticated user',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['system'] = [
|
||||
[
|
||||
'filename' => 'modules/system/system.module',
|
||||
'name' => 'system',
|
||||
'type' => 'module',
|
||||
'owner' => '',
|
||||
'status' => '1',
|
||||
'throttle' => '0',
|
||||
'bootstrap' => '0',
|
||||
'schema_version' => '6055',
|
||||
'weight' => '0',
|
||||
'info' => 'a:0:{}',
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'bid' => 1,
|
||||
'module' => 'block',
|
||||
'delta' => '1',
|
||||
'theme' => 'garland',
|
||||
'status' => 1,
|
||||
'weight' => 0,
|
||||
'region' => 'left',
|
||||
'visibility' => 0,
|
||||
'pages' => '',
|
||||
'title' => 'Test Title 01',
|
||||
'cache' => -1,
|
||||
'roles' => [2],
|
||||
],
|
||||
[
|
||||
'bid' => 2,
|
||||
'module' => 'block',
|
||||
'delta' => '2',
|
||||
'theme' => 'garland',
|
||||
'status' => 1,
|
||||
'weight' => 5,
|
||||
'region' => 'right',
|
||||
'visibility' => 0,
|
||||
'pages' => '<front>',
|
||||
'title' => 'Test Title 02',
|
||||
'cache' => -1,
|
||||
'roles' => [2],
|
||||
],
|
||||
];
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Tests\block\Kernel\Plugin\migrate\source\BlockTest;
|
||||
|
||||
/**
|
||||
* Tests i18n block source plugin.
|
||||
*
|
||||
* @covers \Drupal\block\Plugin\migrate\source\d6\BlockTranslation
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class BlockTranslationTest extends BlockTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
// Test data is the same as BlockTest, but with the addition of i18n_blocks.
|
||||
$tests = parent::providerSource();
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['i18n_blocks'] = [
|
||||
[
|
||||
'ibid' => 1,
|
||||
'module' => 'block',
|
||||
'delta' => '1',
|
||||
'type' => 0,
|
||||
'language' => 'fr',
|
||||
],
|
||||
[
|
||||
'ibid' => 2,
|
||||
'module' => 'block',
|
||||
'delta' => '2',
|
||||
'type' => 0,
|
||||
'language' => 'zu',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['variables'] = [
|
||||
[
|
||||
'name' => 'default_theme',
|
||||
'value' => 's:7:"garland";',
|
||||
],
|
||||
];
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'bid' => 1,
|
||||
'module' => 'block',
|
||||
'delta' => '1',
|
||||
'title' => 'Test Title 01',
|
||||
'ibid' => 1,
|
||||
'type' => '0',
|
||||
'language' => 'fr',
|
||||
'default_theme' => 'Garland',
|
||||
],
|
||||
[
|
||||
'bid' => 2,
|
||||
'module' => 'block',
|
||||
'delta' => '2',
|
||||
'theme' => 'garland',
|
||||
'title' => 'Test Title 02',
|
||||
'ibid' => 2,
|
||||
'type' => '0',
|
||||
'language' => 'zu',
|
||||
'default_theme' => 'Garland',
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
// cspell:ignore objectid objectindex plid textgroup
|
||||
|
||||
/**
|
||||
* Tests i18n block source plugin.
|
||||
*
|
||||
* @covers \Drupal\block\Plugin\migrate\source\d7\BlockTranslation
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class BlockTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['block', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function providerSource() {
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['block'] = [
|
||||
[
|
||||
'bid' => 1,
|
||||
'module' => 'system',
|
||||
'delta' => 'main',
|
||||
'theme' => 'bartik',
|
||||
'status' => 1,
|
||||
'weight' => 0,
|
||||
'region' => 'content',
|
||||
'custom' => '0',
|
||||
'visibility' => 0,
|
||||
'pages' => '',
|
||||
'title' => '',
|
||||
'cache' => -1,
|
||||
'i18n_mode' => 1,
|
||||
],
|
||||
[
|
||||
'bid' => 2,
|
||||
'module' => 'system',
|
||||
'delta' => 'navigation',
|
||||
'theme' => 'bartik',
|
||||
'status' => 1,
|
||||
'weight' => 0,
|
||||
'region' => 'sidebar_first',
|
||||
'custom' => '0',
|
||||
'visibility' => 0,
|
||||
'pages' => '',
|
||||
'title' => 'Navigation',
|
||||
'cache' => -1,
|
||||
'i18n_mode' => 1,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['block_role'] = [
|
||||
[
|
||||
'module' => 'block',
|
||||
'delta' => 1,
|
||||
'rid' => 2,
|
||||
],
|
||||
[
|
||||
'module' => 'block',
|
||||
'delta' => 2,
|
||||
'rid' => 2,
|
||||
],
|
||||
[
|
||||
'module' => 'block',
|
||||
'delta' => 2,
|
||||
'rid' => 100,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['i18n_string'] = [
|
||||
[
|
||||
'lid' => 1,
|
||||
'textgroup' => 'block',
|
||||
'context' => '1',
|
||||
'objectid' => 'navigation',
|
||||
'type' => 'system',
|
||||
'property' => 'title',
|
||||
'objectindex' => 0,
|
||||
'format' => '',
|
||||
],
|
||||
[
|
||||
'lid' => 2,
|
||||
'textgroup' => 'block',
|
||||
'context' => '1',
|
||||
'objectid' => 'main',
|
||||
'type' => 'system',
|
||||
'property' => 'title',
|
||||
'objectindex' => 0,
|
||||
'format' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['source_data']['locales_target'] = [
|
||||
[
|
||||
'lid' => 1,
|
||||
'translation' => 'fr - Navigation',
|
||||
'language' => 'fr',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['role'] = [
|
||||
[
|
||||
'rid' => 2,
|
||||
'name' => 'authenticated user',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['system'] = [
|
||||
[
|
||||
'filename' => 'modules/system/system.module',
|
||||
'name' => 'system',
|
||||
'type' => 'module',
|
||||
'owner' => '',
|
||||
'status' => '1',
|
||||
'throttle' => '0',
|
||||
'bootstrap' => '0',
|
||||
'schema_version' => '7055',
|
||||
'weight' => '0',
|
||||
'info' => 'a:0:{}',
|
||||
],
|
||||
];
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'bid' => 2,
|
||||
'module' => 'system',
|
||||
'delta' => 'navigation',
|
||||
'theme' => 'bartik',
|
||||
'status' => 1,
|
||||
'weight' => 0,
|
||||
'region' => 'sidebar_first',
|
||||
'custom' => '0',
|
||||
'visibility' => 0,
|
||||
'pages' => '',
|
||||
'title' => 'Navigation',
|
||||
'cache' => -1,
|
||||
'i18n_mode' => 1,
|
||||
'lid' => 1,
|
||||
'translation' => 'fr - Navigation',
|
||||
'language' => 'fr',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
// Change the name of the locale_target i18n status field.
|
||||
$tests[1] = $tests[0];
|
||||
foreach ($tests[1]['source_data']['locales_target'] as &$lt) {
|
||||
$lt['status'] = $lt['i18n_status'];
|
||||
unset($lt['i18n_status']);
|
||||
}
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'bid' => 2,
|
||||
'module' => 'system',
|
||||
'delta' => 'navigation',
|
||||
'theme' => 'bartik',
|
||||
'status' => 1,
|
||||
'weight' => 0,
|
||||
'region' => 'sidebar_first',
|
||||
'custom' => '0',
|
||||
'visibility' => 0,
|
||||
'pages' => '',
|
||||
'title' => 'Navigation',
|
||||
'cache' => -1,
|
||||
'i18n_mode' => 1,
|
||||
'lid' => 1,
|
||||
'translation' => 'fr - Navigation',
|
||||
'language' => 'fr',
|
||||
'plid' => 0,
|
||||
'plural' => 0,
|
||||
'i18n_status' => 0,
|
||||
],
|
||||
];
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Traits;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
|
||||
/**
|
||||
* Provides methods to create and place block with default settings.
|
||||
*
|
||||
* This trait is meant to be used only by test classes.
|
||||
*/
|
||||
trait BlockCreationTrait {
|
||||
|
||||
/**
|
||||
* Creates a block instance based on default settings.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin ID of the block type for this block instance.
|
||||
* @param array $settings
|
||||
* (optional) An associative array of settings for the block entity.
|
||||
* Override the defaults by specifying the key and value in the array, for
|
||||
* example:
|
||||
* @code
|
||||
* $this->drupalPlaceBlock('system_powered_by_block', [
|
||||
* 'label' => 'Hello, world!',
|
||||
* ]);
|
||||
* @endcode
|
||||
* The following defaults are provided:
|
||||
* - label: Random string.
|
||||
* - id: Random string.
|
||||
* - region: 'content'.
|
||||
* - theme: The default theme.
|
||||
* - visibility: Empty array (block will be visible on all pages).
|
||||
*
|
||||
* @return \Drupal\block\Entity\Block
|
||||
* The block entity.
|
||||
*
|
||||
* @todo Add support for creating content block instances.
|
||||
*/
|
||||
protected function placeBlock($plugin_id, array $settings = []) {
|
||||
$config = \Drupal::configFactory();
|
||||
$settings += [
|
||||
'plugin' => $plugin_id,
|
||||
'region' => 'content',
|
||||
'id' => $this->randomMachineName(8),
|
||||
'theme' => $config->get('system.theme')->get('default'),
|
||||
'label' => $this->randomMachineName(8),
|
||||
'visibility' => [],
|
||||
'weight' => 0,
|
||||
];
|
||||
$values = [];
|
||||
foreach (['region', 'id', 'theme', 'plugin', 'weight', 'visibility'] as $key) {
|
||||
$values[$key] = $settings[$key];
|
||||
// Remove extra values that do not belong in the settings array.
|
||||
unset($settings[$key]);
|
||||
}
|
||||
foreach ($values['visibility'] as $id => $visibility) {
|
||||
$values['visibility'][$id]['id'] = $id;
|
||||
}
|
||||
$values['settings'] = $settings;
|
||||
$block = Block::create($values);
|
||||
$block->save();
|
||||
return $block;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Drupal\Tests\Core\Plugin\Fixtures\TestConfigurablePlugin;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\Entity\Block
|
||||
* @group block
|
||||
*/
|
||||
class BlockConfigEntityUnitTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The entity type used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The entity type manager used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The ID of the type of the entity under test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityTypeId;
|
||||
|
||||
/**
|
||||
* The UUID generator used for testing.
|
||||
*
|
||||
* @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface|\Prophecy\Prophecy\ProphecyInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The theme handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface|\Prophecy\Prophecy\ProphecyInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->entityTypeId = $this->randomMachineName();
|
||||
|
||||
$this->entityType = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface');
|
||||
$this->entityType->expects($this->any())
|
||||
->method('getProvider')
|
||||
->willReturn('block');
|
||||
|
||||
$this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
|
||||
$this->entityTypeManager->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with($this->entityTypeId)
|
||||
->willReturn($this->entityType);
|
||||
|
||||
$this->uuid = $this->createMock('\Drupal\Component\Uuid\UuidInterface');
|
||||
|
||||
$this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$this->themeHandler = $this->prophesize(ThemeHandlerInterface::class);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('entity_type.manager', $this->entityTypeManager);
|
||||
$container->set('module_handler', $this->moduleHandler->reveal());
|
||||
$container->set('theme_handler', $this->themeHandler->reveal());
|
||||
$container->set('uuid', $this->uuid);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::calculateDependencies
|
||||
*/
|
||||
public function testCalculateDependencies(): void {
|
||||
$this->themeHandler->themeExists('stark')->willReturn(TRUE);
|
||||
$values = ['theme' => 'stark'];
|
||||
// Mock the entity under test so that we can mock getPluginCollections().
|
||||
$entity = $this->getMockBuilder('\Drupal\block\Entity\Block')
|
||||
->setConstructorArgs([$values, $this->entityTypeId])
|
||||
->onlyMethods(['getPluginCollections'])
|
||||
->getMock();
|
||||
// Create a configurable plugin that would add a dependency.
|
||||
$instance_id = $this->randomMachineName();
|
||||
$this->moduleHandler->moduleExists('test')->willReturn(TRUE);
|
||||
$instance = new TestConfigurablePlugin([], $instance_id, ['provider' => 'test']);
|
||||
|
||||
// Create a plugin collection to contain the instance.
|
||||
$plugin_collection = $this->getMockBuilder('\Drupal\Core\Plugin\DefaultLazyPluginCollection')
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['get'])
|
||||
->getMock();
|
||||
$plugin_collection->expects($this->atLeastOnce())
|
||||
->method('get')
|
||||
->with($instance_id)
|
||||
->willReturn($instance);
|
||||
$plugin_collection->addInstanceId($instance_id);
|
||||
|
||||
// Return the mocked plugin collection.
|
||||
$entity->expects($this->once())
|
||||
->method('getPluginCollections')
|
||||
->willReturn([$plugin_collection]);
|
||||
|
||||
$dependencies = $entity->calculateDependencies()->getDependencies();
|
||||
$this->assertContains('test', $dependencies['module']);
|
||||
$this->assertContains('stark', $dependencies['theme']);
|
||||
}
|
||||
|
||||
}
|
||||
184
web/core/modules/block/tests/src/Unit/BlockFormTest.php
Normal file
184
web/core/modules/block/tests/src/Unit/BlockFormTest.php
Normal file
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit;
|
||||
|
||||
use Drupal\block\BlockForm;
|
||||
use Drupal\block\BlockRepository;
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Plugin\PluginFormFactoryInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\BlockForm
|
||||
* @group block
|
||||
*/
|
||||
class BlockFormTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The condition plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Executable\ExecutableManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $conditionManager;
|
||||
|
||||
/**
|
||||
* The block storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The language manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* The theme handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* The theme manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Theme\ThemeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $themeManager;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The mocked context handler.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $contextHandler;
|
||||
|
||||
/**
|
||||
* The mocked context repository.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $contextRepository;
|
||||
|
||||
/**
|
||||
* The plugin form manager.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\PluginFormFactoryInterface|\Prophecy\Prophecy\ProphecyInterface
|
||||
*/
|
||||
protected $pluginFormFactory;
|
||||
|
||||
/**
|
||||
* The block repository.
|
||||
*
|
||||
* @var \Drupal\block\BlockRepositoryInterface
|
||||
*/
|
||||
protected $blockRepository;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->conditionManager = $this->createMock('Drupal\Core\Executable\ExecutableManagerInterface');
|
||||
$this->language = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
|
||||
$this->contextRepository = $this->createMock('Drupal\Core\Plugin\Context\ContextRepositoryInterface');
|
||||
|
||||
$this->entityTypeManager = $this->createMock('Drupal\Core\Entity\EntityTypeManagerInterface');
|
||||
$this->storage = $this->createMock('Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
|
||||
$this->themeHandler = $this->createMock('Drupal\Core\Extension\ThemeHandlerInterface');
|
||||
$this->entityTypeManager->expects($this->any())
|
||||
->method('getStorage')
|
||||
->willReturn($this->storage);
|
||||
|
||||
$this->pluginFormFactory = $this->prophesize(PluginFormFactoryInterface::class);
|
||||
|
||||
$this->themeManager = $this->createMock('\Drupal\Core\Theme\ThemeManagerInterface');
|
||||
$this->contextHandler = $this->createMock('Drupal\Core\Plugin\Context\ContextHandlerInterface');
|
||||
$this->blockRepository = new BlockRepository($this->entityTypeManager, $this->themeManager, $this->contextHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks a block with a block plugin.
|
||||
*
|
||||
* @param string $machine_name
|
||||
* The machine name of the block plugin.
|
||||
*
|
||||
* @return \Drupal\block\BlockInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
* The mocked block.
|
||||
*/
|
||||
protected function getBlockMockWithMachineName($machine_name) {
|
||||
$plugin = $this->getMockBuilder(BlockBase::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$plugin->expects($this->any())
|
||||
->method('getMachineNameSuggestion')
|
||||
->willReturn($machine_name);
|
||||
|
||||
$block = $this->getMockBuilder(Block::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$block->expects($this->any())
|
||||
->method('getPlugin')
|
||||
->willReturn($plugin);
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the unique machine name generator.
|
||||
*
|
||||
* @see \Drupal\block\BlockForm::getUniqueMachineName()
|
||||
*/
|
||||
public function testGetUniqueMachineName(): void {
|
||||
$blocks = [];
|
||||
|
||||
$blocks['test'] = $this->getBlockMockWithMachineName('test');
|
||||
$blocks['other_test'] = $this->getBlockMockWithMachineName('other_test');
|
||||
$blocks['other_test_1'] = $this->getBlockMockWithMachineName('other_test');
|
||||
$blocks['other_test_2'] = $this->getBlockMockWithMachineName('other_test');
|
||||
|
||||
$query = $this->createMock('Drupal\Core\Entity\Query\QueryInterface');
|
||||
$query->expects($this->exactly(5))
|
||||
->method('condition')
|
||||
->willReturn($query);
|
||||
|
||||
$query->expects($this->exactly(5))
|
||||
->method('execute')
|
||||
->willReturn(['test', 'other_test', 'other_test_1', 'other_test_2']);
|
||||
|
||||
$this->storage->expects($this->exactly(5))
|
||||
->method('getQuery')
|
||||
->willReturn($query);
|
||||
|
||||
$block_form_controller = new BlockForm($this->entityTypeManager, $this->conditionManager, $this->contextRepository, $this->language, $this->themeHandler, $this->pluginFormFactory->reveal(), $this->blockRepository);
|
||||
|
||||
// Ensure that the block with just one other instance gets
|
||||
// the next available name suggestion.
|
||||
$this->assertEquals('test_2', $block_form_controller->getUniqueMachineName($blocks['test']));
|
||||
|
||||
// Ensure that the block with already three instances (_0, _1, _2) gets the
|
||||
// 4th available name.
|
||||
$this->assertEquals('other_test_3', $block_form_controller->getUniqueMachineName($blocks['other_test']));
|
||||
$this->assertEquals('other_test_3', $block_form_controller->getUniqueMachineName($blocks['other_test_1']));
|
||||
$this->assertEquals('other_test_3', $block_form_controller->getUniqueMachineName($blocks['other_test_2']));
|
||||
|
||||
// Ensure that a block without an instance yet gets the suggestion as
|
||||
// unique machine name.
|
||||
$last_block = $this->getBlockMockWithMachineName('last_test');
|
||||
$this->assertEquals('last_test', $block_form_controller->getUniqueMachineName($last_block));
|
||||
}
|
||||
|
||||
}
|
||||
199
web/core/modules/block/tests/src/Unit/BlockRepositoryTest.php
Normal file
199
web/core/modules/block/tests/src/Unit/BlockRepositoryTest.php
Normal file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit;
|
||||
|
||||
use Drupal\block\BlockRepository;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\BlockRepository
|
||||
* @group block
|
||||
*/
|
||||
class BlockRepositoryTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The block repository.
|
||||
*
|
||||
* @var \Drupal\block\BlockRepository
|
||||
*/
|
||||
protected $blockRepository;
|
||||
|
||||
/**
|
||||
* The block storage or a mock.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $blockStorage;
|
||||
|
||||
/**
|
||||
* The theme for the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $theme;
|
||||
|
||||
/**
|
||||
* The context handler of a mock.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $contextHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$active_theme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->theme = $this->randomMachineName();
|
||||
$active_theme->expects($this->atLeastOnce())
|
||||
->method('getName')
|
||||
->willReturn($this->theme);
|
||||
$active_theme->expects($this->atLeastOnce())
|
||||
->method('getRegions')
|
||||
->willReturn([
|
||||
'top',
|
||||
'center',
|
||||
'bottom',
|
||||
]);
|
||||
|
||||
$theme_manager = $this->createMock('Drupal\Core\Theme\ThemeManagerInterface');
|
||||
$theme_manager->expects($this->atLeastOnce())
|
||||
->method('getActiveTheme')
|
||||
->willReturn($active_theme);
|
||||
|
||||
$this->contextHandler = $this->createMock('Drupal\Core\Plugin\Context\ContextHandlerInterface');
|
||||
$this->blockStorage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject $entity_type_manager */
|
||||
$entity_type_manager = $this->createMock(EntityTypeManagerInterface::class);
|
||||
$entity_type_manager->expects($this->any())
|
||||
->method('getStorage')
|
||||
->willReturn($this->blockStorage);
|
||||
|
||||
$this->blockRepository = new BlockRepository($entity_type_manager, $theme_manager, $this->contextHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the retrieval of block entities.
|
||||
*
|
||||
* @covers ::getVisibleBlocksPerRegion
|
||||
*
|
||||
* @dataProvider providerBlocksConfig
|
||||
*/
|
||||
public function testGetVisibleBlocksPerRegion(array $blocks_config, array $expected_blocks): void {
|
||||
$blocks = [];
|
||||
foreach ($blocks_config as $block_id => $block_config) {
|
||||
$block = $this->createMock('Drupal\block\BlockInterface');
|
||||
$block->expects($this->once())
|
||||
->method('access')
|
||||
->willReturn($block_config[0]);
|
||||
$block->expects($block_config[0] ? $this->atLeastOnce() : $this->never())
|
||||
->method('getRegion')
|
||||
->willReturn($block_config[1]);
|
||||
$block->expects($this->any())
|
||||
->method('label')
|
||||
->willReturn($block_id);
|
||||
$block->expects($this->any())
|
||||
->method('getWeight')
|
||||
->willReturn($block_config[2]);
|
||||
$blocks[$block_id] = $block;
|
||||
}
|
||||
|
||||
$this->blockStorage->expects($this->once())
|
||||
->method('loadByProperties')
|
||||
->with(['theme' => $this->theme])
|
||||
->willReturn($blocks);
|
||||
$result = [];
|
||||
$cacheable_metadata = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata) as $region => $resulting_blocks) {
|
||||
$result[$region] = [];
|
||||
foreach ($resulting_blocks as $plugin_id => $block) {
|
||||
$result[$region][] = $plugin_id;
|
||||
}
|
||||
}
|
||||
$this->assertEquals($expected_blocks, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to testGetVisibleBlocksPerRegion().
|
||||
*/
|
||||
public static function providerBlocksConfig() {
|
||||
$blocks_config = [
|
||||
'block1' => [
|
||||
AccessResult::allowed(), 'top', 0,
|
||||
],
|
||||
// Test a block without access.
|
||||
'block2' => [
|
||||
AccessResult::forbidden(), 'bottom', 0,
|
||||
],
|
||||
// Test some blocks in the same region with specific weight.
|
||||
'block4' => [
|
||||
AccessResult::allowed(), 'bottom', 5,
|
||||
],
|
||||
'block3' => [
|
||||
AccessResult::allowed(), 'bottom', 5,
|
||||
],
|
||||
'block5' => [
|
||||
AccessResult::allowed(), 'bottom', -5,
|
||||
],
|
||||
];
|
||||
|
||||
$test_cases = [];
|
||||
$test_cases[] = [$blocks_config,
|
||||
[
|
||||
'top' => ['block1'],
|
||||
'center' => [],
|
||||
'bottom' => ['block5', 'block3', 'block4'],
|
||||
],
|
||||
];
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the retrieval of block entities that are context-aware.
|
||||
*
|
||||
* @covers ::getVisibleBlocksPerRegion
|
||||
*/
|
||||
public function testGetVisibleBlocksPerRegionWithContext(): void {
|
||||
$block = $this->createMock('Drupal\block\BlockInterface');
|
||||
$block->expects($this->once())
|
||||
->method('access')
|
||||
->willReturn(AccessResult::allowed()->addCacheTags(['config:block.block.block_id']));
|
||||
$block->expects($this->once())
|
||||
->method('getRegion')
|
||||
->willReturn('top');
|
||||
$blocks['block_id'] = $block;
|
||||
|
||||
$this->blockStorage->expects($this->once())
|
||||
->method('loadByProperties')
|
||||
->with(['theme' => $this->theme])
|
||||
->willReturn($blocks);
|
||||
$result = [];
|
||||
$cacheable_metadata = [];
|
||||
foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata) as $region => $resulting_blocks) {
|
||||
$result[$region] = [];
|
||||
foreach ($resulting_blocks as $plugin_id => $block) {
|
||||
$result[$region][] = $plugin_id;
|
||||
}
|
||||
}
|
||||
$expected = [
|
||||
'top' => [
|
||||
'block_id',
|
||||
],
|
||||
'center' => [],
|
||||
'bottom' => [],
|
||||
];
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
// Assert that the cacheable metadata from the block access results was
|
||||
// collected.
|
||||
$this->assertEquals(['config:block.block.block_id'], $cacheable_metadata['top']->getCacheTags());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\block\Controller\CategoryAutocompleteController;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\Controller\CategoryAutocompleteController
|
||||
* @group block
|
||||
*/
|
||||
class CategoryAutocompleteTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The autocomplete controller.
|
||||
*
|
||||
* @var \Drupal\block\Controller\CategoryAutocompleteController
|
||||
*/
|
||||
protected $autocompleteController;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$block_manager = $this->createMock('Drupal\Core\Block\BlockManagerInterface');
|
||||
$block_manager->expects($this->any())
|
||||
->method('getCategories')
|
||||
->willReturn(['Comment', 'Node', 'None & Such', 'User']);
|
||||
|
||||
$this->autocompleteController = new CategoryAutocompleteController($block_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the autocomplete method.
|
||||
*
|
||||
* @param string $string
|
||||
* The string entered into the autocomplete.
|
||||
* @param array $suggestions
|
||||
* The array of expected suggestions.
|
||||
*
|
||||
* @see \Drupal\block\Controller\CategoryAutocompleteController::autocomplete()
|
||||
*
|
||||
* @dataProvider providerTestAutocompleteSuggestions
|
||||
*/
|
||||
public function testAutocompleteSuggestions($string, $suggestions): void {
|
||||
$suggestions = array_map(function ($suggestion) {
|
||||
return ['value' => $suggestion, 'label' => Html::escape($suggestion)];
|
||||
}, $suggestions);
|
||||
$result = $this->autocompleteController->autocomplete(new Request(['q' => $string]));
|
||||
$this->assertSame($suggestions, json_decode($result->getContent(), TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testAutocompleteSuggestions().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases, each containing an input string and
|
||||
* expected autocomplete suggestions.
|
||||
*/
|
||||
public static function providerTestAutocompleteSuggestions() {
|
||||
$test_parameters = [];
|
||||
$test_parameters[] = [
|
||||
'string' => 'Com',
|
||||
'suggestions' => [
|
||||
'Comment',
|
||||
],
|
||||
];
|
||||
$test_parameters[] = [
|
||||
'string' => 'No',
|
||||
'suggestions' => [
|
||||
'Node',
|
||||
'None & Such',
|
||||
],
|
||||
];
|
||||
$test_parameters[] = [
|
||||
'string' => 'us',
|
||||
'suggestions' => [
|
||||
'User',
|
||||
],
|
||||
];
|
||||
$test_parameters[] = [
|
||||
'string' => 'Banana',
|
||||
'suggestions' => [],
|
||||
];
|
||||
return $test_parameters;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit\Menu;
|
||||
|
||||
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTestBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Tests block local tasks.
|
||||
*
|
||||
* @group block
|
||||
*/
|
||||
class BlockLocalTasksTest extends LocalTaskIntegrationTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->directoryList = ['block' => 'core/modules/block'];
|
||||
parent::setUp();
|
||||
|
||||
$config_factory = $this->getConfigFactoryStub([
|
||||
'system.theme' => ['default' => 'test_c'],
|
||||
]);
|
||||
|
||||
$themes = [];
|
||||
$themes['test_a'] = (object) [
|
||||
'status' => 1,
|
||||
'info' => [
|
||||
'name' => 'test_a',
|
||||
'hidden' => TRUE,
|
||||
],
|
||||
];
|
||||
$themes['test_b'] = (object) [
|
||||
'status' => 1,
|
||||
'info' => [
|
||||
'name' => 'test_b',
|
||||
],
|
||||
];
|
||||
$themes['test_c'] = (object) [
|
||||
'status' => 1,
|
||||
'info' => [
|
||||
'name' => 'test_c',
|
||||
],
|
||||
];
|
||||
$theme_handler = $this->createMock('Drupal\Core\Extension\ThemeHandlerInterface');
|
||||
$theme_handler->expects($this->any())
|
||||
->method('listInfo')
|
||||
->willReturn($themes);
|
||||
$theme_handler->expects($this->any())
|
||||
->method('hasUi')
|
||||
->willReturnMap([
|
||||
['test_a', FALSE],
|
||||
['test_b', TRUE],
|
||||
['test_c', TRUE],
|
||||
]);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('config.factory', $config_factory);
|
||||
$container->set('theme_handler', $theme_handler);
|
||||
$container->setParameter('app.root', $this->root);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the admin edit local task.
|
||||
*/
|
||||
public function testBlockAdminLocalTasks(): void {
|
||||
$this->assertLocalTasks('entity.block.edit_form', [['entity.block.edit_form']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the block admin display local tasks.
|
||||
*
|
||||
* @dataProvider providerTestBlockAdminDisplay
|
||||
*/
|
||||
public function testBlockAdminDisplay($route, $expected): void {
|
||||
$this->assertLocalTasks($route, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of routes to test.
|
||||
*/
|
||||
public static function providerTestBlockAdminDisplay() {
|
||||
return [
|
||||
[
|
||||
'block.admin_display',
|
||||
[
|
||||
['block.admin_display'],
|
||||
[
|
||||
'block.admin_display_theme:test_b',
|
||||
'block.admin_display_theme:test_c',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'block.admin_display_theme',
|
||||
[
|
||||
['block.admin_display'],
|
||||
[
|
||||
'block.admin_display_theme:test_b',
|
||||
'block.admin_display_theme:test_c',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit\Plugin\DisplayVariant;
|
||||
|
||||
use Drupal\block\Plugin\DisplayVariant\BlockPageVariant;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\DependencyInjection\Container;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\Plugin\DisplayVariant\BlockPageVariant
|
||||
* @group block
|
||||
*/
|
||||
class BlockPageVariantTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The block repository.
|
||||
*
|
||||
* @var \Drupal\block\BlockRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $blockRepository;
|
||||
|
||||
/**
|
||||
* The block view builder.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityViewBuilderInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $blockViewBuilder;
|
||||
|
||||
/**
|
||||
* The plugin context handler.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected $contextHandler;
|
||||
|
||||
/**
|
||||
* Sets up a display variant plugin for testing.
|
||||
*
|
||||
* @param array $configuration
|
||||
* An array of plugin configuration.
|
||||
* @param array $definition
|
||||
* The plugin definition array.
|
||||
*
|
||||
* @return \Drupal\block\Plugin\DisplayVariant\BlockPageVariant
|
||||
* A test display variant plugin.
|
||||
*/
|
||||
public function setUpDisplayVariant($configuration = [], $definition = []) {
|
||||
|
||||
$container = new Container();
|
||||
$cache_context_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['assertValidTokens'])
|
||||
->getMock();
|
||||
$container->set('cache_contexts_manager', $cache_context_manager);
|
||||
$cache_context_manager->expects($this->any())
|
||||
->method('assertValidTokens')
|
||||
->willReturn(TRUE);
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$this->blockRepository = $this->createMock('Drupal\block\BlockRepositoryInterface');
|
||||
$this->blockViewBuilder = $this->createMock('Drupal\Core\Entity\EntityViewBuilderInterface');
|
||||
|
||||
return new BlockPageVariant($configuration, 'test', $definition, $this->blockRepository, $this->blockViewBuilder, ['config:block_list']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data to testBuild().
|
||||
*/
|
||||
public static function providerBuild() {
|
||||
$blocks_config = [
|
||||
'block1' => [
|
||||
// region, is main content block, is messages block, is title block
|
||||
'top', FALSE, FALSE, FALSE,
|
||||
],
|
||||
// Test multiple blocks in the same region.
|
||||
'block2' => [
|
||||
'bottom', FALSE, FALSE, FALSE,
|
||||
],
|
||||
'block3' => [
|
||||
'bottom', FALSE, FALSE, FALSE,
|
||||
],
|
||||
// Test a block implementing MainContentBlockPluginInterface.
|
||||
'block4' => [
|
||||
'center', TRUE, FALSE, FALSE,
|
||||
],
|
||||
// Test a block implementing MessagesBlockPluginInterface.
|
||||
'block5' => [
|
||||
'center', FALSE, TRUE, FALSE,
|
||||
],
|
||||
// Test a block implementing TitleBlockPluginInterface.
|
||||
'block6' => [
|
||||
'center', FALSE, FALSE, TRUE,
|
||||
],
|
||||
];
|
||||
|
||||
$test_cases = [];
|
||||
$test_cases[] = [$blocks_config, 6,
|
||||
[
|
||||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
'route',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'top' => [
|
||||
'block1' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
// The main content was rendered via a block.
|
||||
'center' => [
|
||||
'block4' => [],
|
||||
'block5' => [],
|
||||
'block6' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
'bottom' => [
|
||||
'block2' => [],
|
||||
'block3' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
unset($blocks_config['block5']);
|
||||
$test_cases[] = [$blocks_config, 5,
|
||||
[
|
||||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
'route',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'top' => [
|
||||
'block1' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
'center' => [
|
||||
'block4' => [],
|
||||
'block6' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
'bottom' => [
|
||||
'block2' => [],
|
||||
'block3' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
// The messages are rendered via the fallback in case there is no block
|
||||
// rendering the main content.
|
||||
'content' => [
|
||||
'messages' => [
|
||||
'#weight' => -1000,
|
||||
'#type' => 'status_messages',
|
||||
'#include_fallback' => TRUE,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
unset($blocks_config['block4']);
|
||||
unset($blocks_config['block6']);
|
||||
$test_cases[] = [$blocks_config, 3,
|
||||
[
|
||||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
'route',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'top' => [
|
||||
'block1' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
'bottom' => [
|
||||
'block2' => [],
|
||||
'block3' => [],
|
||||
'#sorted' => TRUE,
|
||||
],
|
||||
// The main content & messages are rendered via the fallback in case
|
||||
// there are no blocks rendering them.
|
||||
'content' => [
|
||||
'system_main' => ['#markup' => 'Hello kittens!'],
|
||||
'messages' => [
|
||||
'#weight' => -1000,
|
||||
'#type' => 'status_messages',
|
||||
'#include_fallback' => TRUE,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the building of a full page variant.
|
||||
*
|
||||
* @covers ::build
|
||||
*
|
||||
* @dataProvider providerBuild
|
||||
*/
|
||||
public function testBuild(array $blocks_config, $visible_block_count, array $expected_render_array): void {
|
||||
$display_variant = $this->setUpDisplayVariant();
|
||||
$display_variant->setMainContent(['#markup' => 'Hello kittens!']);
|
||||
|
||||
$blocks = ['top' => [], 'center' => [], 'bottom' => []];
|
||||
$block_plugin = $this->createMock('Drupal\Core\Block\BlockPluginInterface');
|
||||
$main_content_block_plugin = $this->createMock('Drupal\Core\Block\MainContentBlockPluginInterface');
|
||||
$messages_block_plugin = $this->createMock('Drupal\Core\Block\MessagesBlockPluginInterface');
|
||||
$title_block_plugin = $this->createMock('Drupal\Core\Block\TitleBlockPluginInterface');
|
||||
foreach ($blocks_config as $block_id => $block_config) {
|
||||
$block = $this->createMock('Drupal\block\BlockInterface');
|
||||
$block->expects($this->atLeastOnce())
|
||||
->method('getPlugin')
|
||||
->willReturn($block_config[1] ? $main_content_block_plugin : ($block_config[2] ? $messages_block_plugin : ($block_config[3] ? $title_block_plugin : $block_plugin)));
|
||||
$blocks[$block_config[0]][$block_id] = $block;
|
||||
}
|
||||
$this->blockViewBuilder->expects($this->exactly($visible_block_count))
|
||||
->method('view')
|
||||
->willReturn([]);
|
||||
$this->blockRepository->expects($this->once())
|
||||
->method('getVisibleBlocksPerRegion')
|
||||
->willReturnCallback(function (&$cacheable_metadata) use ($blocks) {
|
||||
$cacheable_metadata['top'] = (new CacheableMetadata())->addCacheTags(['route']);
|
||||
return $blocks;
|
||||
});
|
||||
|
||||
$value = $display_variant->build();
|
||||
$this->assertSame($expected_render_array, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the building of a full page variant with no main content set.
|
||||
*
|
||||
* @covers ::build
|
||||
*/
|
||||
public function testBuildWithoutMainContent(): void {
|
||||
$display_variant = $this->setUpDisplayVariant();
|
||||
$this->blockRepository->expects($this->once())
|
||||
->method('getVisibleBlocksPerRegion')
|
||||
->willReturn([]);
|
||||
|
||||
$expected = [
|
||||
'#cache' => [
|
||||
'tags' => [
|
||||
'config:block_list',
|
||||
],
|
||||
'contexts' => [],
|
||||
'max-age' => -1,
|
||||
],
|
||||
'content' => [
|
||||
'system_main' => [],
|
||||
'messages' => [
|
||||
'#weight' => -1000,
|
||||
'#type' => 'status_messages',
|
||||
'#include_fallback' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->assertSame($expected, $display_variant->build());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit\Plugin\migrate\process;
|
||||
|
||||
use Drupal\block\Plugin\migrate\process\BlockRegion;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\Plugin\migrate\process\BlockRegion
|
||||
* @group block
|
||||
*/
|
||||
class BlockRegionTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Transforms a value through the block_region plugin.
|
||||
*
|
||||
* @param array $value
|
||||
* The value to transform.
|
||||
* @param \Drupal\migrate\Row|null $row
|
||||
* (optional) The mocked row.
|
||||
*
|
||||
* @return array|string
|
||||
* The transformed value.
|
||||
*/
|
||||
protected function transform(array $value, ?Row $row = NULL) {
|
||||
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
|
||||
if (empty($row)) {
|
||||
$row = $this->prophesize(Row::class)->reveal();
|
||||
}
|
||||
|
||||
$configuration = [
|
||||
'map' => [
|
||||
'bartik' => [
|
||||
'bartik' => [
|
||||
'triptych_first' => 'triptych_first',
|
||||
'triptych_middle' => 'triptych_second',
|
||||
'triptych_last' => 'triptych_third',
|
||||
],
|
||||
],
|
||||
],
|
||||
'default_value' => 'content',
|
||||
];
|
||||
|
||||
$plugin = new BlockRegion($configuration, 'block_region', [], $configuration['map']['bartik']['bartik']);
|
||||
return $plugin->transform($value, $executable, $row, 'foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests transforming a block with the same theme and an existing region.
|
||||
*
|
||||
* If the source and destination themes are identical, the region should only
|
||||
* be passed through if it actually exists in the destination theme.
|
||||
*
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformSameThemeRegionExists(): void {
|
||||
$this->assertSame('triptych_second', $this->transform(['bartik', 'bartik', 'triptych_middle']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests transforming a block with the same theme and a non-existent region.
|
||||
*
|
||||
* If the source and destination themes are identical, the region should be
|
||||
* changed to 'content' if it doesn't exist in the destination theme.
|
||||
*
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformSameThemeRegionNotExists(): void {
|
||||
$this->assertSame('content', $this->transform(['bartik', 'bartik', 'footer']));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit\Plugin\migrate\process;
|
||||
|
||||
use Drupal\block\Plugin\migrate\process\BlockSettings;
|
||||
use Drupal\Core\Block\BlockManagerInterface;
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Prophecy\Argument;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\block\Plugin\migrate\process\BlockSettings
|
||||
* @group block
|
||||
*/
|
||||
class BlockSettingsTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Tests the blocks settings process plugin.
|
||||
*
|
||||
* @param array $value
|
||||
* The source value for the plugin.
|
||||
* @param array $expected
|
||||
* The expected result.
|
||||
*
|
||||
* @covers ::transform
|
||||
*
|
||||
* @dataProvider providerTestTransform
|
||||
*/
|
||||
public function testTransform($value, $expected): void {
|
||||
$executable = $this->prophesize(MigrateExecutableInterface::class)
|
||||
->reveal();
|
||||
$row = $this->prophesize(Row::class)->reveal();
|
||||
|
||||
// The block plugin should be asked to provide default configuration.
|
||||
$expected['default'] = 'value';
|
||||
|
||||
$mock_plugin = $this->prophesize(BlockPluginInterface::class);
|
||||
$mock_plugin->getConfiguration()
|
||||
->shouldBeCalled()
|
||||
->willReturn($expected);
|
||||
|
||||
$block_manager = $this->prophesize(BlockManagerInterface::class);
|
||||
$block_manager->createInstance($value[0], Argument::type('array'))
|
||||
->shouldBeCalled()
|
||||
->willReturn($mock_plugin->reveal());
|
||||
|
||||
$plugin = new BlockSettings([], 'block_settings', [], $block_manager->reveal());
|
||||
$actual = $plugin->transform($value, $executable, $row, 'foo');
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for testTransform.
|
||||
*/
|
||||
public static function providerTestTransform() {
|
||||
return [
|
||||
'title set' => [
|
||||
[
|
||||
'custom',
|
||||
0,
|
||||
'foo',
|
||||
'title',
|
||||
],
|
||||
[
|
||||
'label' => 'title',
|
||||
'label_display' => 'visible',
|
||||
],
|
||||
],
|
||||
'title empty' => [
|
||||
[
|
||||
'custom',
|
||||
0,
|
||||
'foo',
|
||||
'',
|
||||
],
|
||||
[
|
||||
'label' => '',
|
||||
'label_display' => '0',
|
||||
],
|
||||
],
|
||||
'title <none>' => [
|
||||
[
|
||||
'custom',
|
||||
0,
|
||||
'foo',
|
||||
'<none>',
|
||||
],
|
||||
[
|
||||
'label' => '<none>',
|
||||
'label_display' => '0',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\block\Unit\Plugin\migrate\process;
|
||||
|
||||
use Drupal\block\Plugin\migrate\process\BlockVisibility;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\migrate\MigrateLookupInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
|
||||
|
||||
// cspell:ignore rbaz
|
||||
|
||||
/**
|
||||
* Tests the block_visibility process plugin.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\block\Plugin\migrate\process\BlockVisibility
|
||||
* @group block
|
||||
*/
|
||||
class BlockVisibilityTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$migrate_lookup = $this->prophesize(MigrateLookupInterface::class);
|
||||
$this->plugin = new BlockVisibility([], 'block_visibility_pages', [], $this->moduleHandler->reveal(), $migrate_lookup->reveal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformNoData(): void {
|
||||
$transformed_value = $this->plugin->transform([0, '', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertEmpty($transformed_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformSinglePageWithFront(): void {
|
||||
$visibility = $this->plugin->transform([0, '<front>', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame('request_path', $visibility['request_path']['id']);
|
||||
$this->assertTrue($visibility['request_path']['negate']);
|
||||
$this->assertSame('<front>', $visibility['request_path']['pages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformMultiplePagesWithFront(): void {
|
||||
$visibility = $this->plugin->transform([1, "foo\n/bar\rbaz\r\n<front>", []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame('request_path', $visibility['request_path']['id']);
|
||||
$this->assertFalse($visibility['request_path']['negate']);
|
||||
$this->assertSame("/foo\n/bar\n/baz\n<front>", $visibility['request_path']['pages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformPhpEnabled(): void {
|
||||
$this->moduleHandler->moduleExists('php')->willReturn(TRUE);
|
||||
$visibility = $this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertSame('php', $visibility['php']['id']);
|
||||
$this->assertFalse($visibility['php']['negate']);
|
||||
$this->assertSame('<?php', $visibility['php']['php']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformPhpDisabled(): void {
|
||||
$this->moduleHandler->moduleExists('php')->willReturn(FALSE);
|
||||
$transformed_value = $this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
$this->assertEmpty($transformed_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testTransformException(): void {
|
||||
$this->moduleHandler->moduleExists('php')->willReturn(FALSE);
|
||||
$migrate_lookup = $this->prophesize(MigrateLookupInterface::class);
|
||||
$this->row = $this->getMockBuilder('Drupal\migrate\Row')
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getSourceProperty'])
|
||||
->getMock();
|
||||
$this->row->expects($this->exactly(2))
|
||||
->method('getSourceProperty')
|
||||
->willReturnMap([['bid', 99], ['module', 'foobar']]);
|
||||
$this->plugin = new BlockVisibility(['skip_php' => TRUE], 'block_visibility_pages', [], $this->moduleHandler->reveal(), $migrate_lookup->reveal());
|
||||
$this->expectException(MigrateSkipRowException::class);
|
||||
$this->expectExceptionMessage("The block with bid '99' from module 'foobar' will have no PHP or request_path visibility configuration.");
|
||||
$this->plugin->transform([2, '<?php', []], $this->migrateExecutable, $this->row, 'destination_property');
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user